From de33c2afc884c9ab05a3a7824b5dbe6113ec7117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Andr=C3=A9=20Long?= Date: Thu, 11 Jul 2024 12:46:03 +0200 Subject: [PATCH] Added liveness enforcement. --- development/test.sh | 9 + .../programs/marketplace_example/src/main.leo | 6 +- programs/credits/build/main.aleo | 367 ++ programs/data_custody_protocol/src/main.leo | 21 + programs/dcp_core_protocol/src/main.leo | 10 +- programs/dcp_fee_management/src/main.leo | 96 +- programs/dcp_withdraw_requests/src/main.leo | 54 +- validators/run-rpc/start.js | 17 + validators/run-validator/config/db.js | 15 +- validators/run-validator/config/programs.js | 4 +- validators/run-validator/lib/aleo.js | 108 +- validators/run-validator/lib/db.js | 13 +- validators/run-validator/lib/process.js | 87 +- validators/run-validator/lib/programs.js | 86 + validators/run-validator/lib/sync.js | 87 +- validators/run-validator/package-lock.json | 538 ++ validators/run-validator/package.json | 5 +- .../patches/@aleohq+sdk+0.6.9.patch | 5555 +++++++++++++++++ validators/run-validator/start.js | 10 +- 19 files changed, 6894 insertions(+), 194 deletions(-) create mode 100644 programs/credits/build/main.aleo create mode 100644 validators/run-validator/lib/programs.js create mode 100644 validators/run-validator/patches/@aleohq+sdk+0.6.9.patch diff --git a/development/test.sh b/development/test.sh index d92aa52..a2f6a51 100644 --- a/development/test.sh +++ b/development/test.sh @@ -2,6 +2,7 @@ source ./development/.env +LATEST_HEIGHT_ENDPOINT="$NODE_URL/testnet/latest/height"; TRANSACTION_ENDPOINT="$NODE_URL/testnet/transaction"; BROADCAST_ENDPOINT="$TRANSACTION_ENDPOINT/broadcast"; @@ -93,6 +94,13 @@ SLEEP_BETWEEN_TX=10 } +# Get current block height + +latest_height=$( + curl "$LATEST_HEIGHT_ENDPOINT" +); + + # List NFT { secret_random_viewkey="$((1 + $RANDOM % 100000))scalar" @@ -128,6 +136,7 @@ SLEEP_BETWEEN_TX=10 $((1 + $RANDOM % 100000))field ]" \ "$validators" \ + "${latest_height}u32"\ | awk 'NR==6' ); sleep $SLEEP_BETWEEN_TX; diff --git a/examples/nft_marketplace/programs/marketplace_example/src/main.leo b/examples/nft_marketplace/programs/marketplace_example/src/main.leo index 66189d1..fae33e3 100644 --- a/examples/nft_marketplace/programs/marketplace_example/src/main.leo +++ b/examples/nft_marketplace/programs/marketplace_example/src/main.leo @@ -48,7 +48,8 @@ program marketplace_example.aleo { public dcp_key: field, // random scalar private secret_random_viewkey: scalar, private privacy_random_coefficients: [field; 15], - private validators: [address; 16], + public validators: [address; 16], + public current_block_height: u32 ) -> (NFTView, Future) { let (nft_view, transfer_future): (arc721_example.aleo/NFTView, Future) = arc721_example.aleo/transfer_private_to_public( @@ -69,7 +70,8 @@ program marketplace_example.aleo { dcp_key, // private custody_key: field, privacy_random_coefficients, // private coefficients: [field; 15], validators, // private validators: [address; 16], - MPC_THRESHOLD // private threshold: u8 <= 15 + MPC_THRESHOLD, // private threshold: u8 <= 15 + current_block_height ); let list_future: Future = finalize_list( diff --git a/programs/credits/build/main.aleo b/programs/credits/build/main.aleo new file mode 100644 index 0000000..8def57a --- /dev/null +++ b/programs/credits/build/main.aleo @@ -0,0 +1,367 @@ +program credits.aleo; + +mapping committee: + key as address.public; + value as committee_state.public; + +struct committee_state: + is_open as boolean; + commission as u8; + +mapping delegated: + key as address.public; + value as u64.public; + +mapping metadata: + key as address.public; + value as u32.public; + +mapping bonded: + key as address.public; + value as bond_state.public; + +struct bond_state: + validator as address; + microcredits as u64; + +mapping unbonding: + key as address.public; + value as unbond_state.public; + +struct unbond_state: + microcredits as u64; + height as u32; + +mapping account: + key as address.public; + value as u64.public; + +mapping withdraw: + key as address.public; + value as address.public; + +record credits: + owner as address.private; + microcredits as u64.private; + +function bond_validator: + input r0 as address.public; + input r1 as u64.public; + input r2 as u8.public; + assert.neq self.signer r0; + gte r1 1000000u64 into r3; + assert.eq r3 true; + gt r2 100u8 into r4; + assert.neq r4 true; + async bond_validator self.signer r0 r1 r2 into r5; + output r5 as credits.aleo/bond_validator.future; +finalize bond_validator: + input r0 as address.public; + input r1 as address.public; + input r2 as u64.public; + input r3 as u8.public; + get.or_use withdraw[r0] r1 into r4; + assert.eq r1 r4; + cast true r3 into r5 as committee_state; + get.or_use committee[r0] r5 into r6; + assert.eq r3 r6.commission; + cast r0 0u64 into r7 as bond_state; + get.or_use bonded[r0] r7 into r8; + assert.eq r8.validator r0; + add r8.microcredits r2 into r9; + cast r0 r9 into r10 as bond_state; + get.or_use delegated[r0] 0u64 into r11; + add r2 r11 into r12; + gte r12 10000000000000u64 into r13; + assert.eq r13 true; + get account[r0] into r14; + sub r14 r2 into r15; + contains committee[r0] into r16; + branch.eq r16 true to validator_in_committee; + set r4 into withdraw[r0]; + gte r2 100000000u64 into r17; + assert.eq r17 true; + get.or_use metadata[aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc] 0u32 into r18; + add r18 1u32 into r19; + set r19 into metadata[aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc]; + contains unbonding[r0] into r20; + assert.eq r20 false; + position validator_in_committee; + set r6 into committee[r0]; + set r12 into delegated[r0]; + set r10 into bonded[r0]; + set r15 into account[r0]; + +function bond_public: + input r0 as address.public; + input r1 as address.public; + input r2 as u64.public; + gte r2 1000000u64 into r3; + assert.eq r3 true; + assert.neq self.caller r0; + async bond_public self.caller r0 r1 r2 into r4; + output r4 as credits.aleo/bond_public.future; +finalize bond_public: + input r0 as address.public; + input r1 as address.public; + input r2 as address.public; + input r3 as u64.public; + get.or_use withdraw[r0] r2 into r4; + assert.eq r2 r4; + contains bonded[r0] into r5; + branch.eq r5 true to continue_bond_delegator; + set r2 into withdraw[r0]; + cast true 0u8 into r6 as committee_state; + get.or_use committee[r1] r6 into r7; + assert.eq r7.is_open true; + get.or_use metadata[aleo1qgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqanmpl0] 0u32 into r8; + add r8 1u32 into r9; + lte r9 100000u32 into r10; + assert.eq r10 true; + set r9 into metadata[aleo1qgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqanmpl0]; + position continue_bond_delegator; + cast r1 0u64 into r11 as bond_state; + get.or_use bonded[r0] r11 into r12; + assert.eq r12.validator r1; + add r12.microcredits r3 into r13; + gte r13 10000000000u64 into r14; + assert.eq r14 true; + cast r1 r13 into r15 as bond_state; + get account[r0] into r16; + sub r16 r3 into r17; + get.or_use delegated[r1] 0u64 into r18; + add r3 r18 into r19; + contains unbonding[r1] into r20; + assert.eq r20 false; + set r15 into bonded[r0]; + set r17 into account[r0]; + set r19 into delegated[r1]; + +function unbond_public: + input r0 as address.public; + input r1 as u64.public; + async unbond_public self.caller r0 r1 into r2; + output r2 as credits.aleo/unbond_public.future; +finalize unbond_public: + input r0 as address.public; + input r1 as address.public; + input r2 as u64.public; + add block.height 360u32 into r3; + cast 0u64 r3 into r4 as unbond_state; + get bonded[r1] into r5; + get withdraw[r1] into r6; + is.eq r0 r6 into r7; + contains withdraw[r5.validator] into r8; + get.or_use withdraw[r5.validator] aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc into r9; + is.eq r0 r9 into r10; + and r8 r10 into r11; + or r7 r11 into r12; + assert.eq r12 true; + is.eq r5.validator r1 into r13; + branch.eq r13 true to unbond_validator; + get.or_use unbonding[r1] r4 into r14; + get delegated[r5.validator] into r15; + sub r5.microcredits r2 into r16; + lt r16 10000000000u64 into r17; + or r11 r17 into r18; + ternary r18 r5.microcredits r2 into r19; + add r14.microcredits r19 into r20; + cast r20 r3 into r21 as unbond_state; + set r21 into unbonding[r1]; + sub r15 r19 into r22; + set r22 into delegated[r5.validator]; + branch.eq r18 true to remove_delegator; + cast r5.validator r16 into r23 as bond_state; + set r23 into bonded[r1]; + branch.eq true true to end_unbond_delegator; + position remove_delegator; + remove bonded[r1]; + get metadata[aleo1qgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqanmpl0] into r24; + sub r24 1u32 into r25; + set r25 into metadata[aleo1qgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqanmpl0]; + position end_unbond_delegator; + gte r22 10000000000000u64 into r26; + branch.eq r26 true to end; + position unbond_validator; + contains committee[r5.validator] into r27; + nor r13 r27 into r28; + branch.eq r28 true to end; + get committee[r5.validator] into r29; + get bonded[r5.validator] into r30; + get delegated[r5.validator] into r31; + lt r31 10000000000000u64 into r32; + branch.eq r32 true to remove_validator; + sub r31 r2 into r33; + sub r30.microcredits r2 into r34; + gte r34 100000000u64 into r35; + gte r33 10000000000000u64 into r36; + and r35 r36 into r37; + branch.eq r37 false to remove_validator; + get.or_use unbonding[r5.validator] r4 into r38; + add r38.microcredits r2 into r39; + cast r39 r3 into r40 as unbond_state; + set r40 into unbonding[r5.validator]; + set r33 into delegated[r5.validator]; + cast r5.validator r34 into r41 as bond_state; + set r41 into bonded[r5.validator]; + branch.eq true true to end; + position remove_validator; + remove committee[r5.validator]; + get metadata[aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc] into r42; + sub r42 1u32 into r43; + set r43 into metadata[aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc]; + sub r31 r30.microcredits into r44; + set r44 into delegated[r5.validator]; + remove bonded[r5.validator]; + get.or_use unbonding[r5.validator] r4 into r45; + add r30.microcredits r45.microcredits into r46; + cast r46 r3 into r47 as unbond_state; + set r47 into unbonding[r5.validator]; + position end; + +function claim_unbond_public: + input r0 as address.public; + async claim_unbond_public r0 into r1; + output r1 as credits.aleo/claim_unbond_public.future; +finalize claim_unbond_public: + input r0 as address.public; + get unbonding[r0] into r1; + gte block.height r1.height into r2; + assert.eq r2 true; + get withdraw[r0] into r3; + get.or_use account[r3] 0u64 into r4; + add r1.microcredits r4 into r5; + set r5 into account[r3]; + remove unbonding[r0]; + contains bonded[r0] into r6; + branch.eq r6 true to end; + remove withdraw[r0]; + position end; + +function set_validator_state: + input r0 as boolean.public; + async set_validator_state self.caller r0 into r1; + output r1 as credits.aleo/set_validator_state.future; +finalize set_validator_state: + input r0 as address.public; + input r1 as boolean.public; + get committee[r0] into r2; + cast r1 r2.commission into r3 as committee_state; + set r3 into committee[r0]; + +function transfer_public: + input r0 as address.public; + input r1 as u64.public; + async transfer_public self.caller r0 r1 into r2; + output r2 as credits.aleo/transfer_public.future; +finalize transfer_public: + input r0 as address.public; + input r1 as address.public; + input r2 as u64.public; + get account[r0] into r3; + sub r3 r2 into r4; + set r4 into account[r0]; + get.or_use account[r1] 0u64 into r5; + add r5 r2 into r6; + set r6 into account[r1]; + +function transfer_public_as_signer: + input r0 as address.public; + input r1 as u64.public; + async transfer_public_as_signer self.signer r0 r1 into r2; + output r2 as credits.aleo/transfer_public_as_signer.future; +finalize transfer_public_as_signer: + input r0 as address.public; + input r1 as address.public; + input r2 as u64.public; + get account[r0] into r3; + sub r3 r2 into r4; + set r4 into account[r0]; + get.or_use account[r1] 0u64 into r5; + add r5 r2 into r6; + set r6 into account[r1]; + +function transfer_private: + input r0 as credits.record; + input r1 as address.private; + input r2 as u64.private; + sub r0.microcredits r2 into r3; + cast r1 r2 into r4 as credits.record; + cast r0.owner r3 into r5 as credits.record; + output r4 as credits.record; + output r5 as credits.record; + +function transfer_private_to_public: + input r0 as credits.record; + input r1 as address.public; + input r2 as u64.public; + sub r0.microcredits r2 into r3; + cast r0.owner r3 into r4 as credits.record; + async transfer_private_to_public r1 r2 into r5; + output r4 as credits.record; + output r5 as credits.aleo/transfer_private_to_public.future; +finalize transfer_private_to_public: + input r0 as address.public; + input r1 as u64.public; + get.or_use account[r0] 0u64 into r2; + add r1 r2 into r3; + set r3 into account[r0]; + +function transfer_public_to_private: + input r0 as address.private; + input r1 as u64.public; + cast r0 r1 into r2 as credits.record; + async transfer_public_to_private self.caller r1 into r3; + output r2 as credits.record; + output r3 as credits.aleo/transfer_public_to_private.future; +finalize transfer_public_to_private: + input r0 as address.public; + input r1 as u64.public; + get account[r0] into r2; + sub r2 r1 into r3; + set r3 into account[r0]; + +function join: + input r0 as credits.record; + input r1 as credits.record; + add r0.microcredits r1.microcredits into r2; + cast r0.owner r2 into r3 as credits.record; + output r3 as credits.record; + +function split: + input r0 as credits.record; + input r1 as u64.private; + sub r0.microcredits r1 into r2; + sub r2 10000u64 into r3; + cast r0.owner r1 into r4 as credits.record; + cast r0.owner r3 into r5 as credits.record; + output r4 as credits.record; + output r5 as credits.record; + +function fee_private: + input r0 as credits.record; + input r1 as u64.public; + input r2 as u64.public; + input r3 as field.public; + assert.neq r1 0u64; + assert.neq r3 0field; + add r1 r2 into r4; + sub r0.microcredits r4 into r5; + cast r0.owner r5 into r6 as credits.record; + output r6 as credits.record; + +function fee_public: + input r0 as u64.public; + input r1 as u64.public; + input r2 as field.public; + assert.neq r0 0u64; + assert.neq r2 0field; + add r0 r1 into r3; + async fee_public self.signer r3 into r4; + output r4 as credits.aleo/fee_public.future; +finalize fee_public: + input r0 as address.public; + input r1 as u64.public; + get account[r0] into r2; + sub r2 r1 into r3; + set r3 into account[r0]; diff --git a/programs/data_custody_protocol/src/main.leo b/programs/data_custody_protocol/src/main.leo index 04c473d..4fc8c9b 100644 --- a/programs/data_custody_protocol/src/main.leo +++ b/programs/data_custody_protocol/src/main.leo @@ -13,6 +13,9 @@ program data_custody_protocol.aleo { const MAX_VALIDATORS: u8 = 16u8; const MAX_VALIDATORS_MINUS_1: u8 = 15u8; const VALIDATORS_PER_BATCH: u8 = 16u8; + // 1 block every 5s ? + const INCENTIVE_TTL: u32 = 120u32; // 10min + const HEIGHT_RANGE: u32 = 60u32; // 5min inline hash_custody(custody: Custody) -> field { return BHP256::hash_to_field(custody); @@ -278,6 +281,7 @@ program data_custody_protocol.aleo { public validators: [address; 16], // MAX_VALIDATORS private validator_fee: u64, private protocol_fee_record: credits.aleo/credits, + public current_height: u32 ) -> (credits.aleo/credits, Future) { assert_neq(self.caller, self.signer); let custodied_data: Custody = Custody { @@ -312,6 +316,7 @@ program data_custody_protocol.aleo { to, validator_fee, expected_weight, + current_height + INCENTIVE_TTL ); let protocol_fee_amount: u64 = (MAX_VALIDATORS as u64) * validator_fee; @@ -331,16 +336,32 @@ program data_custody_protocol.aleo { ); let request_data_as_program_future: Future = finalize_request_data_as_program( + current_height, protocol_core_future, lock_fee_future ); return (protocol_fee_change, request_data_as_program_future); } async function finalize_request_data_as_program( + pretended_current_height: u32 protocol_core_future: Future, lock_fee_future: Future ){ + let actual_height: u32 = block.height; + assert(pretended_current_height <= actual_height); + assert(actual_height <= pretended_current_height + HEIGHT_RANGE); + /* + + -------|------------------|---------------------|------------|--------> + tx gen height finalize exec height Max accepted Incentive dies + <--------------------------------------> + HEIGHT_RANGE + <----------------------------------------------------> + INCENTIVE_TTL + + */ protocol_core_future.await(); lock_fee_future.await(); } } + diff --git a/programs/dcp_core_protocol/src/main.leo b/programs/dcp_core_protocol/src/main.leo index 7ad711e..1b9c742 100644 --- a/programs/dcp_core_protocol/src/main.leo +++ b/programs/dcp_core_protocol/src/main.leo @@ -376,9 +376,7 @@ program dcp_core_protocol.aleo { assert_eq(validators, validator_set); } - /* TODO UNCOMMENT ON LEO BUG FIX : - https://github.com/ProvableHQ/leo/issues/28192 - + transition process_request_as_validator( validator_share: dcp_validator_shares.aleo/ValidatorShare, withdraw_request: dcp_withdraw_requests.aleo/WithdrawRequest, @@ -395,13 +393,15 @@ program dcp_core_protocol.aleo { dcp_withdraw_requests.aleo/spend_withdraw_request(withdraw_request); let fee: dcp_fee_management.aleo/Fee = dcp_fee_management.aleo/mint_fee( - self.caller, withdraw_request.fee_amount + self.caller, + withdraw_request.fee_amount, + withdraw_request.expire ); assert_eq(withdraw_request.expected_weight, validator_share.weight); return (destination_share, fee); } - */ + transition spend_destination_shares( destination_share_0: DestinationShare, diff --git a/programs/dcp_fee_management/src/main.leo b/programs/dcp_fee_management/src/main.leo index 0e724fd..69deef9 100644 --- a/programs/dcp_fee_management/src/main.leo +++ b/programs/dcp_fee_management/src/main.leo @@ -4,16 +4,22 @@ import credits.aleo; program dcp_fee_management.aleo { record Fee { owner: address, - microcredits: u64 + microcredits: u64, + expire: u32 + } + + inline min_u32(a: u32, b: u32) -> u32{ + return a Fee { assert_eq(self.caller, dcp_core_protocol.aleo); return Fee{ owner: receiver, microcredits: amount, + expire: expire_height }; } @@ -24,10 +30,14 @@ program dcp_fee_management.aleo { fee.owner, fee.microcredits, ); - return finalize_burn_fee(unlock_fee_future); + return finalize_burn_fee(unlock_fee_future, fee.expire); } - async function finalize_burn_fee(unlock_fee_future: Future){ + async function finalize_burn_fee( + unlock_fee_future: Future, + expire_height: u32 + ){ unlock_fee_future.await(); + assert(expire_height >= block.height); } @@ -38,83 +48,7 @@ program dcp_fee_management.aleo { return Fee{ owner: fee_0.owner, microcredits: fee_0.microcredits + fee_1.microcredits, + expire: min_u32(fee_0.expire, fee_2.expire) }; } - - /* - async transition burn_2_fee( - private fee_0: Fee, - private fee_1: Fee, - ) -> Future { - let amount: u64 = ( - fee_0.microcredits - + fee_1.microcredits - ); - let unlock_fee_future: Future = credits.aleo/transfer_public( - fee_0.owner, - amount, - ); - return finalize_burn_fee(unlock_fee_future); - } - - async transition burn_3_fee( - private fee_0: Fee, - private fee_1: Fee, - private fee_2: Fee, - ) -> Future { - let amount: u64 = ( - fee_0.microcredits - + fee_1.microcredits - + fee_2.microcredits - ); - let unlock_fee_future: Future = credits.aleo/transfer_public( - fee_0.owner, - amount, - ); - return finalize_burn_fee(unlock_fee_future); - } - - - async transition burn_16_fee( - private fee_0: Fee, - private fee_1: Fee, - private fee_2: Fee, - private fee_3: Fee, - private fee_4: Fee, - private fee_5: Fee, - private fee_6: Fee, - private fee_7: Fee, - private fee_8: Fee, - private fee_9: Fee, - private fee_10: Fee, - private fee_11: Fee, - private fee_12: Fee, - private fee_13: Fee, - private fee_14: Fee, - private fee_15: Fee, - ) -> Future { - let amount: u64 = ( - fee_0.microcredits - + fee_1.microcredits - + fee_2.microcredits - + fee_3.microcredits - + fee_4.microcredits - + fee_5.microcredits - + fee_6.microcredits - + fee_7.microcredits - + fee_8.microcredits - + fee_9.microcredits - + fee_10.microcredits - + fee_11.microcredits - + fee_12.microcredits - + fee_13.microcredits - + fee_14.microcredits - + fee_15.microcredits - ); - credits.aleo/transfer_public( - fee_0.owner, - amount, - ); - } - */ } diff --git a/programs/dcp_withdraw_requests/src/main.leo b/programs/dcp_withdraw_requests/src/main.leo index 39b499f..11ac5bf 100644 --- a/programs/dcp_withdraw_requests/src/main.leo +++ b/programs/dcp_withdraw_requests/src/main.leo @@ -6,7 +6,8 @@ program dcp_withdraw_requests.aleo { custody_hash: field, to: address, fee_amount: u64, - expected_weight: u64 + expected_weight: u64, + expire: u32 } transition submit_requests_to_validators( @@ -14,7 +15,8 @@ program dcp_withdraw_requests.aleo { public custody_hash: field, private to: address, private validator_fee_amount: u64, - public expected_weight: u64 + public expected_weight: u64, + public expire_height: u32 ) -> ( WithdrawRequest, WithdrawRequest, @@ -40,112 +42,128 @@ program dcp_withdraw_requests.aleo { custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_1: WithdrawRequest = WithdrawRequest { owner: validators[1u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_2: WithdrawRequest = WithdrawRequest { owner: validators[2u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_3: WithdrawRequest = WithdrawRequest { owner: validators[3u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_4: WithdrawRequest = WithdrawRequest { owner: validators[4u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_5: WithdrawRequest = WithdrawRequest { owner: validators[5u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_6: WithdrawRequest = WithdrawRequest { owner: validators[6u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_7: WithdrawRequest = WithdrawRequest { owner: validators[7u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_8: WithdrawRequest = WithdrawRequest { owner: validators[8u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_9: WithdrawRequest = WithdrawRequest { owner: validators[9u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_10: WithdrawRequest = WithdrawRequest { owner: validators[10u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_11: WithdrawRequest = WithdrawRequest { owner: validators[11u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_12: WithdrawRequest = WithdrawRequest { owner: validators[12u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_13: WithdrawRequest = WithdrawRequest { owner: validators[13u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_14: WithdrawRequest = WithdrawRequest { owner: validators[14u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; let withdraw_request_15: WithdrawRequest = WithdrawRequest { owner: validators[15u8], custody_hash: custody_hash, to: to, fee_amount: validator_fee_amount, - expected_weight: expected_weight + expected_weight: expected_weight, + expire: expire_height }; return ( diff --git a/validators/run-rpc/start.js b/validators/run-rpc/start.js index 4829550..699fc79 100644 --- a/validators/run-rpc/start.js +++ b/validators/run-rpc/start.js @@ -46,6 +46,7 @@ const try_call_rpc_method = async (rpc_request) => { } + app.post("/", async (req, res) => { const rpc_request = req.body; try { @@ -61,4 +62,20 @@ app.post("/", async (req, res) => { } }); +/* +app.get( + "*", async (req, res) => { + try { + console.log(req); + } catch (e) { + const response = { + ...rpc_base, + error: e + '' + }; + + return res.status(400).send(response,); + } + } +); +*/ \ No newline at end of file diff --git a/validators/run-validator/config/db.js b/validators/run-validator/config/db.js index e793f50..cc00bfb 100644 --- a/validators/run-validator/config/db.js +++ b/validators/run-validator/config/db.js @@ -7,11 +7,15 @@ export const tables = { }, request_records: { name: "request_records", - columns: "(serial_number TEXT PRIMARY KEY, plaintext TEXT, spent INT, owner TXT, custody_hash TXT, to_address TXT, fee_amount TXT, expected_weight TXT, _nonce TXT)" + columns: "(serial_number TEXT PRIMARY KEY, plaintext TEXT, spent INT, owner TXT, custody_hash TXT, to_address TXT, fee_amount INT, expected_weight INT, expire INT, _nonce TXT)" }, share_records: { name: "share_records", - columns: "(serial_number TEXT PRIMARY KEY, plaintext TEXT, custody_hash TXT, spent INT, owner TXT, share TXT, custody TXT, weight TXT, _nonce TXT)" + columns: "(serial_number TEXT PRIMARY KEY, plaintext TEXT, spent INT, custody_hash TXT, owner TXT, share TXT, custody TXT, weight INT, _nonce TXT)" + }, + fee_records: { + name: "fee_records", + columns: "(serial_number TEXT PRIMARY KEY, plaintext TEXT, spent INT, owner TXT, microcredits INT, expire INT, _nonce TXT)" } }; @@ -19,8 +23,6 @@ export const tables = { export const db_file_name = "db.sqlite"; /* - - record ValidatorShare { owner: address, share: Share, @@ -37,5 +39,10 @@ record WithdrawRequest { expected_weight: u64 } +record Fee { + owner: address, + microcredits: u64, + expire: u32 +} */ \ No newline at end of file diff --git a/validators/run-validator/config/programs.js b/validators/run-validator/config/programs.js index 630c3a0..90e0392 100644 --- a/validators/run-validator/config/programs.js +++ b/validators/run-validator/config/programs.js @@ -8,11 +8,13 @@ export const jsav_function = "dcp_validator_shares.aleo/join_shares_as_validator export const srtv_function = "dcp_withdraw_requests.aleo/submit_requests_to_validators"; export const swr_function = "dcp_withdraw_requests.aleo/spend_withdraw_request"; +export const process_request_function = "dcp_core_protocol.aleo/process_request_as_validator"; export const hash_custody_function = "dcp_hash_custody_offchain.aleo/hash_custody"; - export const record_data_columns_amounts = { [share_record]: 5, [request_record]: 5 }; + +export const consider_record_spent_after_tx_during_s = 300; \ No newline at end of file diff --git a/validators/run-validator/lib/aleo.js b/validators/run-validator/lib/aleo.js index 6cde5f9..fd3e9df 100644 --- a/validators/run-validator/lib/aleo.js +++ b/validators/run-validator/lib/aleo.js @@ -1,22 +1,35 @@ import { Account, RecordPlaintext, ProgramManager, - initThreadPool, AleoKeyProvider, ProvingKey, VerifyingKey + initThreadPool, AleoKeyProvider, ProvingKey, VerifyingKey, + AleoNetworkClient, NetworkRecordProvider } from '@aleohq/sdk'; -import { data_dir } from "./path.js"; +import { data_dir, programs_dir } from "./path.js"; import fsExists from 'fs.promises.exists'; import fs from 'fs.promises'; +import * as dotenv from 'dotenv'; +dotenv.config(); + await initThreadPool(); const keyProvider = new AleoKeyProvider(); keyProvider.useCache(true); + export const load_aleo_account = async (privateKey) => { const account = new Account({ privateKey }); + const networkClient = new AleoNetworkClient(`${process.env.NODE_URL}`); + const recordProvider = new NetworkRecordProvider(account, networkClient); + const programManager = new ProgramManager( + `${process.env.NODE_URL}`, keyProvider, recordProvider + ); + + // await programManager.networkClient.getLatestHeight(); - const programManager = new ProgramManager(null, keyProvider); programManager.setAccount(account); + programManager.networkClient.fs = fs; + programManager.networkClient.programs_dir = programs_dir; account.programManager = programManager; return account; } @@ -101,30 +114,78 @@ export const execute_program_offchain = async ( } +export const execute_program_onchain = async ( + account, + program_id, + function_name, + inputs, + fee, +) => { + const program_name = program_id.split(".")[0]; + const [ + proving_key, + verifying_key + ] = await load_program_keys(program_name, function_name); + + const transaction = await account.programManager.buildExecutionTransaction( + program_id, + function_name, + fee, + false, + inputs, + null, + null, + null, + proving_key, + verifying_key, + account.privateKey(), + null, + ); + const result = await account.programManager.networkClient.submitTransaction(transaction); + console.log(`Submited: ${result}`) + return result; +} + + + +const get_key_paths = (program_name, function_name) => { + const proving_key_path = + `${data_dir}/${program_name}_${function_name}.prover`; + const verifying_key_path = + `${data_dir}/${program_name}_${function_name}.verifier`; + + return [proving_key_path, verifying_key_path] +} + + export const synthetize_program_keys = async ( account, program_name, program_source, function_name, inputs ) => { - const proving_key_path = `${data_dir}/${program_name}_${function_name}.prover`; - const verifying_key_path = `${data_dir}/${program_name}_${function_name}.verifier`; + const [proving_key_path, verifying_key_path] = get_key_paths( + program_name, function_name + ); if (await fsExists(proving_key_path) && await fsExists(verifying_key_path)) { return; } - const [proving_key, verifying_key] = await account.programManager.synthesizeKeys( - program_source, - function_name, - inputs, - account.privateKey() - ); + const [proving_key, verifying_key] = + await account + .programManager + .synthesizeKeys( + program_source, + function_name, + inputs, + account.privateKey() + ); await fs.writeFile(proving_key_path, proving_key.toBytes()); await fs.writeFile(verifying_key_path, verifying_key.toBytes()); } export const load_program_keys = async (program_name, function_name) => { - const proving_key_path = `${data_dir}/${program_name}_${function_name}.prover`; - const verifying_key_path = `${data_dir}/${program_name}_${function_name}.verifier`; - + const [proving_key_path, verifying_key_path] = get_key_paths( + program_name, function_name + ); const proving_key = ProvingKey.fromBytes( new Uint8Array(await fs.readFile(proving_key_path)) ); @@ -136,3 +197,22 @@ export const load_program_keys = async (program_name, function_name) => { } +const record_attributes = (record) => ( + Object.values(record).map(struct_repr) +); + + +const snarkvm_int_pattern = /^(\-*\d+)((i|u)(\d+))$/; +const convert_snarkvm_value = (col_value) => { + const matches_int = col_value.match(snarkvm_int_pattern); + if (matches_int) { + const [, number1, type, number2] = matches_int; + return BigInt(number1, 10); + } + return col_value; +} + + +export const converted_record_attributes = (record) => ( + record_attributes(record).map(convert_snarkvm_value) +); diff --git a/validators/run-validator/lib/db.js b/validators/run-validator/lib/db.js index cf73ce3..c39ce12 100644 --- a/validators/run-validator/lib/db.js +++ b/validators/run-validator/lib/db.js @@ -74,9 +74,14 @@ export const update_in_table = async (db, table, updates, where) => { export const select_from_table = async (db, table, where) => { const where_expr = (where == null) ? "" : ` WHERE ${where}` - const sql_cmd = `SELECT * FROM ${table}${where_expr}`; - console.log(`Executing: \`${sql_cmd}\``) - const result = db.exec(sql_cmd); + const sql_req = `SELECT * FROM ${table}${where_expr}`; + return await run_select_request(db, sql_req) +} + + +export const run_select_request = async (db, request) => { + console.log(`Executing: \`${request}\``) + const result = db.exec(request); if (result.length === 0) { return []; } @@ -93,6 +98,8 @@ export const select_from_table = async (db, table, where) => { } + + export const save_db = async (db) => { const data = db.export(); const buffer = Buffer.from(data); diff --git a/validators/run-validator/lib/process.js b/validators/run-validator/lib/process.js index 78caa2e..9823340 100644 --- a/validators/run-validator/lib/process.js +++ b/validators/run-validator/lib/process.js @@ -1,5 +1,88 @@ +import { + share_record, + request_record, + process_request_function, + consider_record_spent_after_tx_during_s, +} from "../config/programs.js"; +import { + call_process_request +} from './programs.js'; -export const process_requests = async (db, account) => { +import { record_table } from "./sync.js"; +import { run_select_request } from "./db.js"; -}; \ No newline at end of file + +export const process_requests = async (rpc_provider, db, account) => { + const validator_address = account.address().to_string(); + + // const joinable_couples = ...; + + // TODO IMPLEMENT JOIN WITH HELPERS ALL IN ONE TRANSACTION + + const query = ` + SELECT + req.serial_number req_serial, + share.serial_number share_serial, + req.plaintext req_plaintext, + share.plaintext share_plaintext, + share.weight weight, + req.fee_amount as fee + FROM ${record_table(request_record)} req + JOIN ${record_table(share_record)} share + ON share.custody_hash = req.custody_hash + WHERE + share.spent = 0 + AND + req.spent = 0 + AND + share.owner = '${validator_address}' + AND + req.owner = '${validator_address}' + AND + share.weight = req.expected_weight + GROUP BY req_serial; + `; + + const executable_couples = await run_select_request(db, query); + + // TODO IMPLEMENT CHOICE CONSIDERING LIVENESS INCENTIVE + const couple_to_execute = get_highest_fee_couple(executable_couples); + + console.log(couple_to_execute); + // execute process_request_as_validator on couple_to_execute + await process_request(account, couple_to_execute); + + const expire_timestamp = ( + Date.now() + consider_record_spent_after_tx_during_s * 1000 + ); + await Promise.all([ + tag_record_spent( + db, request_record, couple_to_execute.req_serial, expire_timestamp + ), + tag_record_spent( + db, share_record, couple_to_execute.share_serial, expire_timestamp + ) + ]); +}; + + +const process_request = async (account, couple_to_execute) => { + await call_process_request( + account, + couple_to_execute.share_plaintext, + couple_to_execute.req_plaintext + ) +} + + +function get_highest_fee_couple(couples) { + if (!couples || couples.length === 0) return null; + + return couples.reduce((maxFeeObject, currentObject) => { + const currentFee = parseInt(currentObject.fee.replace('u64', '')); + const maxFee = parseInt(maxFeeObject.fee.replace('u64', '')); + + return currentFee > maxFee ? currentObject : maxFeeObject; + }, couples[0]); +} \ No newline at end of file diff --git a/validators/run-validator/lib/programs.js b/validators/run-validator/lib/programs.js new file mode 100644 index 0000000..6dbe07b --- /dev/null +++ b/validators/run-validator/lib/programs.js @@ -0,0 +1,86 @@ +import { + execute_program_onchain, execute_program_offchain, synthetize_program_keys, +} from "./aleo.js" +import { + hash_custody_function, + process_request_function +} from "../config/programs.js"; + +import { programs_dir } from "./path.js"; +import fs from 'fs.promises'; + +export const hash_custody = async (account, custody) => { + const outputs = await execute_program_offchain( + account, + hash_custody_program_source, + hash_custody_program_name, + hash_custody_function_name, + [custody] + ); + return outputs[0]; +} + +export const call_process_request = async ( + account, share_record_plaintext, request_record_plaintext +) => { + const outputs = await execute_program_onchain( + account, + process_request_program_id, + process_request_function_name, + [share_record_plaintext, request_record_plaintext], + 0.0037, + ); + return outputs; +} + + +export const synthetize_programs_keys = async (account) => { + const address = account.address().to_string(); + await synthetize_program_keys( + account, + hash_custody_program_name, + hash_custody_program_source, + hash_custody_function_name, + ["{origin: aleo1050n3kd4x3spur952m58v56a572uxw8dlnxvmtn9qcjcqnjkty9q0xu8x5,custody_key: 7828field,threshold: 8u8}"] + ); + await synthetize_program_keys( + account, + process_request_program_name, + process_request_program_source, + process_request_function_name, + [ + `{owner:${address}.private,share:{share_val:4752445field.private,index:2field.private},custody:{origin:aleo1050n3kd4x3spur952m58v56a572uxw8dlnxvmtn9qcjcqnjkty9q0xu8x5.private,custody_key:7828field.private,threshold:8u8.private},weight:1u64.private,_nonce:6208724562062762170079864327493571698285315802189525497653082774780201029904group.public}`, + `{owner:${address}.private,custody_hash:7326020223694610699177037627683577570584146866729959130032521342380501061531field.private,to:aleo1m3p4haa2zv8f7qlvds53jle72r5f46lqgpk8jh5zvl350zcu9gxqxrua6e.private,fee_amount:1000u64.private,expected_weight:1u64.private,_nonce:5671608015959128205727583363521834414137213520861986854184800923741662679496group.public}`, + ] + ); +} + + +const load_program_source = async (program_id) => { + const program_name = program_id.split(".")[0]; + const program_path = `${programs_dir}/${program_name}/build/main.aleo`; + try { + return await fs.readFile(program_path, "utf-8"); + } + catch (e) { + throw new Error( + `'${program_id}' build not found,` + + `start by executing './development/build.sh' from project root.` + ); + } +} + + +const [ + hash_custody_program_id, + hash_custody_function_name +] = hash_custody_function.split("/"); +const hash_custody_program_name = hash_custody_program_id.split(".")[0]; +const hash_custody_program_source = await load_program_source(hash_custody_program_id); + +const [ + process_request_program_id, + process_request_function_name +] = process_request_function.split("/"); +const process_request_program_name = process_request_program_id.split(".")[0]; +const process_request_program_source = await load_program_source(process_request_program_id); diff --git a/validators/run-validator/lib/sync.js b/validators/run-validator/lib/sync.js index 79f5493..a109527 100644 --- a/validators/run-validator/lib/sync.js +++ b/validators/run-validator/lib/sync.js @@ -3,11 +3,10 @@ import { } from "./db.js" import { remove_whitespaces } from "./string.js" import { - serial_number, parse_record_plaintext, execute_program_offchain, - struct_repr, synthetize_program_keys + serial_number, parse_record_plaintext, struct_repr, converted_record_attributes } from "./aleo.js" import { sql_string } from "./string.js"; - +import { hash_custody } from "./programs.js"; import { share_record, @@ -16,14 +15,11 @@ import { jsav_function, srtv_function, swr_function, - hash_custody_function, - record_data_columns_amounts + record_data_columns_amounts, } from "../config/programs.js"; import { tables } from "../config/db.js" import { transaction_per_batch } from "../config/rpc.js" -import { programs_dir } from "./path.js"; -import fs from 'fs.promises'; const record_tables = { @@ -32,6 +28,23 @@ const record_tables = { } +export const remove_actually_unspent_records = async (db) => { + await Promise.all( + Object.keys(record_tables).map( + async (record_id) => await remove_actually_unspent_record(db, record_id) + ) + ); +} + + +const remove_actually_unspent_record = async (db, record_id) => { + const table_name = record_table(record_id); + const now = Date.now(); + const where = `spent > 1 AND spent <= ${now}`; + await update_in_table(db, table_name, { spent: 0 }, where); +} + + export const sync_db_with_blockchain = async (rpc_provider, db, account) => { const processed_transitions = await load_processed_transitions(db); await Promise.all([ @@ -58,7 +71,7 @@ const load_transactions_page = async (rpc_provider, programId, functionName, pag }; -const record_table = (record_id) => { +export const record_table = (record_id) => { const table_name = record_tables?.[record_id]; if (!table_name) { throw new Error("Unknown record name."); @@ -105,11 +118,6 @@ export const travel_transaction_pages = async ( } -const record_attributes = (record) => ( - Object.values(record).map(struct_repr) -); - - const get_record_data_columns = async (account, record_id, plaintext) => { const record = parse_record_plaintext(plaintext); if (record_id == share_record) { @@ -117,11 +125,11 @@ const get_record_data_columns = async (account, record_id, plaintext) => { const custody_hash = await hash_custody(account, custody); return [ custody_hash, - ...record_attributes(record) + ...converted_record_attributes(record) ]; } else if (record_id == request_record) { - return record_attributes(record); + return converted_record_attributes(record); } else { throw new Error("Unknown record name.") @@ -163,12 +171,13 @@ const tag_record_received = async ( }; -const tag_record_spent = async (db, record_id, serial) => { +const tag_record_spent = async (db, record_id, serial, expire_timestamp) => { const found = await retrieve_record_from_serial(db, record_id, serial); const table_name = record_table(record_id); if (found != null) { const where = `serial_number = ${sql_string(serial)}`; - await update_in_table(db, table_name, { spent: 1 }, where); + const spent = (expire_timestamp == null) ? 1 : expire_timestamp; + await update_in_table(db, table_name, { spent }, where); } else { const values = [serial, null, 1, ...(new Array(record_data_columns_amounts[record_id]).fill(null))]; await insert_into_table(db, table_name, values); @@ -291,50 +300,6 @@ const sync_swr_transitions = async ( } -const [ - hash_custody_program_id, - hash_custody_function_name -] = hash_custody_function.split("/"); -const hash_custody_program_name = hash_custody_program_id.split(".")[0]; - -const load_hash_custody = async () => { - const hash_custody_program_path = `${programs_dir}/${hash_custody_program_name}/build/main.aleo`; - try { - return await fs.readFile(hash_custody_program_path, "utf-8"); - } - catch (e) { - throw new Error( - `'${hash_custody_program_id}' build not found,` - + `start by executing './development/build.sh' from project root.` - ); - } -} -const hash_custody_program_source = await load_hash_custody(); - - -const hash_custody = async (account, custody) => { - const outputs = await execute_program_offchain( - account, - hash_custody_program_source, - hash_custody_program_name, - hash_custody_function_name, - [custody] - ); - return outputs[0]; -} - - -export const synthetize_hash_custody_keys = async (account) => { - return await synthetize_program_keys( - account, - "dcp_hash_custody_offchain", - hash_custody_program_source, - "hash_custody", - ["{origin: aleo1050n3kd4x3spur952m58v56a572uxw8dlnxvmtn9qcjcqnjkty9q0xu8x5,custody_key: 7828field,threshold: 8u8}"] - ) -} - - /* ---------- diff --git a/validators/run-validator/package-lock.json b/validators/run-validator/package-lock.json index f3d7335..c0ae209 100644 --- a/validators/run-validator/package-lock.json +++ b/validators/run-validator/package-lock.json @@ -7,12 +7,15 @@ "": { "name": "aleo-dcp-validator", "version": "1.0.0", + "hasInstallScript": true, "license": "ISC", "dependencies": { "@aleohq/sdk": "^0.6.9", + "@demox-labs/aleo-sdk-staging": "^0.3.35", "dotenv": "^16.4.5", "fs.promises": "^0.1.2", "fs.promises.exists": "^1.1.4", + "patch-package": "^8.0.0", "sql.js": "^1.10.3" } }, @@ -32,6 +35,11 @@ "resolved": "https://registry.npmjs.org/@aleohq/wasm/-/wasm-0.6.9.tgz", "integrity": "sha512-lDQePcCN+H4uyiCk3Vy22k+vpppogCSMveZk2f3qV3v0H0MCetA1dqFxR3HMZr73n2Yw7B6ZkwTlfotTdcGtPA==" }, + "node_modules/@demox-labs/aleo-sdk-staging": { + "version": "0.3.35", + "resolved": "https://registry.npmjs.org/@demox-labs/aleo-sdk-staging/-/aleo-sdk-staging-0.3.35.tgz", + "integrity": "sha512-vz6km2vyfqx2LzorYrou/DgmhGd8CRqRoopfXmie6uWB73/iWhAjeH+hvibcDRm7NRlAEcCejk3+gA3PvC1q4A==" + }, "node_modules/@types/concat-stream": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", @@ -58,6 +66,25 @@ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==" }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==" + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -68,6 +95,39 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -96,6 +156,51 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -112,6 +217,11 @@ "resolved": "https://registry.npmjs.org/comlink/-/comlink-4.4.1.tgz", "integrity": "sha512-+1dlx0aY5Jo1vHy/tSsIGpSkN4tS9rZSW8FIhG0JH/crs9wwweswIo/POr451r7bZww3hFbPAKnTpimzL/mm4Q==" }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, "node_modules/concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", @@ -131,6 +241,19 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -185,6 +308,25 @@ "node": ">= 0.4" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dependencies": { + "micromatch": "^4.0.2" + } + }, "node_modules/form-data": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", @@ -198,6 +340,20 @@ "node": ">= 0.12" } }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fs.promises": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/fs.promises/-/fs.promises-0.1.2.tgz", @@ -214,6 +370,11 @@ "url": "https://github.com/privatenumber/fs.promises.exists?sponsor=1" } }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -248,6 +409,26 @@ "node": ">=4" } }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -259,6 +440,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -325,16 +519,125 @@ "@types/node": "^10.0.3" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/json-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz", + "integrity": "sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==", + "dependencies": { + "call-bind": "^1.0.5", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/json-stable-stringify/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", @@ -365,6 +668,25 @@ "node": ">= 0.6" } }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -373,11 +695,106 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/parse-cache-control": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==" }, + "node_modules/patch-package": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz", + "integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "ci-info": "^3.7.0", + "cross-spawn": "^7.0.3", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^9.0.0", + "json-stable-stringify": "^1.0.2", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "rimraf": "^2.6.3", + "semver": "^7.5.3", + "slash": "^2.0.0", + "tmp": "^0.0.33", + "yaml": "^2.2.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=14", + "npm": ">5" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -419,11 +836,34 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -440,6 +880,25 @@ "node": ">= 0.4" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, "node_modules/side-channel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", @@ -457,6 +916,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "engines": { + "node": ">=6" + } + }, "node_modules/sql.js": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/sql.js/-/sql.js-1.10.3.tgz", @@ -470,6 +937,17 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/sync-request": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", @@ -517,15 +995,75 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==" }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } } } } diff --git a/validators/run-validator/package.json b/validators/run-validator/package.json index 97ac2e5..217dfe1 100644 --- a/validators/run-validator/package.json +++ b/validators/run-validator/package.json @@ -4,15 +4,18 @@ "description": "", "main": "run.js", "scripts": { - "start": "node start.js" + "start": "node start.js", + "postinstall": "patch-package" }, "author": "", "license": "ISC", "dependencies": { "@aleohq/sdk": "^0.6.9", + "@demox-labs/aleo-sdk-staging": "^0.3.35", "dotenv": "^16.4.5", "fs.promises": "^0.1.2", "fs.promises.exists": "^1.1.4", + "patch-package": "^8.0.0", "sql.js": "^1.10.3" }, "type": "module" diff --git a/validators/run-validator/patches/@aleohq+sdk+0.6.9.patch b/validators/run-validator/patches/@aleohq+sdk+0.6.9.patch new file mode 100644 index 0000000..bfd87b7 --- /dev/null +++ b/validators/run-validator/patches/@aleohq+sdk+0.6.9.patch @@ -0,0 +1,5555 @@ +diff --git a/node_modules/@aleohq/sdk/dist/index.js b/node_modules/@aleohq/sdk/dist/index.js +index 63224a4..5ada176 100644 +--- a/node_modules/@aleohq/sdk/dist/index.js ++++ b/node_modules/@aleohq/sdk/dist/index.js +@@ -31,181 +31,190 @@ import { wrap } from 'comlink'; + * // Verify a signature + * myRandomAccount.verify(hello_world, signature) + */ ++ ++const getProgramCust = async (t, program_id) => { ++ const program_name = program_id.split('.')[0]; ++ const program_dir = `${t.programs_dir}/${program_name}`; ++ const program_code_path = `${program_dir}/build/main.aleo`; ++ const program_code = await t.fs.readFile(program_code_path, 'utf8'); ++ return program_code; ++}; ++ + class Account { +- _privateKey; +- _viewKey; +- _address; +- constructor(params = {}) { +- try { +- this._privateKey = this.privateKeyFromParams(params); +- } +- catch (e) { +- console.error("Wrong parameter", e); +- throw new Error("Wrong Parameter"); +- } +- this._viewKey = ViewKey.from_private_key(this._privateKey); +- this._address = Address.from_private_key(this._privateKey); +- } +- /** +- * Attempts to create an account from a private key ciphertext +- * @param {PrivateKeyCiphertext | string} ciphertext +- * @param {string} password +- * @returns {PrivateKey | Error} +- * +- * @example +- * const ciphertext = PrivateKey.newEncrypted("password"); +- * const account = Account.fromCiphertext(ciphertext, "password"); +- */ +- static fromCiphertext(ciphertext, password) { +- try { +- ciphertext = (typeof ciphertext === "string") ? PrivateKeyCiphertext.fromString(ciphertext) : ciphertext; +- const _privateKey = PrivateKey.fromPrivateKeyCiphertext(ciphertext, password); +- return new Account({ privateKey: _privateKey.to_string() }); +- } +- catch (e) { +- throw new Error("Wrong password or invalid ciphertext"); +- } +- } +- privateKeyFromParams(params) { +- if (params.seed) { +- return PrivateKey.from_seed_unchecked(params.seed); +- } +- if (params.privateKey) { +- return PrivateKey.from_string(params.privateKey); +- } +- return new PrivateKey(); +- } +- privateKey() { +- return this._privateKey; +- } +- viewKey() { +- return this._viewKey; +- } +- address() { +- return this._address; +- } +- toString() { +- return this.address().to_string(); +- } +- /** +- * Encrypt the account's private key with a password +- * @param {string} ciphertext +- * @returns {PrivateKeyCiphertext} +- * +- * @example +- * const account = new Account(); +- * const ciphertext = account.encryptAccount("password"); +- */ +- encryptAccount(password) { +- return this._privateKey.toCiphertext(password); +- } +- /** +- * Decrypts a Record in ciphertext form into plaintext +- * @param {string} ciphertext +- * @returns {Record} +- * +- * @example +- * const account = new Account(); +- * const record = account.decryptRecord("record1ciphertext"); +- */ +- decryptRecord(ciphertext) { +- return this._viewKey.decrypt(ciphertext); +- } +- /** +- * Decrypts an array of Records in ciphertext form into plaintext +- * @param {string[]} ciphertexts +- * @returns {Record[]} +- * +- * @example +- * const account = new Account(); +- * const record = account.decryptRecords(["record1ciphertext", "record2ciphertext"]); +- */ +- decryptRecords(ciphertexts) { +- return ciphertexts.map((ciphertext) => this._viewKey.decrypt(ciphertext)); +- } +- /** +- * Determines whether the account owns a ciphertext record +- * @param {RecordCipherText | string} ciphertext +- * @returns {boolean} +- * +- * @example +- * // Create a connection to the Aleo network and an account +- * const connection = new NodeConnection("vm.aleo.org/api"); +- * const account = Account.fromCiphertext("ciphertext", "password"); +- * +- * // Get a record from the network +- * const record = connection.getBlock(1234); +- * const recordCipherText = record.transactions[0].execution.transitions[0].id; +- * +- * // Check if the account owns the record +- * if account.ownsRecord(recordCipherText) { +- * // Then one can do something like: +- * // Decrypt the record and check if it's spent +- * // Store the record in a local database +- * // Etc. +- * } +- */ +- ownsRecordCiphertext(ciphertext) { +- if (typeof ciphertext === 'string') { +- try { +- const ciphertextObject = RecordCiphertext.fromString(ciphertext); +- return ciphertextObject.isOwner(this._viewKey); +- } +- catch (e) { +- return false; +- } +- } +- else { +- return ciphertext.isOwner(this._viewKey); +- } +- } +- /** +- * Signs a message with the account's private key. +- * Returns a Signature. +- * +- * @param {Uint8Array} message +- * @returns {Signature} +- * +- * @example +- * const account = new Account(); +- * const message = Uint8Array.from([104, 101, 108, 108, 111 119, 111, 114, 108, 100]) +- * account.sign(message); +- */ +- sign(message) { +- return this._privateKey.sign(message); +- } +- /** +- * Verifies the Signature on a message. +- * +- * @param {Uint8Array} message +- * @param {Signature} signature +- * @returns {boolean} +- * +- * @example +- * const account = new Account(); +- * const message = Uint8Array.from([104, 101, 108, 108, 111 119, 111, 114, 108, 100]) +- * const signature = account.sign(message); +- * account.verify(message, signature); +- */ +- verify(message, signature) { +- return this._address.verify(message, signature); +- } ++ _privateKey; ++ _viewKey; ++ _address; ++ constructor(params = {}) { ++ try { ++ this._privateKey = this.privateKeyFromParams(params); ++ } ++ catch (e) { ++ console.error("Wrong parameter", e); ++ throw new Error("Wrong Parameter"); ++ } ++ this._viewKey = ViewKey.from_private_key(this._privateKey); ++ this._address = Address.from_private_key(this._privateKey); ++ } ++ /** ++ * Attempts to create an account from a private key ciphertext ++ * @param {PrivateKeyCiphertext | string} ciphertext ++ * @param {string} password ++ * @returns {PrivateKey | Error} ++ * ++ * @example ++ * const ciphertext = PrivateKey.newEncrypted("password"); ++ * const account = Account.fromCiphertext(ciphertext, "password"); ++ */ ++ static fromCiphertext(ciphertext, password) { ++ try { ++ ciphertext = (typeof ciphertext === "string") ? PrivateKeyCiphertext.fromString(ciphertext) : ciphertext; ++ const _privateKey = PrivateKey.fromPrivateKeyCiphertext(ciphertext, password); ++ return new Account({ privateKey: _privateKey.to_string() }); ++ } ++ catch (e) { ++ throw new Error("Wrong password or invalid ciphertext"); ++ } ++ } ++ privateKeyFromParams(params) { ++ if (params.seed) { ++ return PrivateKey.from_seed_unchecked(params.seed); ++ } ++ if (params.privateKey) { ++ return PrivateKey.from_string(params.privateKey); ++ } ++ return new PrivateKey(); ++ } ++ privateKey() { ++ return this._privateKey; ++ } ++ viewKey() { ++ return this._viewKey; ++ } ++ address() { ++ return this._address; ++ } ++ toString() { ++ return this.address().to_string(); ++ } ++ /** ++ * Encrypt the account's private key with a password ++ * @param {string} ciphertext ++ * @returns {PrivateKeyCiphertext} ++ * ++ * @example ++ * const account = new Account(); ++ * const ciphertext = account.encryptAccount("password"); ++ */ ++ encryptAccount(password) { ++ return this._privateKey.toCiphertext(password); ++ } ++ /** ++ * Decrypts a Record in ciphertext form into plaintext ++ * @param {string} ciphertext ++ * @returns {Record} ++ * ++ * @example ++ * const account = new Account(); ++ * const record = account.decryptRecord("record1ciphertext"); ++ */ ++ decryptRecord(ciphertext) { ++ return this._viewKey.decrypt(ciphertext); ++ } ++ /** ++ * Decrypts an array of Records in ciphertext form into plaintext ++ * @param {string[]} ciphertexts ++ * @returns {Record[]} ++ * ++ * @example ++ * const account = new Account(); ++ * const record = account.decryptRecords(["record1ciphertext", "record2ciphertext"]); ++ */ ++ decryptRecords(ciphertexts) { ++ return ciphertexts.map((ciphertext) => this._viewKey.decrypt(ciphertext)); ++ } ++ /** ++ * Determines whether the account owns a ciphertext record ++ * @param {RecordCipherText | string} ciphertext ++ * @returns {boolean} ++ * ++ * @example ++ * // Create a connection to the Aleo network and an account ++ * const connection = new NodeConnection("vm.aleo.org/api"); ++ * const account = Account.fromCiphertext("ciphertext", "password"); ++ * ++ * // Get a record from the network ++ * const record = connection.getBlock(1234); ++ * const recordCipherText = record.transactions[0].execution.transitions[0].id; ++ * ++ * // Check if the account owns the record ++ * if account.ownsRecord(recordCipherText) { ++ * // Then one can do something like: ++ * // Decrypt the record and check if it's spent ++ * // Store the record in a local database ++ * // Etc. ++ * } ++ */ ++ ownsRecordCiphertext(ciphertext) { ++ if (typeof ciphertext === 'string') { ++ try { ++ const ciphertextObject = RecordCiphertext.fromString(ciphertext); ++ return ciphertextObject.isOwner(this._viewKey); ++ } ++ catch (e) { ++ return false; ++ } ++ } ++ else { ++ return ciphertext.isOwner(this._viewKey); ++ } ++ } ++ /** ++ * Signs a message with the account's private key. ++ * Returns a Signature. ++ * ++ * @param {Uint8Array} message ++ * @returns {Signature} ++ * ++ * @example ++ * const account = new Account(); ++ * const message = Uint8Array.from([104, 101, 108, 108, 111 119, 111, 114, 108, 100]) ++ * account.sign(message); ++ */ ++ sign(message) { ++ return this._privateKey.sign(message); ++ } ++ /** ++ * Verifies the Signature on a message. ++ * ++ * @param {Uint8Array} message ++ * @param {Signature} signature ++ * @returns {boolean} ++ * ++ * @example ++ * const account = new Account(); ++ * const message = Uint8Array.from([104, 101, 108, 108, 111 119, 111, 114, 108, 100]) ++ * const signature = account.sign(message); ++ * account.verify(message, signature); ++ */ ++ verify(message, signature) { ++ return this._address.verify(message, signature); ++ } + } + + async function get(url) { +- const response = await fetch(url); +- if (!response.ok) { +- throw new Error(response.status + " could not get URL " + url); +- } +- return response; ++ const response = await fetch(url); ++ if (!response.ok) { ++ throw new Error(response.status + " could not get URL " + url); ++ } ++ return response; + } + async function post(url, options) { +- options.method = "POST"; +- const response = await fetch(url, options); +- if (!response.ok) { +- throw new Error(response.status + " could not post URL " + url); +- } +- return response; ++ options.method = "POST"; ++ const response = await fetch(url, options); ++ if (!response.ok) { ++ throw new Error(response.status + " could not post URL " + url); ++ } ++ return response; + } + + /** +@@ -221,605 +230,605 @@ async function post(url, options) { + * const publicnetworkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1"); + */ + class AleoNetworkClient { +- host; +- account; +- constructor(host) { +- this.host = host + "/testnet3"; +- } +- /** +- * Set an account to use in networkClient calls +- * +- * @param {Account} account +- * @example +- * const account = new Account(); +- * networkClient.setAccount(account); +- */ +- setAccount(account) { +- this.account = account; +- } +- /** +- * Return the Aleo account used in the networkClient +- * +- * @example +- * const account = networkClient.getAccount(); +- */ +- getAccount() { +- return this.account; +- } +- /** +- * Set a new host for the networkClient +- * +- * @param {string} host The address of a node hosting the Aleo API +- * @param host +- */ +- setHost(host) { +- this.host = host + "/testnet3"; +- } +- async fetchData(url = "/") { +- try { +- const response = await get(this.host + url); +- return await response.json(); +- } +- catch (error) { +- throw new Error("Error fetching data."); +- } +- } +- /** +- * Attempts to find unspent records in the Aleo blockchain for a specified private key +- * @param {number} startHeight - The height at which to start searching for unspent records +- * @param {number} endHeight - The height at which to stop searching for unspent records +- * @param {string | PrivateKey} privateKey - The private key to use to find unspent records +- * @param {number[]} amounts - The amounts (in microcredits) to search for (eg. [100, 200, 3000]) +- * @param {number} maxMicrocredits - The maximum number of microcredits to search for +- * @param {string[]} nonces - The nonces of already found records to exclude from the search +- * +- * @example +- * // Find all unspent records +- * const privateKey = "[PRIVATE_KEY]"; +- * const records = networkClient.findUnspentRecords(0, undefined, privateKey); +- * +- * // Find specific amounts +- * const startHeight = 500000; +- * const amounts = [600000, 1000000]; +- * const records = networkClient.findUnspentRecords(startHeight, undefined, privateKey, amounts); +- * +- * // Find specific amounts with a maximum number of cumulative microcredits +- * const maxMicrocredits = 100000; +- * const records = networkClient.findUnspentRecords(startHeight, undefined, privateKey, undefined, maxMicrocredits); +- */ +- async findUnspentRecords(startHeight, endHeight, privateKey, amounts, maxMicrocredits, nonces) { +- nonces = nonces || []; +- // Ensure start height is not negative +- if (startHeight < 0) { +- throw new Error("Start height must be greater than or equal to 0"); +- } +- // Initialize search parameters +- const records = new Array(); +- let start; +- let end; +- let resolvedPrivateKey; +- let failures = 0; +- let totalRecordValue = BigInt(0); +- let latestHeight; +- // Ensure a private key is present to find owned records +- if (typeof privateKey === "undefined") { +- if (typeof this.account === "undefined") { +- throw new Error("Private key must be specified in an argument to findOwnedRecords or set in the AleoNetworkClient"); +- } +- else { +- resolvedPrivateKey = this.account._privateKey; +- } +- } +- else { +- try { +- resolvedPrivateKey = privateKey instanceof PrivateKey ? privateKey : PrivateKey.from_string(privateKey); +- } +- catch (error) { +- throw new Error("Error parsing private key provided."); +- } +- } +- const viewKey = resolvedPrivateKey.to_view_key(); +- // Get the latest height to ensure the range being searched is valid +- try { +- const blockHeight = await this.getLatestHeight(); +- if (typeof blockHeight === "number") { +- latestHeight = blockHeight; +- } +- else { +- throw new Error("Error fetching latest block height."); +- } +- } +- catch (error) { +- throw new Error("Error fetching latest block height."); +- } +- // If no end height is specified or is greater than the latest height, set the end height to the latest height +- if (typeof endHeight === "number" && endHeight <= latestHeight) { +- end = endHeight; +- } +- else { +- end = latestHeight; +- } +- // If the starting is greater than the ending height, return an error +- if (startHeight > end) { +- throw new Error("Start height must be less than or equal to end height."); +- } +- // Iterate through blocks in reverse order in chunks of 50 +- while (end > startHeight) { +- start = end - 50; +- if (start < startHeight) { +- start = startHeight; +- } +- try { +- // Get 50 blocks (or the difference between the start and end if less than 50) +- const blocks = await this.getBlockRange(start, end); +- end = start; +- if (!(blocks instanceof Error)) { +- // Iterate through blocks to find unspent records +- for (let i = 0; i < blocks.length; i++) { +- const block = blocks[i]; +- const transactions = block.transactions; +- if (!(typeof transactions === "undefined")) { +- for (let j = 0; j < transactions.length; j++) { +- const confirmedTransaction = transactions[j]; +- // Search for unspent records in execute transactions of credits.aleo +- if (confirmedTransaction.type == "execute") { +- const transaction = confirmedTransaction.transaction; +- if (transaction.execution && !(typeof transaction.execution.transitions == "undefined")) { +- for (let k = 0; k < transaction.execution.transitions.length; k++) { +- const transition = transaction.execution.transitions[k]; +- // Only search for unspent records in credits.aleo (for now) +- if (transition.program !== "credits.aleo") { +- continue; +- } +- if (!(typeof transition.outputs == "undefined")) { +- for (let l = 0; l < transition.outputs.length; l++) { +- const output = transition.outputs[l]; +- if (output.type === "record") { +- try { +- // Create a wasm record ciphertext object from the found output +- const record = RecordCiphertext.fromString(output.value); +- // Determine if the record is owned by the specified view key +- if (record.isOwner(viewKey)) { +- // Decrypt the record and get the serial number +- const recordPlaintext = record.decrypt(viewKey); +- // If the record has already been found, skip it +- const nonce = recordPlaintext.nonce(); +- if (nonces.includes(nonce)) { +- continue; +- } +- // Otherwise record the nonce that has been found +- const serialNumber = recordPlaintext.serialNumberString(resolvedPrivateKey, "credits.aleo", "credits"); +- // Attempt to see if the serial number is spent +- try { +- await this.getTransitionId(serialNumber); +- } +- catch (error) { +- // If it's not found, add it to the list of unspent records +- if (!amounts) { +- records.push(recordPlaintext); +- // If the user specified a maximum number of microcredits, check if the search has found enough +- if (typeof maxMicrocredits === "number") { +- totalRecordValue += recordPlaintext.microcredits(); +- // Exit if the search has found the amount specified +- if (totalRecordValue >= BigInt(maxMicrocredits)) { +- return records; +- } +- } +- } +- // If the user specified a list of amounts, check if the search has found them +- if (!(typeof amounts === "undefined") && amounts.length > 0) { +- let amounts_found = 0; +- if (recordPlaintext.microcredits() > amounts[amounts_found]) { +- amounts_found += 1; +- records.push(recordPlaintext); +- // If the user specified a maximum number of microcredits, check if the search has found enough +- if (typeof maxMicrocredits === "number") { +- totalRecordValue += recordPlaintext.microcredits(); +- // Exit if the search has found the amount specified +- if (totalRecordValue >= BigInt(maxMicrocredits)) { +- return records; +- } +- } +- if (records.length >= amounts.length) { +- return records; +- } +- } +- } +- } +- } +- } +- catch (error) { +- } +- } +- } +- } ++ host; ++ account; ++ constructor(host) { ++ this.host = host + "/testnet"; ++ } ++ /** ++ * Set an account to use in networkClient calls ++ * ++ * @param {Account} account ++ * @example ++ * const account = new Account(); ++ * networkClient.setAccount(account); ++ */ ++ setAccount(account) { ++ this.account = account; ++ } ++ /** ++ * Return the Aleo account used in the networkClient ++ * ++ * @example ++ * const account = networkClient.getAccount(); ++ */ ++ getAccount() { ++ return this.account; ++ } ++ /** ++ * Set a new host for the networkClient ++ * ++ * @param {string} host The address of a node hosting the Aleo API ++ * @param host ++ */ ++ setHost(host) { ++ this.host = host + "/testnet"; ++ } ++ async fetchData(url = "/") { ++ try { ++ const response = await get(this.host + url); ++ return await response.json(); ++ } ++ catch (error) { ++ throw new Error("Error fetching data."); ++ } ++ } ++ /** ++ * Attempts to find unspent records in the Aleo blockchain for a specified private key ++ * @param {number} startHeight - The height at which to start searching for unspent records ++ * @param {number} endHeight - The height at which to stop searching for unspent records ++ * @param {string | PrivateKey} privateKey - The private key to use to find unspent records ++ * @param {number[]} amounts - The amounts (in microcredits) to search for (eg. [100, 200, 3000]) ++ * @param {number} maxMicrocredits - The maximum number of microcredits to search for ++ * @param {string[]} nonces - The nonces of already found records to exclude from the search ++ * ++ * @example ++ * // Find all unspent records ++ * const privateKey = "[PRIVATE_KEY]"; ++ * const records = networkClient.findUnspentRecords(0, undefined, privateKey); ++ * ++ * // Find specific amounts ++ * const startHeight = 500000; ++ * const amounts = [600000, 1000000]; ++ * const records = networkClient.findUnspentRecords(startHeight, undefined, privateKey, amounts); ++ * ++ * // Find specific amounts with a maximum number of cumulative microcredits ++ * const maxMicrocredits = 100000; ++ * const records = networkClient.findUnspentRecords(startHeight, undefined, privateKey, undefined, maxMicrocredits); ++ */ ++ async findUnspentRecords(startHeight, endHeight, privateKey, amounts, maxMicrocredits, nonces) { ++ nonces = nonces || []; ++ // Ensure start height is not negative ++ if (startHeight < 0) { ++ throw new Error("Start height must be greater than or equal to 0"); ++ } ++ // Initialize search parameters ++ const records = new Array(); ++ let start; ++ let end; ++ let resolvedPrivateKey; ++ let failures = 0; ++ let totalRecordValue = BigInt(0); ++ let latestHeight; ++ // Ensure a private key is present to find owned records ++ if (typeof privateKey === "undefined") { ++ if (typeof this.account === "undefined") { ++ throw new Error("Private key must be specified in an argument to findOwnedRecords or set in the AleoNetworkClient"); ++ } ++ else { ++ resolvedPrivateKey = this.account._privateKey; ++ } ++ } ++ else { ++ try { ++ resolvedPrivateKey = privateKey instanceof PrivateKey ? privateKey : PrivateKey.from_string(privateKey); ++ } ++ catch (error) { ++ throw new Error("Error parsing private key provided."); ++ } ++ } ++ const viewKey = resolvedPrivateKey.to_view_key(); ++ // Get the latest height to ensure the range being searched is valid ++ try { ++ const blockHeight = await this.getLatestHeight(); ++ if (typeof blockHeight === "number") { ++ latestHeight = blockHeight; ++ } ++ else { ++ throw new Error("Error fetching latest block height."); ++ } ++ } ++ catch (error) { ++ throw new Error("Error fetching latest block height."); ++ } ++ // If no end height is specified or is greater than the latest height, set the end height to the latest height ++ if (typeof endHeight === "number" && endHeight <= latestHeight) { ++ end = endHeight; ++ } ++ else { ++ end = latestHeight; ++ } ++ // If the starting is greater than the ending height, return an error ++ if (startHeight > end) { ++ throw new Error("Start height must be less than or equal to end height."); ++ } ++ // Iterate through blocks in reverse order in chunks of 50 ++ while (end > startHeight) { ++ start = end - 50; ++ if (start < startHeight) { ++ start = startHeight; ++ } ++ try { ++ // Get 50 blocks (or the difference between the start and end if less than 50) ++ const blocks = await this.getBlockRange(start, end); ++ end = start; ++ if (!(blocks instanceof Error)) { ++ // Iterate through blocks to find unspent records ++ for (let i = 0; i < blocks.length; i++) { ++ const block = blocks[i]; ++ const transactions = block.transactions; ++ if (!(typeof transactions === "undefined")) { ++ for (let j = 0; j < transactions.length; j++) { ++ const confirmedTransaction = transactions[j]; ++ // Search for unspent records in execute transactions of credits.aleo ++ if (confirmedTransaction.type == "execute") { ++ const transaction = confirmedTransaction.transaction; ++ if (transaction.execution && !(typeof transaction.execution.transitions == "undefined")) { ++ for (let k = 0; k < transaction.execution.transitions.length; k++) { ++ const transition = transaction.execution.transitions[k]; ++ // Only search for unspent records in credits.aleo (for now) ++ if (transition.program !== "credits.aleo") { ++ continue; ++ } ++ if (!(typeof transition.outputs == "undefined")) { ++ for (let l = 0; l < transition.outputs.length; l++) { ++ const output = transition.outputs[l]; ++ if (output.type === "record") { ++ try { ++ // Create a wasm record ciphertext object from the found output ++ const record = RecordCiphertext.fromString(output.value); ++ // Determine if the record is owned by the specified view key ++ if (record.isOwner(viewKey)) { ++ // Decrypt the record and get the serial number ++ const recordPlaintext = record.decrypt(viewKey); ++ // If the record has already been found, skip it ++ const nonce = recordPlaintext.nonce(); ++ if (nonces.includes(nonce)) { ++ continue; ++ } ++ // Otherwise record the nonce that has been found ++ const serialNumber = recordPlaintext.serialNumberString(resolvedPrivateKey, "credits.aleo", "credits"); ++ // Attempt to see if the serial number is spent ++ try { ++ await this.getTransitionId(serialNumber); ++ } ++ catch (error) { ++ // If it's not found, add it to the list of unspent records ++ if (!amounts) { ++ records.push(recordPlaintext); ++ // If the user specified a maximum number of microcredits, check if the search has found enough ++ if (typeof maxMicrocredits === "number") { ++ totalRecordValue += recordPlaintext.microcredits(); ++ // Exit if the search has found the amount specified ++ if (totalRecordValue >= BigInt(maxMicrocredits)) { ++ return records; ++ } ++ } ++ } ++ // If the user specified a list of amounts, check if the search has found them ++ if (!(typeof amounts === "undefined") && amounts.length > 0) { ++ let amounts_found = 0; ++ if (recordPlaintext.microcredits() > amounts[amounts_found]) { ++ amounts_found += 1; ++ records.push(recordPlaintext); ++ // If the user specified a maximum number of microcredits, check if the search has found enough ++ if (typeof maxMicrocredits === "number") { ++ totalRecordValue += recordPlaintext.microcredits(); ++ // Exit if the search has found the amount specified ++ if (totalRecordValue >= BigInt(maxMicrocredits)) { ++ return records; + } ++ } ++ if (records.length >= amounts.length) { ++ return records; ++ } + } ++ } + } ++ } + } ++ catch (error) { ++ } ++ } + } ++ } + } ++ } + } ++ } + } +- catch (error) { +- // If there is an error fetching blocks, log it and keep searching +- console.warn("Error fetching blocks in range: " + start.toString() + "-" + end.toString()); +- console.warn("Error: ", error); +- failures += 1; +- if (failures > 10) { +- console.warn("10 failures fetching records reached. Returning records fetched so far"); +- return records; +- } +- } +- } +- return records; +- } +- /** +- * Returns the contents of the block at the specified block height +- * +- * @param {number} height +- * @example +- * const block = networkClient.getBlock(1234); +- */ +- async getBlock(height) { +- try { +- const block = await this.fetchData("/block/" + height); +- return block; +- } +- catch (error) { +- throw new Error("Error fetching block."); +- } +- } +- /** +- * Returns a range of blocks between the specified block heights +- * +- * @param {number} start +- * @param {number} end +- * @example +- * const blockRange = networkClient.getBlockRange(2050, 2100); +- */ +- async getBlockRange(start, end) { +- try { +- return await this.fetchData("/blocks?start=" + start + "&end=" + end); +- } +- catch (error) { +- const errorMessage = "Error fetching blocks between " + start + " and " + end + "."; +- throw new Error(errorMessage); +- } +- } +- /** +- * Returns the deployment transaction id associated with the specified program +- * +- * @param {Program | string} program +- * @returns {TransactionModel | Error} +- */ +- async getDeploymentTransactionIDForProgram(program) { +- if (program instanceof Program) { +- program = program.toString(); +- } +- try { +- const id = await this.fetchData("/find/transactionID/deployment/" + program); +- return id.replace("\"", ""); +- } +- catch (error) { +- throw new Error("Error fetching deployment transaction for program."); +- } +- } +- /** +- * Returns the deployment transaction associated with a specified program +- * +- * @param {Program | string} program +- * @returns {TransactionModel | Error} +- */ +- async getDeploymentTransactionForProgram(program) { +- try { +- const transaction_id = await this.getDeploymentTransactionIDForProgram(program); +- return await this.getTransaction(transaction_id); +- } +- catch (error) { +- throw new Error("Error fetching deployment transaction for program."); +- } +- } +- /** +- * Returns the contents of the latest block +- * +- * @example +- * const latestHeight = networkClient.getLatestBlock(); +- */ +- async getLatestBlock() { +- try { +- return await this.fetchData("/latest/block"); +- } +- catch (error) { +- throw new Error("Error fetching latest block."); +- } +- } +- /** +- * Returns the latest committee +- * +- * @returns {Promise} A javascript object containing the latest committee +- */ +- async getLatestCommittee() { +- try { +- return await this.fetchData("/committee/latest"); +- } +- catch (error) { +- throw new Error("Error fetching latest block."); +- } +- } +- /** +- * Returns the latest block height +- * +- * @example +- * const latestHeight = networkClient.getLatestHeight(); +- */ +- async getLatestHeight() { +- try { +- return await this.fetchData("/latest/height"); +- } +- catch (error) { +- throw new Error("Error fetching latest height."); +- } +- } +- /** +- * Returns the source code of a program given a program ID +- * +- * @param {string} programId The program ID of a program deployed to the Aleo Network +- * @return {Promise} Source code of the program +- * +- * @example +- * const program = networkClient.getProgram("hello_hello.aleo"); +- * const expectedSource = "program hello_hello.aleo;\n\nfunction hello:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n" +- * assert.equal(program, expectedSource); +- */ +- async getProgram(programId) { +- try { +- return await this.fetchData("/program/" + programId); +- } +- catch (error) { +- throw new Error("Error fetching program"); +- } +- } +- /** +- * Returns a program object from a program ID or program source code +- * +- * @param {string} inputProgram The program ID or program source code of a program deployed to the Aleo Network +- * @return {Promise} Source code of the program +- * +- * @example +- * const programID = "hello_hello.aleo"; +- * const programSource = "program hello_hello.aleo;\n\nfunction hello:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n" +- * +- * // Get program object from program ID or program source code +- * const programObjectFromID = await networkClient.getProgramObject(programID); +- * const programObjectFromSource = await networkClient.getProgramObject(programSource); +- * +- * // Both program objects should be equal +- * assert.equal(programObjectFromID.to_string(), programObjectFromSource.to_string()); +- */ +- async getProgramObject(inputProgram) { +- try { +- return Program.fromString(inputProgram); +- } +- catch (error) { +- try { +- return Program.fromString((await this.getProgram(inputProgram))); +- } +- catch (error) { +- throw new Error(`${inputProgram} is neither a program name or a valid program`); +- } +- } +- } +- /** +- * Returns an object containing the source code of a program and the source code of all programs it imports +- * +- * @param {Program | string} inputProgram The program ID or program source code of a program deployed to the Aleo Network +- * @returns {Promise} Object of the form { "program_id": "program_source", .. } containing program id & source code for all program imports +- * +- * @example +- * const double_test_source = "import multiply_test.aleo;\n\nprogram double_test.aleo;\n\nfunction double_it:\n input r0 as u32.private;\n call multiply_test.aleo/multiply 2u32 r0 into r1;\n output r1 as u32.private;\n" +- * const double_test = Program.fromString(double_test_source); +- * const expectedImports = { +- * "multiply_test.aleo": "program multiply_test.aleo;\n\nfunction multiply:\n input r0 as u32.public;\n input r1 as u32.private;\n mul r0 r1 into r2;\n output r2 as u32.private;\n" +- * } +- * +- * // Imports can be fetched using the program ID, source code, or program object +- * let programImports = await networkClient.getProgramImports("double_test.aleo"); +- * assert.deepStrictEqual(programImports, expectedImports); +- * +- * // Using the program source code +- * programImports = await networkClient.getProgramImports(double_test_source); +- * assert.deepStrictEqual(programImports, expectedImports); +- * +- * // Using the program object +- * programImports = await networkClient.getProgramImports(double_test); +- * assert.deepStrictEqual(programImports, expectedImports); +- */ +- async getProgramImports(inputProgram) { +- try { +- const imports = {}; +- // Get the program object or fail if the program is not valid or does not exist +- const program = inputProgram instanceof Program ? inputProgram : (await this.getProgramObject(inputProgram)); +- // Get the list of programs that the program imports +- const importList = program.getImports(); +- // Recursively get any imports that the imported programs have in a depth first search order +- for (let i = 0; i < importList.length; i++) { +- const import_id = importList[i]; +- if (!imports.hasOwnProperty(import_id)) { +- const programSource = await this.getProgram(import_id); +- const nestedImports = await this.getProgramImports(import_id); +- for (const key in nestedImports) { +- if (!imports.hasOwnProperty(key)) { +- imports[key] = nestedImports[key]; +- } +- } +- imports[import_id] = programSource; +- } +- } +- return imports; +- } +- catch (error) { +- throw logAndThrow("Error fetching program imports: " + error); +- } +- } +- /** +- * Get a list of the program names that a program imports +- * +- * @param {Program | string} inputProgram - The program id or program source code to get the imports of +- * @returns {string[]} - The list of program names that the program imports +- * +- * @example +- * const programImportsNames = networkClient.getProgramImports("double_test.aleo"); +- * const expectedImportsNames = ["multiply_test.aleo"]; +- * assert.deepStrictEqual(programImportsNames, expectedImportsNames); +- */ +- async getProgramImportNames(inputProgram) { +- try { +- const program = inputProgram instanceof Program ? inputProgram : (await this.getProgramObject(inputProgram)); +- return program.getImports(); +- } +- catch (error) { +- throw new Error("Error fetching program imports with error: " + error); +- } +- } +- /** +- * Returns the names of the mappings of a program +- * +- * @param {string} programId - The program ID to get the mappings of (e.g. "credits.aleo") +- * @example +- * const mappings = networkClient.getProgramMappingNames("credits.aleo"); +- * const expectedMappings = ["account"]; +- * assert.deepStrictEqual(mappings, expectedMappings); +- */ +- async getProgramMappingNames(programId) { +- try { +- return await this.fetchData("/program/" + programId + "/mappings"); +- } +- catch (error) { +- throw new Error("Error fetching program mappings - ensure the program exists on chain before trying again"); +- } +- } +- /** +- * Returns the value of a program's mapping for a specific key +- * +- * @param {string} programId - The program ID to get the mapping value of (e.g. "credits.aleo") +- * @param {string} mappingName - The name of the mapping to get the value of (e.g. "account") +- * @param {string} key - The key of the mapping to get the value of (e.g. "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px") +- * @return {Promise} String representation of the value of the mapping +- * +- * @example +- * // Get public balance of an account +- * const mappingValue = networkClient.getMappingValue("credits.aleo", "account", "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px"); +- * const expectedValue = "0u64"; +- * assert.equal(mappingValue, expectedValue); +- */ +- async getProgramMappingValue(programId, mappingName, key) { +- try { +- return await this.fetchData("/program/" + programId + "/mapping/" + mappingName + "/" + key); +- } +- catch (error) { +- throw new Error("Error fetching mapping value - ensure the mapping exists and the key is correct"); +- } +- } +- /** +- * Returns the latest state/merkle root of the Aleo blockchain +- * +- * @example +- * const stateRoot = networkClient.getStateRoot(); +- */ +- async getStateRoot() { +- try { +- return await this.fetchData("/latest/stateRoot"); +- } +- catch (error) { +- throw new Error("Error fetching Aleo state root"); +- } +- } +- /** +- * Returns a transaction by its unique identifier +- * +- * @param {string} id +- * @example +- * const transaction = networkClient.getTransaction("at1handz9xjrqeynjrr0xay4pcsgtnczdksz3e584vfsgaz0dh0lyxq43a4wj"); +- */ +- async getTransaction(id) { +- try { +- return await this.fetchData("/transaction/" + id); +- } +- catch (error) { +- throw new Error("Error fetching transaction."); +- } +- } +- /** +- * Returns the transactions present at the specified block height +- * +- * @param {number} height +- * @example +- * const transactions = networkClient.getTransactions(654); +- */ +- async getTransactions(height) { +- try { +- return await this.fetchData("/block/" + height.toString() + "/transactions"); +- } +- catch (error) { +- throw new Error("Error fetching transactions."); +- } +- } +- /** +- * Returns the transactions in the memory pool. +- * +- * @example +- * const transactions = networkClient.getTransactionsInMempool(); +- */ +- async getTransactionsInMempool() { +- try { +- return await this.fetchData("/memoryPool/transactions"); +- } +- catch (error) { +- throw new Error("Error fetching transactions from mempool."); +- } +- } +- /** +- * Returns the transition ID of the transition corresponding to the ID of the input or output. +- * @param {string} inputOrOutputID - ID of the input or output. +- * +- * @example +- * const transitionId = networkClient.getTransitionId("2429232855236830926144356377868449890830704336664550203176918782554219952323field"); +- */ +- async getTransitionId(inputOrOutputID) { +- try { +- return await this.fetchData("/find/transitionID/" + inputOrOutputID); +- } +- catch (error) { +- throw new Error("Error fetching transition ID."); +- } +- } +- /** +- * Submit an execute or deployment transaction to the Aleo network +- * +- * @param {Transaction | string} transaction - The transaction to submit to the network +- * @returns {string | Error} - The transaction id of the submitted transaction or the resulting error +- */ +- async submitTransaction(transaction) { +- const transaction_string = transaction instanceof Transaction ? transaction.toString() : transaction; +- try { +- const response = await post(this.host + "/transaction/broadcast", { +- body: transaction_string, +- headers: { +- "Content-Type": "application/json", +- }, +- }); +- try { +- return await response.json(); +- } +- catch (error) { +- throw new Error(`Error posting transaction. Aleo network response: ${error.message}`); ++ } ++ } ++ } ++ catch (error) { ++ // If there is an error fetching blocks, log it and keep searching ++ console.warn("Error fetching blocks in range: " + start.toString() + "-" + end.toString()); ++ console.warn("Error: ", error); ++ failures += 1; ++ if (failures > 10) { ++ console.warn("10 failures fetching records reached. Returning records fetched so far"); ++ return records; ++ } ++ } ++ } ++ return records; ++ } ++ /** ++ * Returns the contents of the block at the specified block height ++ * ++ * @param {number} height ++ * @example ++ * const block = networkClient.getBlock(1234); ++ */ ++ async getBlock(height) { ++ try { ++ const block = await this.fetchData("/block/" + height); ++ return block; ++ } ++ catch (error) { ++ throw new Error("Error fetching block."); ++ } ++ } ++ /** ++ * Returns a range of blocks between the specified block heights ++ * ++ * @param {number} start ++ * @param {number} end ++ * @example ++ * const blockRange = networkClient.getBlockRange(2050, 2100); ++ */ ++ async getBlockRange(start, end) { ++ try { ++ return await this.fetchData("/blocks?start=" + start + "&end=" + end); ++ } ++ catch (error) { ++ const errorMessage = "Error fetching blocks between " + start + " and " + end + "."; ++ throw new Error(errorMessage); ++ } ++ } ++ /** ++ * Returns the deployment transaction id associated with the specified program ++ * ++ * @param {Program | string} program ++ * @returns {TransactionModel | Error} ++ */ ++ async getDeploymentTransactionIDForProgram(program) { ++ if (program instanceof Program) { ++ program = program.toString(); ++ } ++ try { ++ const id = await this.fetchData("/find/transactionID/deployment/" + program); ++ return id.replace("\"", ""); ++ } ++ catch (error) { ++ throw new Error("Error fetching deployment transaction for program."); ++ } ++ } ++ /** ++ * Returns the deployment transaction associated with a specified program ++ * ++ * @param {Program | string} program ++ * @returns {TransactionModel | Error} ++ */ ++ async getDeploymentTransactionForProgram(program) { ++ try { ++ const transaction_id = await this.getDeploymentTransactionIDForProgram(program); ++ return await this.getTransaction(transaction_id); ++ } ++ catch (error) { ++ throw new Error("Error fetching deployment transaction for program."); ++ } ++ } ++ /** ++ * Returns the contents of the latest block ++ * ++ * @example ++ * const latestHeight = networkClient.getLatestBlock(); ++ */ ++ async getLatestBlock() { ++ try { ++ return await this.fetchData("/latest/block"); ++ } ++ catch (error) { ++ throw new Error("Error fetching latest block."); ++ } ++ } ++ /** ++ * Returns the latest committee ++ * ++ * @returns {Promise} A javascript object containing the latest committee ++ */ ++ async getLatestCommittee() { ++ try { ++ return await this.fetchData("/committee/latest"); ++ } ++ catch (error) { ++ throw new Error("Error fetching latest block."); ++ } ++ } ++ /** ++ * Returns the latest block height ++ * ++ * @example ++ * const latestHeight = networkClient.getLatestHeight(); ++ */ ++ async getLatestHeight() { ++ try { ++ return await this.fetchData("/latest/height"); ++ } ++ catch (error) { ++ throw new Error("Error fetching latest height."); ++ } ++ } ++ /** ++ * Returns the source code of a program given a program ID ++ * ++ * @param {string} programId The program ID of a program deployed to the Aleo Network ++ * @return {Promise} Source code of the program ++ * ++ * @example ++ * const program = networkClient.getProgram("hello_hello.aleo"); ++ * const expectedSource = "program hello_hello.aleo;\n\nfunction hello:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n" ++ * assert.equal(program, expectedSource); ++ */ ++ async getProgram(programId) { ++ try { ++ return await this.fetchData("/program/" + programId); ++ } ++ catch (error) { ++ throw new Error("Error fetching program"); ++ } ++ } ++ /** ++ * Returns a program object from a program ID or program source code ++ * ++ * @param {string} inputProgram The program ID or program source code of a program deployed to the Aleo Network ++ * @return {Promise} Source code of the program ++ * ++ * @example ++ * const programID = "hello_hello.aleo"; ++ * const programSource = "program hello_hello.aleo;\n\nfunction hello:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n" ++ * ++ * // Get program object from program ID or program source code ++ * const programObjectFromID = await networkClient.getProgramObject(programID); ++ * const programObjectFromSource = await networkClient.getProgramObject(programSource); ++ * ++ * // Both program objects should be equal ++ * assert.equal(programObjectFromID.to_string(), programObjectFromSource.to_string()); ++ */ ++ async getProgramObject(inputProgram) { ++ try { ++ return Program.fromString(inputProgram); ++ } ++ catch (error) { ++ try { ++ return Program.fromString((await getProgramCust(this, inputProgram))); ++ } ++ catch (error) { ++ throw new Error(`${inputProgram} is neither a program name or a valid program`); ++ } ++ } ++ } ++ /** ++ * Returns an object containing the source code of a program and the source code of all programs it imports ++ * ++ * @param {Program | string} inputProgram The program ID or program source code of a program deployed to the Aleo Network ++ * @returns {Promise} Object of the form { "program_id": "program_source", .. } containing program id & source code for all program imports ++ * ++ * @example ++ * const double_test_source = "import multiply_test.aleo;\n\nprogram double_test.aleo;\n\nfunction double_it:\n input r0 as u32.private;\n call multiply_test.aleo/multiply 2u32 r0 into r1;\n output r1 as u32.private;\n" ++ * const double_test = Program.fromString(double_test_source); ++ * const expectedImports = { ++ * "multiply_test.aleo": "program multiply_test.aleo;\n\nfunction multiply:\n input r0 as u32.public;\n input r1 as u32.private;\n mul r0 r1 into r2;\n output r2 as u32.private;\n" ++ * } ++ * ++ * // Imports can be fetched using the program ID, source code, or program object ++ * let programImports = await networkClient.getProgramImports("double_test.aleo"); ++ * assert.deepStrictEqual(programImports, expectedImports); ++ * ++ * // Using the program source code ++ * programImports = await networkClient.getProgramImports(double_test_source); ++ * assert.deepStrictEqual(programImports, expectedImports); ++ * ++ * // Using the program object ++ * programImports = await networkClient.getProgramImports(double_test); ++ * assert.deepStrictEqual(programImports, expectedImports); ++ */ ++ async getProgramImports(inputProgram) { ++ try { ++ const imports = {}; ++ // Get the program object or fail if the program is not valid or does not exist ++ const program = inputProgram instanceof Program ? inputProgram : (await this.getProgramObject(inputProgram)); ++ // Get the list of programs that the program imports ++ const importList = program.getImports(); ++ // Recursively get any imports that the imported programs have in a depth first search order ++ for (let i = 0; i < importList.length; i++) { ++ const import_id = importList[i]; ++ if (!imports.hasOwnProperty(import_id)) { ++ const programSource = await getProgramCust(this, import_id); ++ const nestedImports = await this.getProgramImports(import_id); ++ for (const key in nestedImports) { ++ if (!imports.hasOwnProperty(key)) { ++ imports[key] = nestedImports[key]; + } +- } +- catch (error) { +- throw new Error(`Error posting transaction: No response received: ${error.message}`); +- } +- } ++ } ++ imports[import_id] = programSource; ++ } ++ } ++ return imports; ++ } ++ catch (error) { ++ throw logAndThrow("Error fetching program imports: " + error); ++ } ++ } ++ /** ++ * Get a list of the program names that a program imports ++ * ++ * @param {Program | string} inputProgram - The program id or program source code to get the imports of ++ * @returns {string[]} - The list of program names that the program imports ++ * ++ * @example ++ * const programImportsNames = networkClient.getProgramImports("double_test.aleo"); ++ * const expectedImportsNames = ["multiply_test.aleo"]; ++ * assert.deepStrictEqual(programImportsNames, expectedImportsNames); ++ */ ++ async getProgramImportNames(inputProgram) { ++ try { ++ const program = inputProgram instanceof Program ? inputProgram : (await this.getProgramObject(inputProgram)); ++ return program.getImports(); ++ } ++ catch (error) { ++ throw new Error("Error fetching program imports with error: " + error); ++ } ++ } ++ /** ++ * Returns the names of the mappings of a program ++ * ++ * @param {string} programId - The program ID to get the mappings of (e.g. "credits.aleo") ++ * @example ++ * const mappings = networkClient.getProgramMappingNames("credits.aleo"); ++ * const expectedMappings = ["account"]; ++ * assert.deepStrictEqual(mappings, expectedMappings); ++ */ ++ async getProgramMappingNames(programId) { ++ try { ++ return await this.fetchData("/program/" + programId + "/mappings"); ++ } ++ catch (error) { ++ throw new Error("Error fetching program mappings - ensure the program exists on chain before trying again"); ++ } ++ } ++ /** ++ * Returns the value of a program's mapping for a specific key ++ * ++ * @param {string} programId - The program ID to get the mapping value of (e.g. "credits.aleo") ++ * @param {string} mappingName - The name of the mapping to get the value of (e.g. "account") ++ * @param {string} key - The key of the mapping to get the value of (e.g. "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px") ++ * @return {Promise} String representation of the value of the mapping ++ * ++ * @example ++ * // Get public balance of an account ++ * const mappingValue = networkClient.getMappingValue("credits.aleo", "account", "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px"); ++ * const expectedValue = "0u64"; ++ * assert.equal(mappingValue, expectedValue); ++ */ ++ async getProgramMappingValue(programId, mappingName, key) { ++ try { ++ return await this.fetchData("/program/" + programId + "/mapping/" + mappingName + "/" + key); ++ } ++ catch (error) { ++ throw new Error("Error fetching mapping value - ensure the mapping exists and the key is correct"); ++ } ++ } ++ /** ++ * Returns the latest state/merkle root of the Aleo blockchain ++ * ++ * @example ++ * const stateRoot = networkClient.getStateRoot(); ++ */ ++ async getStateRoot() { ++ try { ++ return await this.fetchData("/latest/stateRoot"); ++ } ++ catch (error) { ++ throw new Error("Error fetching Aleo state root"); ++ } ++ } ++ /** ++ * Returns a transaction by its unique identifier ++ * ++ * @param {string} id ++ * @example ++ * const transaction = networkClient.getTransaction("at1handz9xjrqeynjrr0xay4pcsgtnczdksz3e584vfsgaz0dh0lyxq43a4wj"); ++ */ ++ async getTransaction(id) { ++ try { ++ return await this.fetchData("/transaction/" + id); ++ } ++ catch (error) { ++ throw new Error("Error fetching transaction."); ++ } ++ } ++ /** ++ * Returns the transactions present at the specified block height ++ * ++ * @param {number} height ++ * @example ++ * const transactions = networkClient.getTransactions(654); ++ */ ++ async getTransactions(height) { ++ try { ++ return await this.fetchData("/block/" + height.toString() + "/transactions"); ++ } ++ catch (error) { ++ throw new Error("Error fetching transactions."); ++ } ++ } ++ /** ++ * Returns the transactions in the memory pool. ++ * ++ * @example ++ * const transactions = networkClient.getTransactionsInMempool(); ++ */ ++ async getTransactionsInMempool() { ++ try { ++ return await this.fetchData("/memoryPool/transactions"); ++ } ++ catch (error) { ++ throw new Error("Error fetching transactions from mempool."); ++ } ++ } ++ /** ++ * Returns the transition ID of the transition corresponding to the ID of the input or output. ++ * @param {string} inputOrOutputID - ID of the input or output. ++ * ++ * @example ++ * const transitionId = networkClient.getTransitionId("2429232855236830926144356377868449890830704336664550203176918782554219952323field"); ++ */ ++ async getTransitionId(inputOrOutputID) { ++ try { ++ return await this.fetchData("/find/transitionID/" + inputOrOutputID); ++ } ++ catch (error) { ++ throw new Error("Error fetching transition ID."); ++ } ++ } ++ /** ++ * Submit an execute or deployment transaction to the Aleo network ++ * ++ * @param {Transaction | string} transaction - The transaction to submit to the network ++ * @returns {string | Error} - The transaction id of the submitted transaction or the resulting error ++ */ ++ async submitTransaction(transaction) { ++ const transaction_string = transaction instanceof Transaction ? transaction.toString() : transaction; ++ try { ++ const response = await post(this.host + "/transaction/broadcast", { ++ body: transaction_string, ++ headers: { ++ "Content-Type": "application/json", ++ }, ++ }); ++ try { ++ return await response.json(); ++ } ++ catch (error) { ++ throw new Error(`Error posting transaction. Aleo network response: ${error.message}`); ++ } ++ } ++ catch (error) { ++ throw new Error(`Error posting transaction: No response received: ${error.message}`); ++ } ++ } + } + + /** +@@ -827,22 +836,22 @@ class AleoNetworkClient { + * verifierUri to fetch keys via HTTP from a remote resource as well as a unique cacheKey to store the keys in memory. + */ + class AleoKeyProviderParams { +- proverUri; +- verifierUri; +- cacheKey; +- /** +- * Create a new AleoKeyProviderParams object which implements the KeySearchParams interface. Users can optionally +- * specify a url for the proverUri & verifierUri to fetch keys via HTTP from a remote resource as well as a unique +- * cacheKey to store the keys in memory for future use. If no proverUri or verifierUri is specified, a cachekey must +- * be provided. +- * +- * @param { AleoKeyProviderInitParams } params - Optional search parameters +- */ +- constructor(params) { +- this.proverUri = params.proverUri; +- this.verifierUri = params.verifierUri; +- this.cacheKey = params.cacheKey; +- } ++ proverUri; ++ verifierUri; ++ cacheKey; ++ /** ++ * Create a new AleoKeyProviderParams object which implements the KeySearchParams interface. Users can optionally ++ * specify a url for the proverUri & verifierUri to fetch keys via HTTP from a remote resource as well as a unique ++ * cacheKey to store the keys in memory for future use. If no proverUri or verifierUri is specified, a cachekey must ++ * be provided. ++ * ++ * @param { AleoKeyProviderInitParams } params - Optional search parameters ++ */ ++ constructor(params) { ++ this.proverUri = params.proverUri; ++ this.verifierUri = params.verifierUri; ++ this.cacheKey = params.cacheKey; ++ } + } + /** + * AleoKeyProvider class. Implements the KeyProvider interface. Enables the retrieval of Aleo program proving and +@@ -850,310 +859,310 @@ class AleoKeyProviderParams { + * keys from a local memory cache. + */ + class AleoKeyProvider { +- cache; +- cacheOption; +- keyUris; +- async fetchBytes(url = "/") { +- try { +- const response = await get(url); +- const data = await response.arrayBuffer(); +- return new Uint8Array(data); +- } +- catch (error) { +- throw new Error("Error fetching data." + error); +- } +- } +- constructor() { +- this.keyUris = KEY_STORE; +- this.cache = new Map(); +- this.cacheOption = false; +- } +- /** +- * Use local memory to store keys +- * +- * @param {boolean} useCache whether to store keys in local memory +- */ +- useCache(useCache) { +- this.cacheOption = useCache; +- } +- /** +- * Clear the key cache +- */ +- clearCache() { +- this.cache.clear(); +- } +- /** +- * Cache a set of keys. This will overwrite any existing keys with the same keyId. The user can check if a keyId +- * exists in the cache using the containsKeys method prior to calling this method if overwriting is not desired. +- * +- * @param {string} keyId access key for the cache +- * @param {FunctionKeyPair} keys keys to cache +- */ +- cacheKeys(keyId, keys) { +- const [provingKey, verifyingKey] = keys; +- this.cache.set(keyId, [provingKey.toBytes(), verifyingKey.toBytes()]); +- } +- /** +- * Determine if a keyId exists in the cache +- * +- * @param {string} keyId keyId of a proving and verifying key pair +- * @returns {boolean} true if the keyId exists in the cache, false otherwise +- */ +- containsKeys(keyId) { +- return this.cache.has(keyId); +- } +- /** +- * Delete a set of keys from the cache +- * +- * @param {string} keyId keyId of a proving and verifying key pair to delete from memory +- * @returns {boolean} true if the keyId exists in the cache and was deleted, false if the key did not exist +- */ +- deleteKeys(keyId) { +- return this.cache.delete(keyId); +- } +- /** +- * Get a set of keys from the cache +- * @param keyId keyId of a proving and verifying key pair +- * +- * @returns {FunctionKeyPair | Error} Proving and verifying keys for the specified program +- */ +- getKeys(keyId) { +- console.debug(`Checking if key exists in cache. KeyId: ${keyId}`); +- if (this.cache.has(keyId)) { +- const [provingKeyBytes, verifyingKeyBytes] = this.cache.get(keyId); +- return [ProvingKey.fromBytes(provingKeyBytes), VerifyingKey.fromBytes(verifyingKeyBytes)]; ++ cache; ++ cacheOption; ++ keyUris; ++ async fetchBytes(url = "/") { ++ try { ++ const response = await get(url); ++ const data = await response.arrayBuffer(); ++ return new Uint8Array(data); ++ } ++ catch (error) { ++ throw new Error("Error fetching data." + error); ++ } ++ } ++ constructor() { ++ this.keyUris = KEY_STORE; ++ this.cache = new Map(); ++ this.cacheOption = false; ++ } ++ /** ++ * Use local memory to store keys ++ * ++ * @param {boolean} useCache whether to store keys in local memory ++ */ ++ useCache(useCache) { ++ this.cacheOption = useCache; ++ } ++ /** ++ * Clear the key cache ++ */ ++ clearCache() { ++ this.cache.clear(); ++ } ++ /** ++ * Cache a set of keys. This will overwrite any existing keys with the same keyId. The user can check if a keyId ++ * exists in the cache using the containsKeys method prior to calling this method if overwriting is not desired. ++ * ++ * @param {string} keyId access key for the cache ++ * @param {FunctionKeyPair} keys keys to cache ++ */ ++ cacheKeys(keyId, keys) { ++ const [provingKey, verifyingKey] = keys; ++ this.cache.set(keyId, [provingKey.toBytes(), verifyingKey.toBytes()]); ++ } ++ /** ++ * Determine if a keyId exists in the cache ++ * ++ * @param {string} keyId keyId of a proving and verifying key pair ++ * @returns {boolean} true if the keyId exists in the cache, false otherwise ++ */ ++ containsKeys(keyId) { ++ return this.cache.has(keyId); ++ } ++ /** ++ * Delete a set of keys from the cache ++ * ++ * @param {string} keyId keyId of a proving and verifying key pair to delete from memory ++ * @returns {boolean} true if the keyId exists in the cache and was deleted, false if the key did not exist ++ */ ++ deleteKeys(keyId) { ++ return this.cache.delete(keyId); ++ } ++ /** ++ * Get a set of keys from the cache ++ * @param keyId keyId of a proving and verifying key pair ++ * ++ * @returns {FunctionKeyPair | Error} Proving and verifying keys for the specified program ++ */ ++ getKeys(keyId) { ++ console.debug(`Checking if key exists in cache. KeyId: ${keyId}`); ++ if (this.cache.has(keyId)) { ++ const [provingKeyBytes, verifyingKeyBytes] = this.cache.get(keyId); ++ return [ProvingKey.fromBytes(provingKeyBytes), VerifyingKey.fromBytes(verifyingKeyBytes)]; ++ } ++ else { ++ return new Error("Key not found in cache."); ++ } ++ } ++ /** ++ * Get arbitrary function keys from a provider ++ * ++ * @param {KeySearchParams} params parameters for the key search in form of: {proverUri: string, verifierUri: string, cacheKey: string} ++ * @returns {Promise} Proving and verifying keys for the specified program ++ * ++ * @example ++ * // Create a new object which implements the KeyProvider interface ++ * const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1"); ++ * const keyProvider = new AleoKeyProvider(); ++ * const recordProvider = new NetworkRecordProvider(account, networkClient); ++ * const AleoProviderParams = new AleoProviderParams("https://testnet3.parameters.aleo.org/transfer_private."); ++ * ++ * // Initialize a program manager with the key provider to automatically fetch keys for value transfers ++ * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, recordProvider); ++ * programManager.transfer(1, "aleo166q6ww6688cug7qxwe7nhctjpymydwzy2h7rscfmatqmfwnjvggqcad0at", "public", 0.5); ++ * ++ * // Keys can also be fetched manually using the key provider ++ * const keySearchParams = { "cacheKey": "myProgram:myFunction" }; ++ * const [transferPrivateProvingKey, transferPrivateVerifyingKey] = await keyProvider.functionKeys(keySearchParams); ++ */ ++ async functionKeys(params) { ++ if (params) { ++ let proverUrl; ++ let verifierUrl; ++ let cacheKey; ++ if ("proverUri" in params && typeof params["proverUri"] == "string") { ++ proverUrl = params["proverUri"]; ++ } ++ if ("verifierUri" in params && typeof params["verifierUri"] == "string") { ++ verifierUrl = params["verifierUri"]; ++ } ++ if ("cacheKey" in params && typeof params["cacheKey"] == "string") { ++ cacheKey = params["cacheKey"]; ++ } ++ if (proverUrl && verifierUrl) { ++ return await this.fetchKeys(proverUrl, verifierUrl, cacheKey); ++ } ++ if (cacheKey) { ++ return this.getKeys(cacheKey); ++ } ++ } ++ throw Error("Invalid parameters provided, must provide either a cacheKey and/or a proverUrl and a verifierUrl"); ++ } ++ /** ++ * Returns the proving and verifying keys for a specified program from a specified url. ++ * ++ * @param {string} verifierUrl Url of the proving key ++ * @param {string} proverUrl Url the verifying key ++ * @param {string} cacheKey Key to store the keys in the cache ++ * ++ * @returns {Promise} Proving and verifying keys for the specified program ++ * ++ * @example ++ * // Create a new AleoKeyProvider object ++ * const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1"); ++ * const keyProvider = new AleoKeyProvider(); ++ * const recordProvider = new NetworkRecordProvider(account, networkClient); ++ * ++ * // Initialize a program manager with the key provider to automatically fetch keys for value transfers ++ * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); ++ * programManager.transfer(1, "aleo166q6ww6688cug7qxwe7nhctjpymydwzy2h7rscfmatqmfwnjvggqcad0at", "public", 0.5); ++ * ++ * // Keys can also be fetched manually ++ * const [transferPrivateProvingKey, transferPrivateVerifyingKey] = await keyProvider.fetchKeys("https://testnet3.parameters.aleo.org/transfer_private.prover.2a9a6f2", "https://testnet3.parameters.aleo.org/transfer_private.verifier.3a59762"); ++ */ ++ async fetchKeys(proverUrl, verifierUrl, cacheKey) { ++ try { ++ // If cache is enabled, check if the keys have already been fetched and return them if they have ++ if (this.cacheOption) { ++ if (!cacheKey) { ++ cacheKey = proverUrl; ++ } ++ const value = this.cache.get(cacheKey); ++ if (typeof value !== "undefined") { ++ return [ProvingKey.fromBytes(value[0]), VerifyingKey.fromBytes(value[1])]; + } + else { +- return new Error("Key not found in cache."); +- } +- } +- /** +- * Get arbitrary function keys from a provider +- * +- * @param {KeySearchParams} params parameters for the key search in form of: {proverUri: string, verifierUri: string, cacheKey: string} +- * @returns {Promise} Proving and verifying keys for the specified program +- * +- * @example +- * // Create a new object which implements the KeyProvider interface +- * const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1"); +- * const keyProvider = new AleoKeyProvider(); +- * const recordProvider = new NetworkRecordProvider(account, networkClient); +- * const AleoProviderParams = new AleoProviderParams("https://testnet3.parameters.aleo.org/transfer_private."); +- * +- * // Initialize a program manager with the key provider to automatically fetch keys for value transfers +- * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, recordProvider); +- * programManager.transfer(1, "aleo166q6ww6688cug7qxwe7nhctjpymydwzy2h7rscfmatqmfwnjvggqcad0at", "public", 0.5); +- * +- * // Keys can also be fetched manually using the key provider +- * const keySearchParams = { "cacheKey": "myProgram:myFunction" }; +- * const [transferPrivateProvingKey, transferPrivateVerifyingKey] = await keyProvider.functionKeys(keySearchParams); +- */ +- async functionKeys(params) { +- if (params) { +- let proverUrl; +- let verifierUrl; +- let cacheKey; +- if ("proverUri" in params && typeof params["proverUri"] == "string") { +- proverUrl = params["proverUri"]; +- } +- if ("verifierUri" in params && typeof params["verifierUri"] == "string") { +- verifierUrl = params["verifierUri"]; +- } +- if ("cacheKey" in params && typeof params["cacheKey"] == "string") { +- cacheKey = params["cacheKey"]; +- } +- if (proverUrl && verifierUrl) { +- return await this.fetchKeys(proverUrl, verifierUrl, cacheKey); +- } +- if (cacheKey) { +- return this.getKeys(cacheKey); +- } +- } +- throw Error("Invalid parameters provided, must provide either a cacheKey and/or a proverUrl and a verifierUrl"); +- } +- /** +- * Returns the proving and verifying keys for a specified program from a specified url. +- * +- * @param {string} verifierUrl Url of the proving key +- * @param {string} proverUrl Url the verifying key +- * @param {string} cacheKey Key to store the keys in the cache +- * +- * @returns {Promise} Proving and verifying keys for the specified program +- * +- * @example +- * // Create a new AleoKeyProvider object +- * const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1"); +- * const keyProvider = new AleoKeyProvider(); +- * const recordProvider = new NetworkRecordProvider(account, networkClient); +- * +- * // Initialize a program manager with the key provider to automatically fetch keys for value transfers +- * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); +- * programManager.transfer(1, "aleo166q6ww6688cug7qxwe7nhctjpymydwzy2h7rscfmatqmfwnjvggqcad0at", "public", 0.5); +- * +- * // Keys can also be fetched manually +- * const [transferPrivateProvingKey, transferPrivateVerifyingKey] = await keyProvider.fetchKeys("https://testnet3.parameters.aleo.org/transfer_private.prover.2a9a6f2", "https://testnet3.parameters.aleo.org/transfer_private.verifier.3a59762"); +- */ +- async fetchKeys(proverUrl, verifierUrl, cacheKey) { ++ console.debug("Fetching proving keys from url " + proverUrl); ++ const provingKey = ProvingKey.fromBytes(await this.fetchBytes(proverUrl)); ++ console.debug("Fetching verifying keys " + verifierUrl); ++ const verifyingKey = (await this.getVerifyingKey(verifierUrl)); ++ this.cache.set(cacheKey, [provingKey.toBytes(), verifyingKey.toBytes()]); ++ return [provingKey, verifyingKey]; ++ } ++ } ++ else { ++ // If cache is disabled, fetch the keys and return them ++ const provingKey = ProvingKey.fromBytes(await this.fetchBytes(proverUrl)); ++ const verifyingKey = (await this.getVerifyingKey(verifierUrl)); ++ return [provingKey, verifyingKey]; ++ } ++ } ++ catch (error) { ++ throw new Error(`Error: ${error} fetching fee proving and verifying keys from ${proverUrl} and ${verifierUrl}.`); ++ } ++ } ++ bondPublicKeys() { ++ return this.fetchKeys(CREDITS_PROGRAM_KEYS.bond_public.prover, CREDITS_PROGRAM_KEYS.bond_public.verifier, CREDITS_PROGRAM_KEYS.bond_public.locator); ++ } ++ claimUnbondPublicKeys() { ++ return this.fetchKeys(CREDITS_PROGRAM_KEYS.claim_unbond_public.prover, CREDITS_PROGRAM_KEYS.claim_unbond_public.verifier, CREDITS_PROGRAM_KEYS.claim_unbond_public.locator); ++ } ++ /** ++ * Returns the proving and verifying keys for the transfer functions in the credits.aleo program ++ * @param {string} visibility Visibility of the transfer function ++ * @returns {Promise} Proving and verifying keys for the transfer functions ++ * ++ * @example ++ * // Create a new AleoKeyProvider ++ * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); ++ * const keyProvider = new AleoKeyProvider(); ++ * const recordProvider = new NetworkRecordProvider(account, networkClient); ++ * ++ * // Initialize a program manager with the key provider to automatically fetch keys for value transfers ++ * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); ++ * programManager.transfer(1, "aleo166q6ww6688cug7qxwe7nhctjpymydwzy2h7rscfmatqmfwnjvggqcad0at", "public", 0.5); ++ * ++ * // Keys can also be fetched manually ++ * const [transferPublicProvingKey, transferPublicVerifyingKey] = await keyProvider.transferKeys("public"); ++ */ ++ async transferKeys(visibility) { ++ if (PRIVATE_TRANSFER.has(visibility)) { ++ return await this.fetchKeys(CREDITS_PROGRAM_KEYS.transfer_private.prover, CREDITS_PROGRAM_KEYS.transfer_private.verifier, CREDITS_PROGRAM_KEYS.transfer_private.locator); ++ } ++ else if (PRIVATE_TO_PUBLIC_TRANSFER.has(visibility)) { ++ return await this.fetchKeys(CREDITS_PROGRAM_KEYS.transfer_private_to_public.prover, CREDITS_PROGRAM_KEYS.transfer_private_to_public.verifier, CREDITS_PROGRAM_KEYS.transfer_private_to_public.locator); ++ } ++ else if (PUBLIC_TRANSFER.has(visibility)) { ++ return await this.fetchKeys(CREDITS_PROGRAM_KEYS.transfer_public.prover, CREDITS_PROGRAM_KEYS.transfer_public.verifier, CREDITS_PROGRAM_KEYS.transfer_public.locator); ++ } ++ else if (PUBLIC_TO_PRIVATE_TRANSFER.has(visibility)) { ++ return await this.fetchKeys(CREDITS_PROGRAM_KEYS.transfer_public_to_private.prover, CREDITS_PROGRAM_KEYS.transfer_public_to_private.verifier, CREDITS_PROGRAM_KEYS.transfer_public_to_private.locator); ++ } ++ else { ++ throw new Error("Invalid visibility type"); ++ } ++ } ++ /** ++ * Returns the proving and verifying keys for the join function in the credits.aleo program ++ * ++ * @returns {Promise} Proving and verifying keys for the join function ++ */ ++ async joinKeys() { ++ return await this.fetchKeys(CREDITS_PROGRAM_KEYS.join.prover, CREDITS_PROGRAM_KEYS.join.verifier, CREDITS_PROGRAM_KEYS.join.locator); ++ } ++ /** ++ * Returns the proving and verifying keys for the split function in the credits.aleo program ++ * ++ * @returns {Promise} Proving and verifying keys for the split function ++ * */ ++ async splitKeys() { ++ return await this.fetchKeys(CREDITS_PROGRAM_KEYS.split.prover, CREDITS_PROGRAM_KEYS.split.verifier, CREDITS_PROGRAM_KEYS.split.locator); ++ } ++ /** ++ * Returns the proving and verifying keys for the fee_private function in the credits.aleo program ++ * ++ * @returns {Promise} Proving and verifying keys for the fee function ++ */ ++ async feePrivateKeys() { ++ return await this.fetchKeys(CREDITS_PROGRAM_KEYS.fee_private.prover, CREDITS_PROGRAM_KEYS.fee_private.verifier, CREDITS_PROGRAM_KEYS.fee_private.locator); ++ } ++ /** ++ * Returns the proving and verifying keys for the fee_public function in the credits.aleo program ++ * ++ * @returns {Promise} Proving and verifying keys for the fee function ++ */ ++ async feePublicKeys() { ++ return await this.fetchKeys(CREDITS_PROGRAM_KEYS.fee_public.prover, CREDITS_PROGRAM_KEYS.fee_public.verifier, CREDITS_PROGRAM_KEYS.fee_public.locator); ++ } ++ /** ++ * Gets a verifying key. If the verifying key is for a credits.aleo function, get it from the wasm cache otherwise ++ * ++ * @returns {Promise} Verifying key for the function ++ */ ++ // attempt to fetch it from the network ++ async getVerifyingKey(verifierUri) { ++ switch (verifierUri) { ++ case CREDITS_PROGRAM_KEYS.bond_public.verifier: ++ return CREDITS_PROGRAM_KEYS.bond_public.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.claim_unbond_public.verifier: ++ return CREDITS_PROGRAM_KEYS.claim_unbond_public.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.fee_private.verifier: ++ return CREDITS_PROGRAM_KEYS.fee_private.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.fee_public.verifier: ++ return CREDITS_PROGRAM_KEYS.fee_public.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.inclusion.verifier: ++ return CREDITS_PROGRAM_KEYS.inclusion.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.join.verifier: ++ return CREDITS_PROGRAM_KEYS.join.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.set_validator_state.verifier: ++ return CREDITS_PROGRAM_KEYS.set_validator_state.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.split.verifier: ++ return CREDITS_PROGRAM_KEYS.split.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.transfer_private.verifier: ++ return CREDITS_PROGRAM_KEYS.transfer_private.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.transfer_private_to_public.verifier: ++ return CREDITS_PROGRAM_KEYS.transfer_private_to_public.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.transfer_public.verifier: ++ return CREDITS_PROGRAM_KEYS.transfer_public.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.transfer_public_to_private.verifier: ++ return CREDITS_PROGRAM_KEYS.transfer_public_to_private.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.verifier: ++ return CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.verifyingKey(); ++ case CREDITS_PROGRAM_KEYS.unbond_public.verifier: ++ return CREDITS_PROGRAM_KEYS.unbond_public.verifyingKey(); ++ default: + try { +- // If cache is enabled, check if the keys have already been fetched and return them if they have +- if (this.cacheOption) { +- if (!cacheKey) { +- cacheKey = proverUrl; +- } +- const value = this.cache.get(cacheKey); +- if (typeof value !== "undefined") { +- return [ProvingKey.fromBytes(value[0]), VerifyingKey.fromBytes(value[1])]; +- } +- else { +- console.debug("Fetching proving keys from url " + proverUrl); +- const provingKey = ProvingKey.fromBytes(await this.fetchBytes(proverUrl)); +- console.debug("Fetching verifying keys " + verifierUrl); +- const verifyingKey = (await this.getVerifyingKey(verifierUrl)); +- this.cache.set(cacheKey, [provingKey.toBytes(), verifyingKey.toBytes()]); +- return [provingKey, verifyingKey]; +- } +- } +- else { +- // If cache is disabled, fetch the keys and return them +- const provingKey = ProvingKey.fromBytes(await this.fetchBytes(proverUrl)); +- const verifyingKey = (await this.getVerifyingKey(verifierUrl)); +- return [provingKey, verifyingKey]; +- } +- } +- catch (error) { +- throw new Error(`Error: ${error} fetching fee proving and verifying keys from ${proverUrl} and ${verifierUrl}.`); +- } +- } +- bondPublicKeys() { +- return this.fetchKeys(CREDITS_PROGRAM_KEYS.bond_public.prover, CREDITS_PROGRAM_KEYS.bond_public.verifier, CREDITS_PROGRAM_KEYS.bond_public.locator); +- } +- claimUnbondPublicKeys() { +- return this.fetchKeys(CREDITS_PROGRAM_KEYS.claim_unbond_public.prover, CREDITS_PROGRAM_KEYS.claim_unbond_public.verifier, CREDITS_PROGRAM_KEYS.claim_unbond_public.locator); +- } +- /** +- * Returns the proving and verifying keys for the transfer functions in the credits.aleo program +- * @param {string} visibility Visibility of the transfer function +- * @returns {Promise} Proving and verifying keys for the transfer functions +- * +- * @example +- * // Create a new AleoKeyProvider +- * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); +- * const keyProvider = new AleoKeyProvider(); +- * const recordProvider = new NetworkRecordProvider(account, networkClient); +- * +- * // Initialize a program manager with the key provider to automatically fetch keys for value transfers +- * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); +- * programManager.transfer(1, "aleo166q6ww6688cug7qxwe7nhctjpymydwzy2h7rscfmatqmfwnjvggqcad0at", "public", 0.5); +- * +- * // Keys can also be fetched manually +- * const [transferPublicProvingKey, transferPublicVerifyingKey] = await keyProvider.transferKeys("public"); +- */ +- async transferKeys(visibility) { +- if (PRIVATE_TRANSFER.has(visibility)) { +- return await this.fetchKeys(CREDITS_PROGRAM_KEYS.transfer_private.prover, CREDITS_PROGRAM_KEYS.transfer_private.verifier, CREDITS_PROGRAM_KEYS.transfer_private.locator); +- } +- else if (PRIVATE_TO_PUBLIC_TRANSFER.has(visibility)) { +- return await this.fetchKeys(CREDITS_PROGRAM_KEYS.transfer_private_to_public.prover, CREDITS_PROGRAM_KEYS.transfer_private_to_public.verifier, CREDITS_PROGRAM_KEYS.transfer_private_to_public.locator); +- } +- else if (PUBLIC_TRANSFER.has(visibility)) { +- return await this.fetchKeys(CREDITS_PROGRAM_KEYS.transfer_public.prover, CREDITS_PROGRAM_KEYS.transfer_public.verifier, CREDITS_PROGRAM_KEYS.transfer_public.locator); +- } +- else if (PUBLIC_TO_PRIVATE_TRANSFER.has(visibility)) { +- return await this.fetchKeys(CREDITS_PROGRAM_KEYS.transfer_public_to_private.prover, CREDITS_PROGRAM_KEYS.transfer_public_to_private.verifier, CREDITS_PROGRAM_KEYS.transfer_public_to_private.locator); +- } +- else { +- throw new Error("Invalid visibility type"); +- } +- } +- /** +- * Returns the proving and verifying keys for the join function in the credits.aleo program +- * +- * @returns {Promise} Proving and verifying keys for the join function +- */ +- async joinKeys() { +- return await this.fetchKeys(CREDITS_PROGRAM_KEYS.join.prover, CREDITS_PROGRAM_KEYS.join.verifier, CREDITS_PROGRAM_KEYS.join.locator); +- } +- /** +- * Returns the proving and verifying keys for the split function in the credits.aleo program +- * +- * @returns {Promise} Proving and verifying keys for the split function +- * */ +- async splitKeys() { +- return await this.fetchKeys(CREDITS_PROGRAM_KEYS.split.prover, CREDITS_PROGRAM_KEYS.split.verifier, CREDITS_PROGRAM_KEYS.split.locator); +- } +- /** +- * Returns the proving and verifying keys for the fee_private function in the credits.aleo program +- * +- * @returns {Promise} Proving and verifying keys for the fee function +- */ +- async feePrivateKeys() { +- return await this.fetchKeys(CREDITS_PROGRAM_KEYS.fee_private.prover, CREDITS_PROGRAM_KEYS.fee_private.verifier, CREDITS_PROGRAM_KEYS.fee_private.locator); +- } +- /** +- * Returns the proving and verifying keys for the fee_public function in the credits.aleo program +- * +- * @returns {Promise} Proving and verifying keys for the fee function +- */ +- async feePublicKeys() { +- return await this.fetchKeys(CREDITS_PROGRAM_KEYS.fee_public.prover, CREDITS_PROGRAM_KEYS.fee_public.verifier, CREDITS_PROGRAM_KEYS.fee_public.locator); +- } +- /** +- * Gets a verifying key. If the verifying key is for a credits.aleo function, get it from the wasm cache otherwise +- * +- * @returns {Promise} Verifying key for the function +- */ +- // attempt to fetch it from the network +- async getVerifyingKey(verifierUri) { +- switch (verifierUri) { +- case CREDITS_PROGRAM_KEYS.bond_public.verifier: +- return CREDITS_PROGRAM_KEYS.bond_public.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.claim_unbond_public.verifier: +- return CREDITS_PROGRAM_KEYS.claim_unbond_public.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.fee_private.verifier: +- return CREDITS_PROGRAM_KEYS.fee_private.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.fee_public.verifier: +- return CREDITS_PROGRAM_KEYS.fee_public.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.inclusion.verifier: +- return CREDITS_PROGRAM_KEYS.inclusion.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.join.verifier: +- return CREDITS_PROGRAM_KEYS.join.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.set_validator_state.verifier: +- return CREDITS_PROGRAM_KEYS.set_validator_state.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.split.verifier: +- return CREDITS_PROGRAM_KEYS.split.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.transfer_private.verifier: +- return CREDITS_PROGRAM_KEYS.transfer_private.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.transfer_private_to_public.verifier: +- return CREDITS_PROGRAM_KEYS.transfer_private_to_public.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.transfer_public.verifier: +- return CREDITS_PROGRAM_KEYS.transfer_public.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.transfer_public_to_private.verifier: +- return CREDITS_PROGRAM_KEYS.transfer_public_to_private.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.verifier: +- return CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.verifyingKey(); +- case CREDITS_PROGRAM_KEYS.unbond_public.verifier: +- return CREDITS_PROGRAM_KEYS.unbond_public.verifyingKey(); +- default: +- try { +- /// Try to fetch the verifying key from the network as a string +- const response = await get(verifierUri); +- const text = await response.text(); +- return VerifyingKey.fromString(text); +- } +- catch (e) { +- /// If that fails, try to fetch the verifying key from the network as bytes +- try { +- return VerifyingKey.fromBytes(await this.fetchBytes(verifierUri)); +- } +- catch (inner) { +- return new Error("Invalid verifying key. Error: " + inner); +- } +- } ++ /// Try to fetch the verifying key from the network as a string ++ const response = await get(verifierUri); ++ const text = await response.text(); ++ return VerifyingKey.fromString(text); + } +- } +- unBondPublicKeys() { +- return this.fetchKeys(CREDITS_PROGRAM_KEYS.unbond_public.prover, CREDITS_PROGRAM_KEYS.unbond_public.verifier, CREDITS_PROGRAM_KEYS.unbond_public.locator); +- } ++ catch (e) { ++ /// If that fails, try to fetch the verifying key from the network as bytes ++ try { ++ return VerifyingKey.fromBytes(await this.fetchBytes(verifierUri)); ++ } ++ catch (inner) { ++ return new Error("Invalid verifying key. Error: " + inner); ++ } ++ } ++ } ++ } ++ unBondPublicKeys() { ++ return this.fetchKeys(CREDITS_PROGRAM_KEYS.unbond_public.prover, CREDITS_PROGRAM_KEYS.unbond_public.verifier, CREDITS_PROGRAM_KEYS.unbond_public.locator); ++ } + } + + /** +@@ -1168,104 +1177,104 @@ class AleoKeyProvider { + * unbondDelegatorAsValidatorSearchParams = OfflineSearchParams.unbondDelegatorAsValidatorKeyParams(); + */ + class OfflineSearchParams { +- cacheKey; +- verifyCreditsKeys; +- /** +- * Create a new OfflineSearchParams instance. +- * +- * @param {string} cacheKey - Key used to store the local function proving & verifying keys. This should be stored +- * under the naming convention "programName/functionName" (i.e. "myprogram.aleo/myfunction") +- * @param {boolean} verifyCreditsKeys - Whether to verify the keys against the credits.aleo program, +- * defaults to false, but should be set to true if using keys from the credits.aleo program +- */ +- constructor(cacheKey, verifyCreditsKeys = false) { +- this.cacheKey = cacheKey; +- this.verifyCreditsKeys = verifyCreditsKeys; +- } +- /** +- * Create a new OfflineSearchParams instance for the bond_public function of the credits.aleo program. +- */ +- static bondPublicKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.bond_public.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the claim_unbond_public function of the +- */ +- static claimUnbondPublicKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.claim_unbond_public.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the fee_private function of the credits.aleo program. +- */ +- static feePrivateKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.fee_private.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the fee_public function of the credits.aleo program. +- */ +- static feePublicKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.fee_public.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the inclusion prover function. +- */ +- static inclusionKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.inclusion.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the join function of the credits.aleo program. +- */ +- static joinKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.join.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the set_validator_state function of the credits.aleo program. +- */ +- static setValidatorStateKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.set_validator_state.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the split function of the credits.aleo program. +- */ +- static splitKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.split.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the transfer_private function of the credits.aleo program. +- */ +- static transferPrivateKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.transfer_private.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the transfer_private_to_public function of the credits.aleo program. +- */ +- static transferPrivateToPublicKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.transfer_private_to_public.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the transfer_public function of the credits.aleo program. +- */ +- static transferPublicKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.transfer_public.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the transfer_public_to_private function of the credits.aleo program. +- */ +- static transferPublicToPrivateKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.transfer_public_to_private.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the unbond_delegator_as_validator function of the credits.aleo program. +- */ +- static unbondDelegatorAsValidatorKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.locator, true); +- } +- /** +- * Create a new OfflineSearchParams instance for the unbond_delegator function of the credits.aleo program. +- */ +- static unbondPublicKeyParams() { +- return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.unbond_public.locator, true); +- } ++ cacheKey; ++ verifyCreditsKeys; ++ /** ++ * Create a new OfflineSearchParams instance. ++ * ++ * @param {string} cacheKey - Key used to store the local function proving & verifying keys. This should be stored ++ * under the naming convention "programName/functionName" (i.e. "myprogram.aleo/myfunction") ++ * @param {boolean} verifyCreditsKeys - Whether to verify the keys against the credits.aleo program, ++ * defaults to false, but should be set to true if using keys from the credits.aleo program ++ */ ++ constructor(cacheKey, verifyCreditsKeys = false) { ++ this.cacheKey = cacheKey; ++ this.verifyCreditsKeys = verifyCreditsKeys; ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the bond_public function of the credits.aleo program. ++ */ ++ static bondPublicKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.bond_public.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the claim_unbond_public function of the ++ */ ++ static claimUnbondPublicKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.claim_unbond_public.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the fee_private function of the credits.aleo program. ++ */ ++ static feePrivateKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.fee_private.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the fee_public function of the credits.aleo program. ++ */ ++ static feePublicKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.fee_public.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the inclusion prover function. ++ */ ++ static inclusionKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.inclusion.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the join function of the credits.aleo program. ++ */ ++ static joinKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.join.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the set_validator_state function of the credits.aleo program. ++ */ ++ static setValidatorStateKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.set_validator_state.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the split function of the credits.aleo program. ++ */ ++ static splitKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.split.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the transfer_private function of the credits.aleo program. ++ */ ++ static transferPrivateKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.transfer_private.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the transfer_private_to_public function of the credits.aleo program. ++ */ ++ static transferPrivateToPublicKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.transfer_private_to_public.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the transfer_public function of the credits.aleo program. ++ */ ++ static transferPublicKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.transfer_public.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the transfer_public_to_private function of the credits.aleo program. ++ */ ++ static transferPublicToPrivateKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.transfer_public_to_private.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the unbond_delegator_as_validator function of the credits.aleo program. ++ */ ++ static unbondDelegatorAsValidatorKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.locator, true); ++ } ++ /** ++ * Create a new OfflineSearchParams instance for the unbond_delegator function of the credits.aleo program. ++ */ ++ static unbondPublicKeyParams() { ++ return new OfflineSearchParams(CREDITS_PROGRAM_KEYS.unbond_public.locator, true); ++ } + } + /** + * A key provider meant for building transactions offline on devices such as hardware wallets. This key provider is not +@@ -1319,402 +1328,402 @@ class OfflineSearchParams { + * const txId = await networkClient.broadcastTransaction(offlineExecuteTx); + */ + class OfflineKeyProvider { +- cache; +- constructor() { +- this.cache = new Map(); +- } +- /** +- * Get bond_public function keys from the credits.aleo program. The keys must be cached prior to calling this +- * method for it to work. +- * +- * @returns {Promise} Proving and verifying keys for the bond_public function +- */ +- bondPublicKeys() { +- return this.functionKeys(OfflineSearchParams.bondPublicKeyParams()); +- } +- ; +- /** +- * Cache a set of keys. This will overwrite any existing keys with the same keyId. The user can check if a keyId +- * exists in the cache using the containsKeys method prior to calling this method if overwriting is not desired. +- * +- * @param {string} keyId access key for the cache +- * @param {FunctionKeyPair} keys keys to cache +- */ +- cacheKeys(keyId, keys) { +- const [provingKey, verifyingKey] = keys; +- this.cache.set(keyId, [provingKey.toBytes(), verifyingKey.toBytes()]); +- } +- ; +- /** +- * Get unbond_public function keys from the credits.aleo program. The keys must be cached prior to calling this +- * method for it to work. +- * +- * @returns {Promise} Proving and verifying keys for the unbond_public function +- */ +- claimUnbondPublicKeys() { +- return this.functionKeys(OfflineSearchParams.claimUnbondPublicKeyParams()); +- } +- ; +- /** +- * Get arbitrary function key from the offline key provider cache. +- * +- * @param {KeySearchParams | undefined} params - Optional search parameters for the key provider +- * @returns {Promise} Proving and verifying keys for the specified program +- * +- * @example +- * /// First cache the keys from local offline resources +- * const offlineKeyProvider = new OfflineKeyProvider(); +- * const myFunctionVerifyingKey = VerifyingKey.fromString("verifier..."); +- * const myFunctionProvingKeyBytes = await readBinaryFile('./resources/myfunction.prover'); +- * const myFunctionProvingKey = ProvingKey.fromBytes(myFunctionProvingKeyBytes); +- * +- * /// Cache the keys for future use with a memorable locator +- * offlineKeyProvider.cacheKeys("myprogram.aleo/myfunction", [myFunctionProvingKey, myFunctionVerifyingKey]); +- * +- * /// When they're needed, retrieve the keys from the cache +- * +- * /// First create a search parameter object with the same locator used to cache the keys +- * const keyParams = new OfflineSearchParams("myprogram.aleo/myfunction"); +- * +- * /// Then retrieve the keys +- * const [myFunctionProver, myFunctionVerifier] = await offlineKeyProvider.functionKeys(keyParams); +- */ +- functionKeys(params) { +- return new Promise((resolve, reject) => { +- if (params === undefined) { +- reject(new Error("No search parameters provided, cannot retrieve keys")); +- } +- else { +- const keyId = params.cacheKey; +- const verifyCreditsKeys = params.verifyCreditsKeys; +- if (this.cache.has(keyId)) { +- const [provingKeyBytes, verifyingKeyBytes] = this.cache.get(keyId); +- const provingKey = ProvingKey.fromBytes(provingKeyBytes); +- const verifyingKey = VerifyingKey.fromBytes(verifyingKeyBytes); +- if (verifyCreditsKeys) { +- const keysMatchExpected = this.verifyCreditsKeys(keyId, provingKey, verifyingKey); +- if (!keysMatchExpected) { +- reject(new Error(`Cached keys do not match expected keys for ${keyId}`)); +- } +- } +- resolve([provingKey, verifyingKey]); +- } +- else { +- reject(new Error("Keys not found in cache for " + keyId)); +- } ++ cache; ++ constructor() { ++ this.cache = new Map(); ++ } ++ /** ++ * Get bond_public function keys from the credits.aleo program. The keys must be cached prior to calling this ++ * method for it to work. ++ * ++ * @returns {Promise} Proving and verifying keys for the bond_public function ++ */ ++ bondPublicKeys() { ++ return this.functionKeys(OfflineSearchParams.bondPublicKeyParams()); ++ } ++ ; ++ /** ++ * Cache a set of keys. This will overwrite any existing keys with the same keyId. The user can check if a keyId ++ * exists in the cache using the containsKeys method prior to calling this method if overwriting is not desired. ++ * ++ * @param {string} keyId access key for the cache ++ * @param {FunctionKeyPair} keys keys to cache ++ */ ++ cacheKeys(keyId, keys) { ++ const [provingKey, verifyingKey] = keys; ++ this.cache.set(keyId, [provingKey.toBytes(), verifyingKey.toBytes()]); ++ } ++ ; ++ /** ++ * Get unbond_public function keys from the credits.aleo program. The keys must be cached prior to calling this ++ * method for it to work. ++ * ++ * @returns {Promise} Proving and verifying keys for the unbond_public function ++ */ ++ claimUnbondPublicKeys() { ++ return this.functionKeys(OfflineSearchParams.claimUnbondPublicKeyParams()); ++ } ++ ; ++ /** ++ * Get arbitrary function key from the offline key provider cache. ++ * ++ * @param {KeySearchParams | undefined} params - Optional search parameters for the key provider ++ * @returns {Promise} Proving and verifying keys for the specified program ++ * ++ * @example ++ * /// First cache the keys from local offline resources ++ * const offlineKeyProvider = new OfflineKeyProvider(); ++ * const myFunctionVerifyingKey = VerifyingKey.fromString("verifier..."); ++ * const myFunctionProvingKeyBytes = await readBinaryFile('./resources/myfunction.prover'); ++ * const myFunctionProvingKey = ProvingKey.fromBytes(myFunctionProvingKeyBytes); ++ * ++ * /// Cache the keys for future use with a memorable locator ++ * offlineKeyProvider.cacheKeys("myprogram.aleo/myfunction", [myFunctionProvingKey, myFunctionVerifyingKey]); ++ * ++ * /// When they're needed, retrieve the keys from the cache ++ * ++ * /// First create a search parameter object with the same locator used to cache the keys ++ * const keyParams = new OfflineSearchParams("myprogram.aleo/myfunction"); ++ * ++ * /// Then retrieve the keys ++ * const [myFunctionProver, myFunctionVerifier] = await offlineKeyProvider.functionKeys(keyParams); ++ */ ++ functionKeys(params) { ++ return new Promise((resolve, reject) => { ++ if (params === undefined) { ++ reject(new Error("No search parameters provided, cannot retrieve keys")); ++ } ++ else { ++ const keyId = params.cacheKey; ++ const verifyCreditsKeys = params.verifyCreditsKeys; ++ if (this.cache.has(keyId)) { ++ const [provingKeyBytes, verifyingKeyBytes] = this.cache.get(keyId); ++ const provingKey = ProvingKey.fromBytes(provingKeyBytes); ++ const verifyingKey = VerifyingKey.fromBytes(verifyingKeyBytes); ++ if (verifyCreditsKeys) { ++ const keysMatchExpected = this.verifyCreditsKeys(keyId, provingKey, verifyingKey); ++ if (!keysMatchExpected) { ++ reject(new Error(`Cached keys do not match expected keys for ${keyId}`)); + } +- }); +- } +- ; +- /** +- * Determines if the keys for a given credits function match the expected keys. +- * +- * @returns {boolean} Whether the keys match the expected keys +- */ +- verifyCreditsKeys(locator, provingKey, verifyingKey) { +- switch (locator) { +- case CREDITS_PROGRAM_KEYS.bond_public.locator: +- return provingKey.isBondPublicProver() && verifyingKey.isBondPublicVerifier(); +- case CREDITS_PROGRAM_KEYS.claim_unbond_public.locator: +- return provingKey.isClaimUnbondPublicProver() && verifyingKey.isClaimUnbondPublicVerifier(); +- case CREDITS_PROGRAM_KEYS.fee_private.locator: +- return provingKey.isFeePrivateProver() && verifyingKey.isFeePrivateVerifier(); +- case CREDITS_PROGRAM_KEYS.fee_public.locator: +- return provingKey.isFeePublicProver() && verifyingKey.isFeePublicVerifier(); +- case CREDITS_PROGRAM_KEYS.inclusion.locator: +- return provingKey.isInclusionProver() && verifyingKey.isInclusionVerifier(); +- case CREDITS_PROGRAM_KEYS.join.locator: +- return provingKey.isJoinProver() && verifyingKey.isJoinVerifier(); +- case CREDITS_PROGRAM_KEYS.set_validator_state.locator: +- return provingKey.isSetValidatorStateProver() && verifyingKey.isSetValidatorStateVerifier(); +- case CREDITS_PROGRAM_KEYS.split.locator: +- return provingKey.isSplitProver() && verifyingKey.isSplitVerifier(); +- case CREDITS_PROGRAM_KEYS.transfer_private.locator: +- return provingKey.isTransferPrivateProver() && verifyingKey.isTransferPrivateVerifier(); +- case CREDITS_PROGRAM_KEYS.transfer_private_to_public.locator: +- return provingKey.isTransferPrivateToPublicProver() && verifyingKey.isTransferPrivateToPublicVerifier(); +- case CREDITS_PROGRAM_KEYS.transfer_public.locator: +- return provingKey.isTransferPublicProver() && verifyingKey.isTransferPublicVerifier(); +- case CREDITS_PROGRAM_KEYS.transfer_public_to_private.locator: +- return provingKey.isTransferPublicToPrivateProver() && verifyingKey.isTransferPublicToPrivateVerifier(); +- case CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.locator: +- return provingKey.isUnbondDelegatorAsValidatorProver() && verifyingKey.isUnbondDelegatorAsValidatorVerifier(); +- case CREDITS_PROGRAM_KEYS.unbond_public.locator: +- return provingKey.isUnbondPublicProver() && verifyingKey.isUnbondPublicVerifier(); +- default: +- return false; +- } +- } +- /** +- * Get fee_private function keys from the credits.aleo program. The keys must be cached prior to calling this +- * method for it to work. +- * +- * @returns {Promise} Proving and verifying keys for the join function +- */ +- feePrivateKeys() { +- return this.functionKeys(OfflineSearchParams.feePrivateKeyParams()); +- } +- ; +- /** +- * Get fee_public function keys from the credits.aleo program. The keys must be cached prior to calling this +- * method for it to work. +- * +- * @returns {Promise} Proving and verifying keys for the join function +- */ +- feePublicKeys() { +- return this.functionKeys(OfflineSearchParams.feePublicKeyParams()); +- } +- ; +- /** +- * Get join function keys from the credits.aleo program. The keys must be cached prior to calling this +- * method for it to work. +- * +- * @returns {Promise} Proving and verifying keys for the join function +- */ +- joinKeys() { +- return this.functionKeys(OfflineSearchParams.joinKeyParams()); +- } +- ; +- /** +- * Get split function keys from the credits.aleo program. The keys must be cached prior to calling this +- * method for it to work. +- * +- * @returns {Promise} Proving and verifying keys for the join function +- */ +- splitKeys() { +- return this.functionKeys(OfflineSearchParams.splitKeyParams()); +- } +- ; +- /** +- * Get keys for a variant of the transfer function from the credits.aleo program. +- * +- * +- * @param {string} visibility Visibility of the transfer function (private, public, privateToPublic, publicToPrivate) +- * @returns {Promise} Proving and verifying keys for the specified transfer function +- * +- * @example +- * // Create a new OfflineKeyProvider +- * const offlineKeyProvider = new OfflineKeyProvider(); +- * +- * // Cache the keys for future use with the official locator +- * const transferPublicProvingKeyBytes = await readBinaryFile('./resources/transfer_public.prover.a74565e'); +- * const transferPublicProvingKey = ProvingKey.fromBytes(transferPublicProvingKeyBytes); +- * +- * // Cache the transfer_public keys for future use with the OfflinKeyProvider's convenience method for +- * // transfer_public (the verifying key will be cached automatically) +- * offlineKeyProvider.insertTransferPublicKeys(transferPublicProvingKey); +- * +- * /// When they're needed, retrieve the keys from the cache +- * const [transferPublicProvingKey, transferPublicVerifyingKey] = await keyProvider.transferKeys("public"); +- */ +- transferKeys(visibility) { +- if (PRIVATE_TRANSFER.has(visibility)) { +- return this.functionKeys(OfflineSearchParams.transferPrivateKeyParams()); +- } +- else if (PRIVATE_TO_PUBLIC_TRANSFER.has(visibility)) { +- return this.functionKeys(OfflineSearchParams.transferPrivateToPublicKeyParams()); +- } +- else if (PUBLIC_TRANSFER.has(visibility)) { +- return this.functionKeys(OfflineSearchParams.transferPublicKeyParams()); +- } +- else if (PUBLIC_TO_PRIVATE_TRANSFER.has(visibility)) { +- return this.functionKeys(OfflineSearchParams.transferPublicToPrivateKeyParams()); ++ } ++ resolve([provingKey, verifyingKey]); + } + else { +- throw new Error("Invalid visibility type"); +- } +- } +- ; +- /** +- * Get unbond_public function keys from the credits.aleo program +- * +- * @returns {Promise} Proving and verifying keys for the join function +- */ +- async unBondPublicKeys() { +- return this.functionKeys(OfflineSearchParams.unbondPublicKeyParams()); +- } +- ; +- /** +- * Insert the proving and verifying keys for the bond_public function into the cache. Only the proving key needs +- * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check +- * that the keys match the expected checksum for bond_public before inserting them into the cache. +- * +- * @param provingKey +- */ +- insertBondPublicKeys(provingKey) { +- if (provingKey.isBondPublicProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.bond_public.locator, [provingKey.toBytes(), VerifyingKey.bondPublicVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for bond_public"); +- } +- } +- /** +- * Insert the proving and verifying keys for the claim_unbond_public function into the cache. Only the proving key needs +- * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check +- * that the keys match the expected checksum for claim_unbond_public before inserting them into the cache. +- * +- * @param provingKey +- */ +- insertClaimUnbondPublicKeys(provingKey) { +- if (provingKey.isClaimUnbondPublicProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.claim_unbond_public.locator, [provingKey.toBytes(), VerifyingKey.claimUnbondPublicVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for claim_unbond_public"); +- } +- } +- /** +- * Insert the proving and verifying keys for the fee_private function into the cache. Only the proving key needs +- * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check +- * that the keys match the expected checksum for fee_private before inserting them into the cache. +- * +- * @param provingKey +- */ +- insertFeePrivateKeys(provingKey) { +- if (provingKey.isFeePrivateProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.fee_private.locator, [provingKey.toBytes(), VerifyingKey.feePrivateVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for fee_private"); +- } +- } +- /** +- * Insert the proving and verifying keys for the fee_public function into the cache. Only the proving key needs +- * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check +- * that the keys match the expected checksum for fee_public before inserting them into the cache. +- * +- * @param provingKey +- */ +- insertFeePublicKeys(provingKey) { +- if (provingKey.isFeePublicProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.fee_public.locator, [provingKey.toBytes(), VerifyingKey.feePublicVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for fee_public"); +- } +- } +- /** +- * Insert the proving and verifying keys for the join function into the cache. Only the proving key needs +- * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check +- * that the keys match the expected checksum for join before inserting them into the cache. +- * +- * @param provingKey +- */ +- insertJoinKeys(provingKey) { +- if (provingKey.isJoinProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.join.locator, [provingKey.toBytes(), VerifyingKey.joinVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for join"); +- } +- } +- /** +- * Insert the proving and verifying keys for the set_validator_state function into the cache. Only the proving key needs +- * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check +- * that the keys match the expected checksum for set_validator_state before inserting them into the cache. +- * +- * @param provingKey +- */ +- insertSetValidatorStateKeys(provingKey) { +- if (provingKey.isSetValidatorStateProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.set_validator_state.locator, [provingKey.toBytes(), VerifyingKey.setValidatorStateVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for set_validator_state"); +- } +- } +- /** +- * Insert the proving and verifying keys for the split function into the cache. Only the proving key needs +- * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check +- * that the keys match the expected checksum for split before inserting them into the cache. +- * +- * @param provingKey +- */ +- insertSplitKeys(provingKey) { +- if (provingKey.isSplitProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.split.locator, [provingKey.toBytes(), VerifyingKey.splitVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for split"); +- } +- } +- /** +- * Insert the proving and verifying keys for the transfer_private function into the cache. Only the proving key needs +- * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check +- * that the keys match the expected checksum for transfer_private before inserting them into the cache. +- * +- * @param provingKey +- */ +- insertTransferPrivateKeys(provingKey) { +- if (provingKey.isTransferPrivateProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.transfer_private.locator, [provingKey.toBytes(), VerifyingKey.transferPrivateVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for transfer_private"); +- } +- } +- /** +- * Insert the proving and verifying keys for the transfer_private_to_public function into the cache. Only the proving key needs +- * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check +- * that the keys match the expected checksum for transfer_private_to_public before inserting them into the cache. +- * +- * @param provingKey +- */ +- insertTransferPrivateToPublicKeys(provingKey) { +- if (provingKey.isTransferPrivateToPublicProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.transfer_private_to_public.locator, [provingKey.toBytes(), VerifyingKey.transferPrivateToPublicVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for transfer_private_to_public"); +- } +- } +- /** +- * Insert the proving and verifying keys for the transfer_public function into the cache. Only the proving key needs +- * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check +- * that the keys match the expected checksum for transfer_public before inserting them into the cache. +- * +- * @param provingKey +- */ +- insertTransferPublicKeys(provingKey) { +- if (provingKey.isTransferPublicProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.transfer_public.locator, [provingKey.toBytes(), VerifyingKey.transferPublicVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for transfer_public"); +- } +- } +- /** +- * Insert the proving and verifying keys for the transfer_public_to_private function into the cache. Only the proving key needs +- * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check +- * that the keys match the expected checksum for transfer_public_to_private before inserting them into the cache. +- * +- * @param provingKey +- */ +- insertTransferPublicToPrivateKeys(provingKey) { +- if (provingKey.isTransferPublicToPrivateProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.transfer_public_to_private.locator, [provingKey.toBytes(), VerifyingKey.transferPublicToPrivateVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for transfer_public_to_private"); +- } +- } +- insertUnbondDelegatorAsValidatorKeys(provingKey) { +- if (provingKey.isUnbondDelegatorAsValidatorProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.locator, [provingKey.toBytes(), VerifyingKey.unbondDelegatorAsValidatorVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for unbond_delegator_as_validator"); +- } +- } +- insertUnbondPublicKeys(provingKey) { +- if (provingKey.isUnbondPublicProver()) { +- this.cache.set(CREDITS_PROGRAM_KEYS.unbond_public.locator, [provingKey.toBytes(), VerifyingKey.unbondPublicVerifier().toBytes()]); +- } +- else { +- throw new Error("Attempted to insert invalid proving keys for unbond_public"); +- } +- } ++ reject(new Error("Keys not found in cache for " + keyId)); ++ } ++ } ++ }); ++ } ++ ; ++ /** ++ * Determines if the keys for a given credits function match the expected keys. ++ * ++ * @returns {boolean} Whether the keys match the expected keys ++ */ ++ verifyCreditsKeys(locator, provingKey, verifyingKey) { ++ switch (locator) { ++ case CREDITS_PROGRAM_KEYS.bond_public.locator: ++ return provingKey.isBondPublicProver() && verifyingKey.isBondPublicVerifier(); ++ case CREDITS_PROGRAM_KEYS.claim_unbond_public.locator: ++ return provingKey.isClaimUnbondPublicProver() && verifyingKey.isClaimUnbondPublicVerifier(); ++ case CREDITS_PROGRAM_KEYS.fee_private.locator: ++ return provingKey.isFeePrivateProver() && verifyingKey.isFeePrivateVerifier(); ++ case CREDITS_PROGRAM_KEYS.fee_public.locator: ++ return provingKey.isFeePublicProver() && verifyingKey.isFeePublicVerifier(); ++ case CREDITS_PROGRAM_KEYS.inclusion.locator: ++ return provingKey.isInclusionProver() && verifyingKey.isInclusionVerifier(); ++ case CREDITS_PROGRAM_KEYS.join.locator: ++ return provingKey.isJoinProver() && verifyingKey.isJoinVerifier(); ++ case CREDITS_PROGRAM_KEYS.set_validator_state.locator: ++ return provingKey.isSetValidatorStateProver() && verifyingKey.isSetValidatorStateVerifier(); ++ case CREDITS_PROGRAM_KEYS.split.locator: ++ return provingKey.isSplitProver() && verifyingKey.isSplitVerifier(); ++ case CREDITS_PROGRAM_KEYS.transfer_private.locator: ++ return provingKey.isTransferPrivateProver() && verifyingKey.isTransferPrivateVerifier(); ++ case CREDITS_PROGRAM_KEYS.transfer_private_to_public.locator: ++ return provingKey.isTransferPrivateToPublicProver() && verifyingKey.isTransferPrivateToPublicVerifier(); ++ case CREDITS_PROGRAM_KEYS.transfer_public.locator: ++ return provingKey.isTransferPublicProver() && verifyingKey.isTransferPublicVerifier(); ++ case CREDITS_PROGRAM_KEYS.transfer_public_to_private.locator: ++ return provingKey.isTransferPublicToPrivateProver() && verifyingKey.isTransferPublicToPrivateVerifier(); ++ case CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.locator: ++ return provingKey.isUnbondDelegatorAsValidatorProver() && verifyingKey.isUnbondDelegatorAsValidatorVerifier(); ++ case CREDITS_PROGRAM_KEYS.unbond_public.locator: ++ return provingKey.isUnbondPublicProver() && verifyingKey.isUnbondPublicVerifier(); ++ default: ++ return false; ++ } ++ } ++ /** ++ * Get fee_private function keys from the credits.aleo program. The keys must be cached prior to calling this ++ * method for it to work. ++ * ++ * @returns {Promise} Proving and verifying keys for the join function ++ */ ++ feePrivateKeys() { ++ return this.functionKeys(OfflineSearchParams.feePrivateKeyParams()); ++ } ++ ; ++ /** ++ * Get fee_public function keys from the credits.aleo program. The keys must be cached prior to calling this ++ * method for it to work. ++ * ++ * @returns {Promise} Proving and verifying keys for the join function ++ */ ++ feePublicKeys() { ++ return this.functionKeys(OfflineSearchParams.feePublicKeyParams()); ++ } ++ ; ++ /** ++ * Get join function keys from the credits.aleo program. The keys must be cached prior to calling this ++ * method for it to work. ++ * ++ * @returns {Promise} Proving and verifying keys for the join function ++ */ ++ joinKeys() { ++ return this.functionKeys(OfflineSearchParams.joinKeyParams()); ++ } ++ ; ++ /** ++ * Get split function keys from the credits.aleo program. The keys must be cached prior to calling this ++ * method for it to work. ++ * ++ * @returns {Promise} Proving and verifying keys for the join function ++ */ ++ splitKeys() { ++ return this.functionKeys(OfflineSearchParams.splitKeyParams()); ++ } ++ ; ++ /** ++ * Get keys for a variant of the transfer function from the credits.aleo program. ++ * ++ * ++ * @param {string} visibility Visibility of the transfer function (private, public, privateToPublic, publicToPrivate) ++ * @returns {Promise} Proving and verifying keys for the specified transfer function ++ * ++ * @example ++ * // Create a new OfflineKeyProvider ++ * const offlineKeyProvider = new OfflineKeyProvider(); ++ * ++ * // Cache the keys for future use with the official locator ++ * const transferPublicProvingKeyBytes = await readBinaryFile('./resources/transfer_public.prover.a74565e'); ++ * const transferPublicProvingKey = ProvingKey.fromBytes(transferPublicProvingKeyBytes); ++ * ++ * // Cache the transfer_public keys for future use with the OfflinKeyProvider's convenience method for ++ * // transfer_public (the verifying key will be cached automatically) ++ * offlineKeyProvider.insertTransferPublicKeys(transferPublicProvingKey); ++ * ++ * /// When they're needed, retrieve the keys from the cache ++ * const [transferPublicProvingKey, transferPublicVerifyingKey] = await keyProvider.transferKeys("public"); ++ */ ++ transferKeys(visibility) { ++ if (PRIVATE_TRANSFER.has(visibility)) { ++ return this.functionKeys(OfflineSearchParams.transferPrivateKeyParams()); ++ } ++ else if (PRIVATE_TO_PUBLIC_TRANSFER.has(visibility)) { ++ return this.functionKeys(OfflineSearchParams.transferPrivateToPublicKeyParams()); ++ } ++ else if (PUBLIC_TRANSFER.has(visibility)) { ++ return this.functionKeys(OfflineSearchParams.transferPublicKeyParams()); ++ } ++ else if (PUBLIC_TO_PRIVATE_TRANSFER.has(visibility)) { ++ return this.functionKeys(OfflineSearchParams.transferPublicToPrivateKeyParams()); ++ } ++ else { ++ throw new Error("Invalid visibility type"); ++ } ++ } ++ ; ++ /** ++ * Get unbond_public function keys from the credits.aleo program ++ * ++ * @returns {Promise} Proving and verifying keys for the join function ++ */ ++ async unBondPublicKeys() { ++ return this.functionKeys(OfflineSearchParams.unbondPublicKeyParams()); ++ } ++ ; ++ /** ++ * Insert the proving and verifying keys for the bond_public function into the cache. Only the proving key needs ++ * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check ++ * that the keys match the expected checksum for bond_public before inserting them into the cache. ++ * ++ * @param provingKey ++ */ ++ insertBondPublicKeys(provingKey) { ++ if (provingKey.isBondPublicProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.bond_public.locator, [provingKey.toBytes(), VerifyingKey.bondPublicVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for bond_public"); ++ } ++ } ++ /** ++ * Insert the proving and verifying keys for the claim_unbond_public function into the cache. Only the proving key needs ++ * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check ++ * that the keys match the expected checksum for claim_unbond_public before inserting them into the cache. ++ * ++ * @param provingKey ++ */ ++ insertClaimUnbondPublicKeys(provingKey) { ++ if (provingKey.isClaimUnbondPublicProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.claim_unbond_public.locator, [provingKey.toBytes(), VerifyingKey.claimUnbondPublicVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for claim_unbond_public"); ++ } ++ } ++ /** ++ * Insert the proving and verifying keys for the fee_private function into the cache. Only the proving key needs ++ * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check ++ * that the keys match the expected checksum for fee_private before inserting them into the cache. ++ * ++ * @param provingKey ++ */ ++ insertFeePrivateKeys(provingKey) { ++ if (provingKey.isFeePrivateProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.fee_private.locator, [provingKey.toBytes(), VerifyingKey.feePrivateVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for fee_private"); ++ } ++ } ++ /** ++ * Insert the proving and verifying keys for the fee_public function into the cache. Only the proving key needs ++ * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check ++ * that the keys match the expected checksum for fee_public before inserting them into the cache. ++ * ++ * @param provingKey ++ */ ++ insertFeePublicKeys(provingKey) { ++ if (provingKey.isFeePublicProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.fee_public.locator, [provingKey.toBytes(), VerifyingKey.feePublicVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for fee_public"); ++ } ++ } ++ /** ++ * Insert the proving and verifying keys for the join function into the cache. Only the proving key needs ++ * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check ++ * that the keys match the expected checksum for join before inserting them into the cache. ++ * ++ * @param provingKey ++ */ ++ insertJoinKeys(provingKey) { ++ if (provingKey.isJoinProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.join.locator, [provingKey.toBytes(), VerifyingKey.joinVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for join"); ++ } ++ } ++ /** ++ * Insert the proving and verifying keys for the set_validator_state function into the cache. Only the proving key needs ++ * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check ++ * that the keys match the expected checksum for set_validator_state before inserting them into the cache. ++ * ++ * @param provingKey ++ */ ++ insertSetValidatorStateKeys(provingKey) { ++ if (provingKey.isSetValidatorStateProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.set_validator_state.locator, [provingKey.toBytes(), VerifyingKey.setValidatorStateVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for set_validator_state"); ++ } ++ } ++ /** ++ * Insert the proving and verifying keys for the split function into the cache. Only the proving key needs ++ * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check ++ * that the keys match the expected checksum for split before inserting them into the cache. ++ * ++ * @param provingKey ++ */ ++ insertSplitKeys(provingKey) { ++ if (provingKey.isSplitProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.split.locator, [provingKey.toBytes(), VerifyingKey.splitVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for split"); ++ } ++ } ++ /** ++ * Insert the proving and verifying keys for the transfer_private function into the cache. Only the proving key needs ++ * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check ++ * that the keys match the expected checksum for transfer_private before inserting them into the cache. ++ * ++ * @param provingKey ++ */ ++ insertTransferPrivateKeys(provingKey) { ++ if (provingKey.isTransferPrivateProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.transfer_private.locator, [provingKey.toBytes(), VerifyingKey.transferPrivateVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for transfer_private"); ++ } ++ } ++ /** ++ * Insert the proving and verifying keys for the transfer_private_to_public function into the cache. Only the proving key needs ++ * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check ++ * that the keys match the expected checksum for transfer_private_to_public before inserting them into the cache. ++ * ++ * @param provingKey ++ */ ++ insertTransferPrivateToPublicKeys(provingKey) { ++ if (provingKey.isTransferPrivateToPublicProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.transfer_private_to_public.locator, [provingKey.toBytes(), VerifyingKey.transferPrivateToPublicVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for transfer_private_to_public"); ++ } ++ } ++ /** ++ * Insert the proving and verifying keys for the transfer_public function into the cache. Only the proving key needs ++ * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check ++ * that the keys match the expected checksum for transfer_public before inserting them into the cache. ++ * ++ * @param provingKey ++ */ ++ insertTransferPublicKeys(provingKey) { ++ if (provingKey.isTransferPublicProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.transfer_public.locator, [provingKey.toBytes(), VerifyingKey.transferPublicVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for transfer_public"); ++ } ++ } ++ /** ++ * Insert the proving and verifying keys for the transfer_public_to_private function into the cache. Only the proving key needs ++ * to be inserted, the verifying key is automatically inserted by the SDK. This function will automatically check ++ * that the keys match the expected checksum for transfer_public_to_private before inserting them into the cache. ++ * ++ * @param provingKey ++ */ ++ insertTransferPublicToPrivateKeys(provingKey) { ++ if (provingKey.isTransferPublicToPrivateProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.transfer_public_to_private.locator, [provingKey.toBytes(), VerifyingKey.transferPublicToPrivateVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for transfer_public_to_private"); ++ } ++ } ++ insertUnbondDelegatorAsValidatorKeys(provingKey) { ++ if (provingKey.isUnbondDelegatorAsValidatorProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.locator, [provingKey.toBytes(), VerifyingKey.unbondDelegatorAsValidatorVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for unbond_delegator_as_validator"); ++ } ++ } ++ insertUnbondPublicKeys(provingKey) { ++ if (provingKey.isUnbondPublicProver()) { ++ this.cache.set(CREDITS_PROGRAM_KEYS.unbond_public.locator, [provingKey.toBytes(), VerifyingKey.unbondPublicVerifier().toBytes()]); ++ } ++ else { ++ throw new Error("Attempted to insert invalid proving keys for unbond_public"); ++ } ++ } + } + + /** +@@ -1722,120 +1731,120 @@ class OfflineKeyProvider { + * deployment, wallet functionality, and other use cases. + */ + class NetworkRecordProvider { +- account; +- networkClient; +- constructor(account, networkClient) { +- this.account = account; +- this.networkClient = networkClient; +- } +- /** +- * Set the account used to search for records +- * +- * @param {Account} account The account to use for searching for records +- */ +- setAccount(account) { +- this.account = account; +- } +- /** +- * Find a list of credit records with a given number of microcredits by via the official Aleo API +- * +- * @param {number[]} microcredits The number of microcredits to search for +- * @param {boolean} unspent Whether or not the record is unspent +- * @param {string[]} nonces Nonces of records already found so that they are not found again +- * @param {RecordSearchParams} searchParameters Additional parameters to search for +- * @returns {Promise} The record if found, otherwise an error +- * +- * @example +- * // Create a new NetworkRecordProvider +- * const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1"); +- * const keyProvider = new AleoKeyProvider(); +- * const recordProvider = new NetworkRecordProvider(account, networkClient); +- * +- * // The record provider can be used to find records with a given number of microcredits +- * const record = await recordProvider.findCreditsRecord(5000, true, []); +- * +- * // When a record is found but not yet used, it's nonce should be added to the nonces parameter so that it is not +- * // found again if a subsequent search is performed +- * const records = await recordProvider.findCreditsRecords(5000, true, [record.nonce()]); +- * +- * // When the program manager is initialized with the record provider it will be used to find automatically find +- * // fee records and amount records for value transfers so that they do not need to be specified manually +- * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, recordProvider); +- * programManager.transfer(1, "aleo166q6ww6688cug7qxwe7nhctjpymydwzy2h7rscfmatqmfwnjvggqcad0at", "public", 0.5); +- * +- * */ +- async findCreditsRecords(microcredits, unspent, nonces, searchParameters) { +- let startHeight = 0; +- let endHeight = 0; +- if (searchParameters) { +- if ("startHeight" in searchParameters && typeof searchParameters["endHeight"] == "number") { +- startHeight = searchParameters["startHeight"]; +- } +- if ("endHeight" in searchParameters && typeof searchParameters["endHeight"] == "number") { +- endHeight = searchParameters["endHeight"]; +- } +- } +- // If the end height is not specified, use the current block height +- if (endHeight == 0) { +- const end = await this.networkClient.getLatestHeight(); +- if (end instanceof Error) { +- throw logAndThrow("Unable to get current block height from the network"); +- } +- endHeight = end; +- } +- // If the start height is greater than the end height, throw an error +- if (startHeight >= endHeight) { +- throw logAndThrow("Start height must be less than end height"); +- } +- return await this.networkClient.findUnspentRecords(startHeight, endHeight, this.account.privateKey(), microcredits, undefined, nonces); +- } +- /** +- * Find a credit record with a given number of microcredits by via the official Aleo API +- * +- * @param {number} microcredits The number of microcredits to search for +- * @param {boolean} unspent Whether or not the record is unspent +- * @param {string[]} nonces Nonces of records already found so that they are not found again +- * @param {RecordSearchParams} searchParameters Additional parameters to search for +- * @returns {Promise} The record if found, otherwise an error +- * +- * @example +- * // Create a new NetworkRecordProvider +- * const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1"); +- * const keyProvider = new AleoKeyProvider(); +- * const recordProvider = new NetworkRecordProvider(account, networkClient); +- * +- * // The record provider can be used to find records with a given number of microcredits +- * const record = await recordProvider.findCreditsRecord(5000, true, []); +- * +- * // When a record is found but not yet used, it's nonce should be added to the nonces parameter so that it is not +- * // found again if a subsequent search is performed +- * const records = await recordProvider.findCreditsRecords(5000, true, [record.nonce()]); +- * +- * // When the program manager is initialized with the record provider it will be used to find automatically find +- * // fee records and amount records for value transfers so that they do not need to be specified manually +- * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, recordProvider); +- * programManager.transfer(1, "aleo166q6ww6688cug7qxwe7nhctjpymydwzy2h7rscfmatqmfwnjvggqcad0at", "public", 0.5); +- */ +- async findCreditsRecord(microcredits, unspent, nonces, searchParameters) { +- const records = await this.findCreditsRecords([microcredits], unspent, nonces, searchParameters); +- if (!(records instanceof Error) && records.length > 0) { +- return records[0]; +- } +- console.error("Record not found with error:", records); +- return new Error("Record not found"); +- } +- /** +- * Find an arbitrary record. WARNING: This function is not implemented yet and will throw an error. +- */ +- async findRecord(unspent, nonces, searchParameters) { +- throw new Error("Method not implemented."); +- } +- /** +- * Find multiple arbitrary records. WARNING: This function is not implemented yet and will throw an error. +- */ +- async findRecords(unspent, nonces, searchParameters) { +- throw new Error("Method not implemented."); +- } ++ account; ++ networkClient; ++ constructor(account, networkClient) { ++ this.account = account; ++ this.networkClient = networkClient; ++ } ++ /** ++ * Set the account used to search for records ++ * ++ * @param {Account} account The account to use for searching for records ++ */ ++ setAccount(account) { ++ this.account = account; ++ } ++ /** ++ * Find a list of credit records with a given number of microcredits by via the official Aleo API ++ * ++ * @param {number[]} microcredits The number of microcredits to search for ++ * @param {boolean} unspent Whether or not the record is unspent ++ * @param {string[]} nonces Nonces of records already found so that they are not found again ++ * @param {RecordSearchParams} searchParameters Additional parameters to search for ++ * @returns {Promise} The record if found, otherwise an error ++ * ++ * @example ++ * // Create a new NetworkRecordProvider ++ * const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1"); ++ * const keyProvider = new AleoKeyProvider(); ++ * const recordProvider = new NetworkRecordProvider(account, networkClient); ++ * ++ * // The record provider can be used to find records with a given number of microcredits ++ * const record = await recordProvider.findCreditsRecord(5000, true, []); ++ * ++ * // When a record is found but not yet used, it's nonce should be added to the nonces parameter so that it is not ++ * // found again if a subsequent search is performed ++ * const records = await recordProvider.findCreditsRecords(5000, true, [record.nonce()]); ++ * ++ * // When the program manager is initialized with the record provider it will be used to find automatically find ++ * // fee records and amount records for value transfers so that they do not need to be specified manually ++ * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, recordProvider); ++ * programManager.transfer(1, "aleo166q6ww6688cug7qxwe7nhctjpymydwzy2h7rscfmatqmfwnjvggqcad0at", "public", 0.5); ++ * ++ * */ ++ async findCreditsRecords(microcredits, unspent, nonces, searchParameters) { ++ let startHeight = 0; ++ let endHeight = 0; ++ if (searchParameters) { ++ if ("startHeight" in searchParameters && typeof searchParameters["endHeight"] == "number") { ++ startHeight = searchParameters["startHeight"]; ++ } ++ if ("endHeight" in searchParameters && typeof searchParameters["endHeight"] == "number") { ++ endHeight = searchParameters["endHeight"]; ++ } ++ } ++ // If the end height is not specified, use the current block height ++ if (endHeight == 0) { ++ const end = await this.networkClient.getLatestHeight(); ++ if (end instanceof Error) { ++ throw logAndThrow("Unable to get current block height from the network"); ++ } ++ endHeight = end; ++ } ++ // If the start height is greater than the end height, throw an error ++ if (startHeight >= endHeight) { ++ throw logAndThrow("Start height must be less than end height"); ++ } ++ return await this.networkClient.findUnspentRecords(startHeight, endHeight, this.account.privateKey(), microcredits, undefined, nonces); ++ } ++ /** ++ * Find a credit record with a given number of microcredits by via the official Aleo API ++ * ++ * @param {number} microcredits The number of microcredits to search for ++ * @param {boolean} unspent Whether or not the record is unspent ++ * @param {string[]} nonces Nonces of records already found so that they are not found again ++ * @param {RecordSearchParams} searchParameters Additional parameters to search for ++ * @returns {Promise} The record if found, otherwise an error ++ * ++ * @example ++ * // Create a new NetworkRecordProvider ++ * const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1"); ++ * const keyProvider = new AleoKeyProvider(); ++ * const recordProvider = new NetworkRecordProvider(account, networkClient); ++ * ++ * // The record provider can be used to find records with a given number of microcredits ++ * const record = await recordProvider.findCreditsRecord(5000, true, []); ++ * ++ * // When a record is found but not yet used, it's nonce should be added to the nonces parameter so that it is not ++ * // found again if a subsequent search is performed ++ * const records = await recordProvider.findCreditsRecords(5000, true, [record.nonce()]); ++ * ++ * // When the program manager is initialized with the record provider it will be used to find automatically find ++ * // fee records and amount records for value transfers so that they do not need to be specified manually ++ * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, recordProvider); ++ * programManager.transfer(1, "aleo166q6ww6688cug7qxwe7nhctjpymydwzy2h7rscfmatqmfwnjvggqcad0at", "public", 0.5); ++ */ ++ async findCreditsRecord(microcredits, unspent, nonces, searchParameters) { ++ const records = await this.findCreditsRecords([microcredits], unspent, nonces, searchParameters); ++ if (!(records instanceof Error) && records.length > 0) { ++ return records[0]; ++ } ++ console.error("Record not found with error:", records); ++ return new Error("Record not found"); ++ } ++ /** ++ * Find an arbitrary record. WARNING: This function is not implemented yet and will throw an error. ++ */ ++ async findRecord(unspent, nonces, searchParameters) { ++ throw new Error("Method not implemented."); ++ } ++ /** ++ * Find multiple arbitrary records. WARNING: This function is not implemented yet and will throw an error. ++ */ ++ async findRecords(unspent, nonces, searchParameters) { ++ throw new Error("Method not implemented."); ++ } + } + /** + * BlockHeightSearch is a RecordSearchParams implementation that allows for searching for records within a given +@@ -1856,1078 +1865,1076 @@ class NetworkRecordProvider { + * + */ + class BlockHeightSearch { +- startHeight; +- endHeight; +- constructor(startHeight, endHeight) { +- this.startHeight = startHeight; +- this.endHeight = endHeight; +- } ++ startHeight; ++ endHeight; ++ constructor(startHeight, endHeight) { ++ this.startHeight = startHeight; ++ this.endHeight = endHeight; ++ } + } + + // Experimental example where SDK manages worker + let singletonWorker = null; + const createAleoWorker = () => { +- if (!singletonWorker) { +- const worker = new Worker(new URL("worker.js", import.meta.url), { +- type: "module", +- }); +- singletonWorker = wrap(worker); +- } +- return singletonWorker; ++ if (!singletonWorker) { ++ const worker = new Worker(new URL("worker.js", import.meta.url), { ++ type: "module", ++ }); ++ singletonWorker = wrap(worker); ++ } ++ return singletonWorker; + }; + + /** + * The ProgramManager class is used to execute and deploy programs on the Aleo network and create value transfers. + */ + class ProgramManager { +- account; +- keyProvider; +- host; +- networkClient; +- recordProvider; +- /** Create a new instance of the ProgramManager +- * +- * @param { string | undefined } host A host uri running the official Aleo API +- * @param { FunctionKeyProvider | undefined } keyProvider A key provider that implements {@link FunctionKeyProvider} interface +- * @param { RecordProvider | undefined } recordProvider A record provider that implements {@link RecordProvider} interface +- */ +- constructor(host, keyProvider, recordProvider) { +- if (!host) { +- this.host = "https://api.explorer.aleo.org/v1"; +- this.networkClient = new AleoNetworkClient(this.host); +- } +- else { +- this.host = host; +- this.networkClient = new AleoNetworkClient(host); +- } +- if (!keyProvider) { +- this.keyProvider = new AleoKeyProvider(); +- } +- else { +- this.keyProvider = keyProvider; +- } +- this.recordProvider = recordProvider; +- } +- /** +- * Set the account to use for transaction submission to the Aleo network +- * +- * @param {Account} account Account to use for transaction submission +- */ +- setAccount(account) { +- this.account = account; +- } +- /** +- * Set the key provider that provides the proving and verifying keys for programs +- * +- * @param {FunctionKeyProvider} keyProvider +- */ +- setKeyProvider(keyProvider) { +- this.keyProvider = keyProvider; +- } +- /** +- * Set the host peer to use for transaction submission to the Aleo network +- * +- * @param host {string} Peer url to use for transaction submission +- */ +- setHost(host) { +- this.host = host; +- this.networkClient.setHost(host); +- } +- /** +- * Set the record provider that provides records for transactions +- * +- * @param {RecordProvider} recordProvider +- */ +- setRecordProvider(recordProvider) { +- this.recordProvider = recordProvider; +- } +- /** +- * Deploy an Aleo program to the Aleo network +- * +- * @param {string} program Program source code +- * @param {number} fee Fee to pay for the transaction +- * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance +- * @param {RecordSearchParams | undefined} recordSearchParams Optional parameters for searching for a record to use +- * pay the deployment fee +- * @param {string | RecordPlaintext | undefined} feeRecord Optional Fee record to use for the transaction +- * @param {PrivateKey | undefined} privateKey Optional private key to use for the transaction +- * @returns {string | Error} The transaction id of the deployed program or a failure message from the network +- * +- * @example +- * // Create a new NetworkClient, KeyProvider, and RecordProvider +- * const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1"); +- * const keyProvider = new AleoKeyProvider(); +- * const recordProvider = new NetworkRecordProvider(account, networkClient); +- * +- * // Initialize a program manager with the key provider to automatically fetch keys for deployments +- * const program = "program hello_hello.aleo;\n\nfunction hello:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n"; +- * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, recordProvider); +- * +- * // Define a fee in credits +- * const fee = 1.2; +- * +- * // Deploy the program +- * const tx_id = await programManager.deploy(program, fee); +- * +- * // Verify the transaction was successful +- * const transaction = await programManager.networkClient.getTransaction(tx_id); +- */ +- async deploy(program, fee, privateFee, recordSearchParams, feeRecord, privateKey) { +- // Ensure the program is valid and does not exist on the network +- try { +- const programObject = Program.fromString(program); +- let programSource; +- try { +- programSource = await this.networkClient.getProgram(programObject.id()); +- } +- catch (e) { +- // Program does not exist on the network, deployment can proceed +- console.log(`Program ${programObject.id()} does not exist on the network, deploying...`); +- } +- if (typeof programSource == "string") { +- throw (`Program ${programObject.id()} already exists on the network, please rename your program`); +- } +- } +- catch (e) { +- throw logAndThrow(`Error validating program: ${e}`); +- } +- // Get the private key from the account if it is not provided in the parameters +- let deploymentPrivateKey = privateKey; +- if (typeof privateKey === "undefined" && typeof this.account !== "undefined") { +- deploymentPrivateKey = this.account.privateKey(); +- } +- if (typeof deploymentPrivateKey === "undefined") { +- throw ("No private key provided and no private key set in the ProgramManager"); +- } +- // Get the fee record from the account if it is not provided in the parameters +- try { +- feeRecord = privateFee ? await this.getCreditsRecord(fee, [], feeRecord, recordSearchParams) : undefined; +- } +- catch (e) { +- throw logAndThrow(`Error finding fee record. Record finder response: '${e}'. Please ensure you're connected to a valid Aleo network and a record with enough balance exists.`); +- } +- // Get the proving and verifying keys from the key provider +- let feeKeys; +- try { +- feeKeys = privateFee ? await this.keyProvider.feePrivateKeys() : await this.keyProvider.feePublicKeys(); +- } +- catch (e) { +- throw logAndThrow(`Error finding fee keys. Key finder response: '${e}'. Please ensure your key provider is configured correctly.`); +- } +- const [feeProvingKey, feeVerifyingKey] = feeKeys; +- // Resolve the program imports if they exist +- let imports; +- try { +- imports = await this.networkClient.getProgramImports(program); +- } +- catch (e) { +- throw logAndThrow(`Error finding program imports. Network response: '${e}'. Please ensure you're connected to a valid Aleo network and the program is deployed to the network.`); +- } +- // Build a deployment transaction and submit it to the network +- const tx = await ProgramManager$1.buildDeploymentTransaction(deploymentPrivateKey, program, fee, feeRecord, this.host, imports, feeProvingKey, feeVerifyingKey); +- return await this.networkClient.submitTransaction(tx); +- } +- /** +- * Build an execution transaction for later submission to the Aleo network. +- * +- * @param {string} programName Program name containing the function to be executed +- * @param {string} functionName Function name to execute +- * @param {number} fee Fee to pay for the transaction +- * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance +- * @param {string[]} inputs Inputs to the function +- * @param {RecordSearchParams} recordSearchParams Optional parameters for searching for a record to pay the fee for +- * the execution transaction +- * @param {KeySearchParams} keySearchParams Optional parameters for finding the matching proving & verifying keys +- * for the function +- * @param {string | RecordPlaintext | undefined} feeRecord Optional Fee record to use for the transaction +- * @param {ProvingKey | undefined} provingKey Optional proving key to use for the transaction +- * @param {VerifyingKey | undefined} verifyingKey Optional verifying key to use for the transaction +- * @param {PrivateKey | undefined} privateKey Optional private key to use for the transaction +- * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment +- * @param {string | Program | undefined} program Optional program source code to use for the transaction +- * @param {ProgramImports} imports Programs that the program being executed imports +- * @returns {Promise} +- * +- * @example +- * // Create a new NetworkClient, KeyProvider, and RecordProvider using official Aleo record, key, and network providers +- * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); +- * const keyProvider = new AleoKeyProvider(); +- * keyProvider.useCache = true; +- * const recordProvider = new NetworkRecordProvider(account, networkClient); +- * +- * // Initialize a program manager with the key provider to automatically fetch keys for executions +- * const programName = "hello_hello.aleo"; +- * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); +- * const keySearchParams = { "cacheKey": "hello_hello:hello" }; +- * const transaction = await programManager.execute(programName, "hello_hello", 0.020, ["5u32", "5u32"], undefined, undefined, undefined, keySearchParams); +- * const result = await programManager.networkClient.submitTransaction(transaction); +- */ +- async buildExecutionTransaction(programName, functionName, fee, privateFee, inputs, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery, program, imports) { +- // Ensure the function exists on the network +- if (program === undefined) { +- try { +- program = (await this.networkClient.getProgram(programName)); +- } +- catch (e) { +- throw logAndThrow(`Error finding ${programName}. Network response: '${e}'. Please ensure you're connected to a valid Aleo network the program is deployed to the network.`); +- } +- } +- else if (program instanceof Program) { +- program = program.toString(); +- } +- // Get the private key from the account if it is not provided in the parameters +- let executionPrivateKey = privateKey; +- if (typeof privateKey === "undefined" && typeof this.account !== "undefined") { +- executionPrivateKey = this.account.privateKey(); +- } +- if (typeof executionPrivateKey === "undefined") { +- throw ("No private key provided and no private key set in the ProgramManager"); +- } +- // Get the fee record from the account if it is not provided in the parameters +- try { +- feeRecord = privateFee ? await this.getCreditsRecord(fee, [], feeRecord, recordSearchParams) : undefined; +- } +- catch (e) { +- throw logAndThrow(`Error finding fee record. Record finder response: '${e}'. Please ensure you're connected to a valid Aleo network and a record with enough balance exists.`); +- } +- // Get the fee proving and verifying keys from the key provider +- let feeKeys; +- try { +- feeKeys = privateFee ? await this.keyProvider.feePrivateKeys() : await this.keyProvider.feePublicKeys(); +- } +- catch (e) { +- throw logAndThrow(`Error finding fee keys. Key finder response: '${e}'. Please ensure your key provider is configured correctly.`); +- } +- const [feeProvingKey, feeVerifyingKey] = feeKeys; +- // If the function proving and verifying keys are not provided, attempt to find them using the key provider +- if (!provingKey || !verifyingKey) { +- try { +- [provingKey, verifyingKey] = await this.keyProvider.functionKeys(keySearchParams); +- } +- catch (e) { +- console.log(`Function keys not found. Key finder response: '${e}'. The function keys will be synthesized`); +- } +- } +- // Resolve the program imports if they exist +- const numberOfImports = Program.fromString(program).getImports().length; +- if (numberOfImports > 0 && !imports) { +- try { +- imports = await this.networkClient.getProgramImports(programName); +- } +- catch (e) { +- throw logAndThrow(`Error finding program imports. Network response: '${e}'. Please ensure you're connected to a valid Aleo network and the program is deployed to the network.`); +- } +- } +- // Build an execution transaction and submit it to the network +- return await ProgramManager$1.buildExecutionTransaction(executionPrivateKey, program, functionName, inputs, fee, feeRecord, this.host, imports, provingKey, verifyingKey, feeProvingKey, feeVerifyingKey, offlineQuery); +- } +- /** +- * Execute an Aleo program on the Aleo network +- * +- * @param {string} programName Program name containing the function to be executed +- * @param {string} functionName Function name to execute +- * @param {number} fee Fee to pay for the transaction +- * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance +- * @param {string[]} inputs Inputs to the function +- * @param {RecordSearchParams} recordSearchParams Optional parameters for searching for a record to pay the fee for +- * the execution transaction +- * @param {KeySearchParams} keySearchParams Optional parameters for finding the matching proving & verifying keys +- * for the function +- * @param {string | RecordPlaintext | undefined} feeRecord Optional Fee record to use for the transaction +- * @param {ProvingKey | undefined} provingKey Optional proving key to use for the transaction +- * @param {VerifyingKey | undefined} verifyingKey Optional verifying key to use for the transaction +- * @param {PrivateKey | undefined} privateKey Optional private key to use for the transaction +- * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment +- * @returns {Promise} +- * +- * @example +- * // Create a new NetworkClient, KeyProvider, and RecordProvider using official Aleo record, key, and network providers +- * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); +- * const keyProvider = new AleoKeyProvider(); +- * keyProvider.useCache = true; +- * const recordProvider = new NetworkRecordProvider(account, networkClient); +- * +- * // Initialize a program manager with the key provider to automatically fetch keys for executions +- * const programName = "hello_hello.aleo"; +- * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); +- * const keySearchParams = { "cacheKey": "hello_hello:hello" }; +- * const tx_id = await programManager.execute(programName, "hello_hello", 0.020, ["5u32", "5u32"], undefined, undefined, undefined, keySearchParams); +- * const transaction = await programManager.networkClient.getTransaction(tx_id); +- */ +- async execute(programName, functionName, fee, privateFee, inputs, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery, program) { +- const tx = await this.buildExecutionTransaction(programName, functionName, fee, privateFee, inputs, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery, program); +- return await this.networkClient.submitTransaction(tx); +- } +- /** +- * Run an Aleo program in offline mode +- * +- * @param {string} program Program source code containing the function to be executed +- * @param {string} function_name Function name to execute +- * @param {string[]} inputs Inputs to the function +- * @param {number} proveExecution Whether to prove the execution of the function and return an execution transcript +- * that contains the proof. +- * @param {string[] | undefined} imports Optional imports to the program +- * @param {KeySearchParams | undefined} keySearchParams Optional parameters for finding the matching proving & +- * verifying keys for the function +- * @param {ProvingKey | undefined} provingKey Optional proving key to use for the transaction +- * @param {VerifyingKey | undefined} verifyingKey Optional verifying key to use for the transaction +- * @param {PrivateKey | undefined} privateKey Optional private key to use for the transaction +- * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment +- * @returns {Promise} +- * +- * @example +- * import { Account, Program } from '@aleohq/sdk'; +- * +- * /// Create the source for the "helloworld" program +- * const program = "program helloworld.aleo;\n\nfunction hello:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n"; +- * const programManager = new ProgramManager(); +- * +- * /// Create a temporary account for the execution of the program +- * const account = new Account(); +- * programManager.setAccount(account); +- * +- * /// Get the response and ensure that the program executed correctly +- * const executionResponse = await programManager.executeOffline(program, "hello", ["5u32", "5u32"]); +- * const result = executionResponse.getOutputs(); +- * assert(result === ["10u32"]); +- */ +- async run(program, function_name, inputs, proveExecution, imports, keySearchParams, provingKey, verifyingKey, privateKey, offlineQuery) { +- // Get the private key from the account if it is not provided in the parameters +- let executionPrivateKey = privateKey; +- if (typeof privateKey === "undefined" && typeof this.account !== "undefined") { +- executionPrivateKey = this.account.privateKey(); +- } +- if (typeof executionPrivateKey === "undefined") { +- throw ("No private key provided and no private key set in the ProgramManager"); +- } +- // If the function proving and verifying keys are not provided, attempt to find them using the key provider +- if (!provingKey || !verifyingKey) { +- try { +- [provingKey, verifyingKey] = await this.keyProvider.functionKeys(keySearchParams); +- } +- catch (e) { +- console.log(`Function keys not found. Key finder response: '${e}'. The function keys will be synthesized`); +- } +- } +- // Run the program offline and return the result +- console.log("Running program offline"); +- console.log("Proving key: ", provingKey); +- console.log("Verifying key: ", verifyingKey); +- return ProgramManager$1.executeFunctionOffline(executionPrivateKey, program, function_name, inputs, proveExecution, false, imports, provingKey, verifyingKey, this.host, offlineQuery); +- } +- /** +- * Join two credits records into a single credits record +- * +- * @param {RecordPlaintext | string} recordOne First credits record to join +- * @param {RecordPlaintext | string} recordTwo Second credits record to join +- * @param {number} fee Fee in credits pay for the join transaction +- * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance +- * @param {RecordSearchParams | undefined} recordSearchParams Optional parameters for finding the fee record to use +- * to pay the fee for the join transaction +- * @param {RecordPlaintext | string | undefined} feeRecord Fee record to use for the join transaction +- * @param {PrivateKey | undefined} privateKey Private key to use for the join transaction +- * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment +- * @returns {Promise} +- */ +- async join(recordOne, recordTwo, fee, privateFee, recordSearchParams, feeRecord, privateKey, offlineQuery) { +- // Get the private key from the account if it is not provided in the parameters +- let executionPrivateKey = privateKey; +- if (typeof privateKey === "undefined" && typeof this.account !== "undefined") { +- executionPrivateKey = this.account.privateKey(); +- } +- if (typeof executionPrivateKey === "undefined") { +- throw ("No private key provided and no private key set in the ProgramManager"); +- } +- // Get the proving and verifying keys from the key provider +- let feeKeys; +- let joinKeys; +- try { +- feeKeys = privateFee ? await this.keyProvider.feePrivateKeys() : await this.keyProvider.feePublicKeys(); +- joinKeys = await this.keyProvider.joinKeys(); +- } +- catch (e) { +- throw logAndThrow(`Error finding fee keys. Key finder response: '${e}'. Please ensure your key provider is configured correctly.`); +- } +- const [feeProvingKey, feeVerifyingKey] = feeKeys; +- const [joinProvingKey, joinVerifyingKey] = joinKeys; +- // Get the fee record from the account if it is not provided in the parameters +- try { +- feeRecord = privateFee ? await this.getCreditsRecord(fee, [], feeRecord, recordSearchParams) : undefined; +- } +- catch (e) { +- throw logAndThrow(`Error finding fee record. Record finder response: '${e}'. Please ensure you're connected to a valid Aleo network and a record with enough balance exists.`); +- } +- // Validate the records provided are valid plaintext records +- try { +- recordOne = recordOne instanceof RecordPlaintext ? recordOne : RecordPlaintext.fromString(recordOne); +- recordTwo = recordTwo instanceof RecordPlaintext ? recordTwo : RecordPlaintext.fromString(recordTwo); +- } +- catch (e) { +- throw logAndThrow('Records provided are not valid. Please ensure they are valid plaintext records.'); +- } +- // Build an execution transaction and submit it to the network +- const tx = await ProgramManager$1.buildJoinTransaction(executionPrivateKey, recordOne, recordTwo, fee, feeRecord, this.host, joinProvingKey, joinVerifyingKey, feeProvingKey, feeVerifyingKey, offlineQuery); +- return await this.networkClient.submitTransaction(tx); +- } +- /** +- * Split credits into two new credits records +- * +- * @param {number} splitAmount Amount in microcredits to split from the original credits record +- * @param {RecordPlaintext | string} amountRecord Amount record to use for the split transaction +- * @param {PrivateKey | undefined} privateKey Optional private key to use for the split transaction +- * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment +- * @returns {Promise} +- * +- * @example +- * // Create a new NetworkClient, KeyProvider, and RecordProvider +- * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); +- * const keyProvider = new AleoKeyProvider(); +- * const recordProvider = new NetworkRecordProvider(account, networkClient); +- * +- * // Initialize a program manager with the key provider to automatically fetch keys for executions +- * const programName = "hello_hello.aleo"; +- * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); +- * const record = "{ owner: aleo184vuwr5u7u0ha5f5k44067dd2uaqewxx6pe5ltha5pv99wvhfqxqv339h4.private, microcredits: 45000000u64.private, _nonce: 4106205762862305308495708971985748592380064201230396559307556388725936304984group.public}" +- * const tx_id = await programManager.split(25000000, record); +- * const transaction = await programManager.networkClient.getTransaction(tx_id); +- */ +- async split(splitAmount, amountRecord, privateKey, offlineQuery) { +- // Get the private key from the account if it is not provided in the parameters +- let executionPrivateKey = privateKey; +- if (typeof executionPrivateKey === "undefined" && typeof this.account !== "undefined") { +- executionPrivateKey = this.account.privateKey(); +- } +- if (typeof executionPrivateKey === "undefined") { +- throw ("No private key provided and no private key set in the ProgramManager"); +- } +- // Get the split keys from the key provider +- let splitKeys; +- try { +- splitKeys = await this.keyProvider.splitKeys(); +- } +- catch (e) { +- throw logAndThrow(`Error finding fee keys. Key finder response: '${e}'. Please ensure your key provider is configured correctly.`); +- } +- const [splitProvingKey, splitVerifyingKey] = splitKeys; +- // Validate the record to be split +- try { +- amountRecord = amountRecord instanceof RecordPlaintext ? amountRecord : RecordPlaintext.fromString(amountRecord); +- } +- catch (e) { +- throw logAndThrow("Record provided is not valid. Please ensure it is a valid plaintext record."); +- } +- // Build an execution transaction and submit it to the network +- const tx = await ProgramManager$1.buildSplitTransaction(executionPrivateKey, splitAmount, amountRecord, this.host, splitProvingKey, splitVerifyingKey, offlineQuery); +- return await this.networkClient.submitTransaction(tx); +- } +- /** +- * Pre-synthesize proving and verifying keys for a program +- * +- * @param program {string} The program source code to synthesize keys for +- * @param function_id {string} The function id to synthesize keys for +- * @param inputs {Array} Sample inputs to the function +- * @param privateKey {PrivateKey | undefined} Optional private key to use for the key synthesis +- * +- * @returns {Promise} +- */ +- async synthesizeKeys(program, function_id, inputs, privateKey) { +- // Resolve the program imports if they exist +- let imports; +- let executionPrivateKey = privateKey; +- if (typeof executionPrivateKey === "undefined") { +- if (typeof this.account !== "undefined") { +- executionPrivateKey = this.account.privateKey(); +- } +- else { +- executionPrivateKey = new PrivateKey(); +- } +- } +- // Attempt to run an offline execution of the program and extract the proving and verifying keys +- try { +- imports = await this.networkClient.getProgramImports(program); +- const keyPair = await ProgramManager$1.synthesizeKeyPair(executionPrivateKey, program, function_id, inputs, imports); +- return [keyPair.provingKey(), keyPair.verifyingKey()]; +- } +- catch (e) { +- throw logAndThrow(`Could not synthesize keys - error ${e}. Please ensure the program is valid and the inputs are correct.`); +- } +- } +- /** +- * Build a transaction to transfer credits to another account for later submission to the Aleo network +- * +- * @param {number} amount The amount of credits to transfer +- * @param {string} recipient The recipient of the transfer +- * @param {string} transferType The type of transfer to perform - options: 'private', 'privateToPublic', 'public', 'publicToPrivate' +- * @param {number} fee The fee to pay for the transfer +- * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance +- * @param {RecordSearchParams | undefined} recordSearchParams Optional parameters for finding the amount and fee +- * records for the transfer transaction +- * @param {RecordPlaintext | string} amountRecord Optional amount record to use for the transfer +- * @param {RecordPlaintext | string} feeRecord Optional fee record to use for the transfer +- * @param {PrivateKey | undefined} privateKey Optional private key to use for the transfer transaction +- * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment +- * @returns {Promise} The transaction id of the transfer transaction +- * +- * @example +- * // Create a new NetworkClient, KeyProvider, and RecordProvider +- * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); +- * const keyProvider = new AleoKeyProvider(); +- * const recordProvider = new NetworkRecordProvider(account, networkClient); +- * +- * // Initialize a program manager with the key provider to automatically fetch keys for executions +- * const programName = "hello_hello.aleo"; +- * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); +- * await programManager.initialize(); +- * const tx_id = await programManager.transfer(1, "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px", "private", 0.2) +- * const transaction = await programManager.networkClient.getTransaction(tx_id); +- */ +- async buildTransferTransaction(amount, recipient, transferType, fee, privateFee, recordSearchParams, amountRecord, feeRecord, privateKey, offlineQuery) { +- // Validate the transfer type +- transferType = validateTransferType(transferType); +- // Get the private key from the account if it is not provided in the parameters +- let executionPrivateKey = privateKey; +- if (typeof executionPrivateKey === "undefined" && typeof this.account !== "undefined") { +- executionPrivateKey = this.account.privateKey(); +- } +- if (typeof executionPrivateKey === "undefined") { +- throw ("No private key provided and no private key set in the ProgramManager"); +- } +- // Get the proving and verifying keys from the key provider +- let feeKeys; +- let transferKeys; +- try { +- feeKeys = privateFee ? await this.keyProvider.feePrivateKeys() : await this.keyProvider.feePublicKeys(); +- transferKeys = await this.keyProvider.transferKeys(transferType); +- } +- catch (e) { +- throw logAndThrow(`Error finding fee keys. Key finder response: '${e}'. Please ensure your key provider is configured correctly.`); +- } +- const [feeProvingKey, feeVerifyingKey] = feeKeys; +- const [transferProvingKey, transferVerifyingKey] = transferKeys; +- // Get the amount and fee record from the account if it is not provided in the parameters +- try { +- // Track the nonces of the records found so no duplicate records are used +- const nonces = []; +- if (requiresAmountRecord(transferType)) { +- // If the transfer type is private and requires an amount record, get it from the record provider +- amountRecord = await this.getCreditsRecord(fee, [], amountRecord, recordSearchParams); +- nonces.push(amountRecord.nonce()); +- } +- else { +- amountRecord = undefined; +- } +- feeRecord = privateFee ? await this.getCreditsRecord(fee, nonces, feeRecord, recordSearchParams) : undefined; +- } +- catch (e) { +- throw logAndThrow(`Error finding fee record. Record finder response: '${e}'. Please ensure you're connected to a valid Aleo network and a record with enough balance exists.`); +- } +- // Build an execution transaction and submit it to the network +- return await ProgramManager$1.buildTransferTransaction(executionPrivateKey, amount, recipient, transferType, amountRecord, fee, feeRecord, this.host, transferProvingKey, transferVerifyingKey, feeProvingKey, feeVerifyingKey, offlineQuery); +- } +- /** +- * Build a transfer_public transaction to transfer credits to another account for later submission to the Aleo network +- * +- * @param {number} amount The amount of credits to transfer +- * @param {string} recipient The recipient of the transfer +- * @param {string} transferType The type of transfer to perform - options: 'private', 'privateToPublic', 'public', 'publicToPrivate' +- * @param {number} fee The fee to pay for the transfer +- * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance +- * @param {RecordSearchParams | undefined} recordSearchParams Optional parameters for finding the amount and fee +- * records for the transfer transaction +- * @param {RecordPlaintext | string} amountRecord Optional amount record to use for the transfer +- * @param {RecordPlaintext | string} feeRecord Optional fee record to use for the transfer +- * @param {PrivateKey | undefined} privateKey Optional private key to use for the transfer transaction +- * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment +- * @returns {Promise} The transaction id of the transfer transaction +- * +- * @example +- * // Create a new NetworkClient, KeyProvider, and RecordProvider +- * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); +- * const keyProvider = new AleoKeyProvider(); +- * const recordProvider = new NetworkRecordProvider(account, networkClient); +- * +- * // Initialize a program manager with the key provider to automatically fetch keys for executions +- * const programName = "hello_hello.aleo"; +- * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); +- * await programManager.initialize(); +- * const tx_id = await programManager.transfer(1, "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px", "private", 0.2) +- * const transaction = await programManager.networkClient.getTransaction(tx_id); +- */ +- async buildTransferPublicTransaction(amount, recipient, fee, privateKey, offlineQuery) { +- return this.buildTransferTransaction(amount, recipient, "public", fee, false, undefined, undefined, undefined, privateKey, offlineQuery); +- } +- /** +- * Transfer credits to another account +- * +- * @param {number} amount The amount of credits to transfer +- * @param {string} recipient The recipient of the transfer +- * @param {string} transferType The type of transfer to perform - options: 'private', 'privateToPublic', 'public', 'publicToPrivate' +- * @param {number} fee The fee to pay for the transfer +- * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance +- * @param {RecordSearchParams | undefined} recordSearchParams Optional parameters for finding the amount and fee +- * records for the transfer transaction +- * @param {RecordPlaintext | string} amountRecord Optional amount record to use for the transfer +- * @param {RecordPlaintext | string} feeRecord Optional fee record to use for the transfer +- * @param {PrivateKey | undefined} privateKey Optional private key to use for the transfer transaction +- * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment +- * @returns {Promise} The transaction id of the transfer transaction +- * +- * @example +- * // Create a new NetworkClient, KeyProvider, and RecordProvider +- * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); +- * const keyProvider = new AleoKeyProvider(); +- * const recordProvider = new NetworkRecordProvider(account, networkClient); +- * +- * // Initialize a program manager with the key provider to automatically fetch keys for executions +- * const programName = "hello_hello.aleo"; +- * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); +- * await programManager.initialize(); +- * const tx_id = await programManager.transfer(1, "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px", "private", 0.2) +- * const transaction = await programManager.networkClient.getTransaction(tx_id); +- */ +- async transfer(amount, recipient, transferType, fee, privateFee, recordSearchParams, amountRecord, feeRecord, privateKey, offlineQuery) { +- const tx = await this.buildTransferTransaction(amount, recipient, transferType, fee, privateFee, recordSearchParams, amountRecord, feeRecord, privateKey, offlineQuery); +- return await this.networkClient.submitTransaction(tx); +- } +- /** +- * Build transaction to bond credits to a staking committee for later submission to the Aleo Network +- * +- * @example +- * // Create a keyProvider to handle key management +- * const keyProvider = new AleoKeyProvider(); +- * keyProvider.useCache = true; +- * +- * // Create a new ProgramManager with the key that will be used to bond credits +- * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, undefined); +- * programManager.setAccount(new Account("YourPrivateKey")); +- * +- * // Create the bonding transaction +- * const tx_id = await programManager.bondPublic("aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px", 2000000); +- * +- * @returns string +- * @param {string} address Address of the validator to bond to, if this address is the same as the signer (i.e. the +- * executor of this function), it will attempt to bond the credits as a validator. Bonding as a validator currently +- * requires a minimum of 1,000,000 credits to bond (subject to change). If the address is specified is an existing +- * validator and is different from the address of the executor of this function, it will bond the credits to that +- * validator's staking committee as a delegator. A minimum of 10 credits is required to bond as a delegator. +- * @param {number} amount The amount of credits to bond +- * @param {Options} options Options for the execution +- */ +- async buildBondPublicTransaction(address, amount, options = {}) { +- amount = Math.trunc(amount * 1000000); +- const { offlineParams = {}, executionParams = {} } = options || {}; +- let { programName = "credits.aleo", functionName = "bond_public", fee = executionParams?.fee || 0.86, privateFee = false, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey } = executionParams; +- if (keySearchParams === undefined) { +- keySearchParams = new AleoKeyProviderParams({ +- proverUri: CREDITS_PROGRAM_KEYS.bond_public.prover, +- verifierUri: CREDITS_PROGRAM_KEYS.bond_public.verifier, +- cacheKey: "credits.aleo/bond_public" +- }); +- } +- const { offlineQuery, } = offlineParams; +- return await this.buildExecutionTransaction(programName, functionName, fee, privateFee, [address, `${amount.toString()}u64`], recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery, this.creditsProgram()); +- } +- /** +- * Bond credits to a staking committee +- * +- * @example +- * // Create a keyProvider to handle key management +- * const keyProvider = new AleoKeyProvider(); +- * keyProvider.useCache = true; +- * +- * // Create a new ProgramManager with the key that will be used to bond credits +- * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, undefined); +- * programManager.setAccount(new Account("YourPrivateKey")); +- * +- * // Create the bonding transaction +- * const tx_id = await programManager.bondPublic("aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px", 2000000); +- * +- * @returns string +- * @param {string} address Address of the validator to bond to, if this address is the same as the signer (i.e. the +- * executor of this function), it will attempt to bond the credits as a validator. Bonding as a validator currently +- * requires a minimum of 1,000,000 credits to bond (subject to change). If the address is specified is an existing +- * validator and is different from the address of the executor of this function, it will bond the credits to that +- * validator's staking committee as a delegator. A minimum of 10 credits is required to bond as a delegator. +- * @param {number} amount The amount of credits to bond +- * @param {Options} options Options for the execution +- */ +- async bondPublic(address, amount, options = {}) { +- const tx = await this.buildBondPublicTransaction(address, amount, options); +- return await this.networkClient.submitTransaction(tx); +- } +- /** +- * Build a transaction to unbond a specified amount of staked credits to be used later +- * +- * @example +- * // Create a keyProvider to handle key management +- * const keyProvider = new AleoKeyProvider(); +- * keyProvider.useCache = true; +- * +- * // Create a new ProgramManager with the key that will be used to bond credits +- * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, undefined); +- * programManager.setAccount(new Account("YourPrivateKey")); +- * +- * // Create the bonding transaction +- * const tx_id = await programManager.unbondPublic(10); +- * +- * @returns string +- * @param {number} amount Amount of credits to unbond. If the address of the executor of this function is an +- * existing validator, it will subtract this amount of credits from the validator's staked credits. If there are +- * less than 1,000,000 credits staked pool after the unbond, the validator will be removed from the validator set. +- * If the address of the executor of this function is not a validator and has credits bonded as a delegator, it will +- * subtract this amount of credits from the delegator's staked credits. If there are less than 10 credits bonded +- * after the unbond operation, the delegator will be removed from the validator's staking pool. +- * @param {Options} options Options for the execution +- */ +- async buildUnbondPublicTransaction(amount, options = {}) { +- amount = Math.trunc(amount * 1000000); +- const { offlineParams = {}, executionParams = {} } = options || {}; +- let { programName = "credits.aleo", functionName = "unbond_public", fee = executionParams?.fee || 1.3, privateFee = false, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey } = executionParams; +- if (keySearchParams === undefined) { +- keySearchParams = new AleoKeyProviderParams({ +- proverUri: CREDITS_PROGRAM_KEYS.unbond_public.prover, +- verifierUri: CREDITS_PROGRAM_KEYS.unbond_public.verifier, +- cacheKey: "credits.aleo/unbond_public" +- }); +- } +- const { offlineQuery, } = offlineParams; +- return this.buildExecutionTransaction(programName, functionName, fee, privateFee, [`${amount.toString()}u64`], recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery, this.creditsProgram()); +- } +- /** +- * Unbond a specified amount of staked credits to be used later +- * +- * @example +- * // Create a keyProvider to handle key management +- * const keyProvider = new AleoKeyProvider(); +- * keyProvider.useCache = true; +- * +- * // Create a new ProgramManager with the key that will be used to bond credits +- * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, undefined); +- * programManager.setAccount(new Account("YourPrivateKey")); +- * +- * // Create the bonding transaction +- * const tx_id = await programManager.unbondPublic(10); +- * +- * @returns string +- * @param {number} amount Amount of credits to unbond. If the address of the executor of this function is an +- * existing validator, it will subtract this amount of credits from the validator's staked credits. If there are +- * less than 1,000,000 credits staked pool after the unbond, the validator will be removed from the validator set. +- * If the address of the executor of this function is not a validator and has credits bonded as a delegator, it will +- * subtract this amount of credits from the delegator's staked credits. If there are less than 10 credits bonded +- * after the unbond operation, the delegator will be removed from the validator's staking pool. +- * @param {Options} options Options for the execution +- */ +- async unbondPublic(amount, options = {}) { +- const tx = await this.buildUnbondPublicTransaction(amount, options); +- return await this.networkClient.submitTransaction(tx); +- } +- /** +- * Build a transaction to Claim unbonded credits for later submission. If credits have been unbonded by the account +- * executing this function, this method will claim them and add them to the public balance of the account. +- * +- * @example +- * // Create a keyProvider to handle key management +- * const keyProvider = new AleoKeyProvider(); +- * keyProvider.useCache = true; +- * +- * // Create a new ProgramManager with the key that will be used to bond credits +- * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, undefined); +- * programManager.setAccount(new Account("YourPrivateKey")); +- * +- * // Create the bonding transaction +- * const tx_id = await programManager.claimUnbondPublic(); +- * +- * @returns string +- * @param {Options} options +- */ +- async buildClaimUnbondPublicTransaction(options = {}) { +- const { offlineParams = {}, executionParams = {} } = options || {}; +- let { programName = "credits.aleo", functionName = "claim_unbond_public", fee = executionParams?.fee || 2, privateFee = false, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey } = executionParams; +- if (keySearchParams === undefined) { +- keySearchParams = new AleoKeyProviderParams({ +- proverUri: CREDITS_PROGRAM_KEYS.claim_unbond_public.prover, +- verifierUri: CREDITS_PROGRAM_KEYS.claim_unbond_public.verifier, +- cacheKey: "credits.aleo/claim_unbond_public" +- }); +- } +- const { offlineQuery, } = offlineParams; +- return await this.buildExecutionTransaction(programName, functionName, fee, privateFee, [], recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery, this.creditsProgram()); +- } +- /** +- * Claim unbonded credits. If credits have been unbonded by the account executing this function, this method will +- * claim them and add them to the public balance of the account. +- * +- * @example +- * // Create a keyProvider to handle key management +- * const keyProvider = new AleoKeyProvider(); +- * keyProvider.useCache = true; +- * +- * // Create a new ProgramManager with the key that will be used to bond credits +- * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, undefined); +- * programManager.setAccount(new Account("YourPrivateKey")); +- * +- * // Create the bonding transaction +- * const tx_id = await programManager.claimUnbondPublic(); +- * +- * @returns string +- * @param {Options} options +- */ +- async claimUnbondPublic(options = {}) { +- const tx = await this.buildClaimUnbondPublicTransaction(options); +- return await this.networkClient.submitTransaction(tx); +- } +- /** +- * Set Validator State +- * @returns string +- * @param {boolean} validator_state +- * @param options +- */ +- async setValidatorState(validator_state, options = {}) { +- const { offlineParams = {}, executionParams = {} } = options || {}; +- let { programName = "credits.aleo", functionName = "set_validator_state", fee = 1, privateFee = false, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey } = executionParams; +- if (keySearchParams === undefined) { +- keySearchParams = new AleoKeyProviderParams({ +- proverUri: CREDITS_PROGRAM_KEYS.set_validator_state.prover, +- verifierUri: CREDITS_PROGRAM_KEYS.set_validator_state.verifier, +- cacheKey: "credits.aleo/set_validator_state" +- }); +- } +- const { offlineQuery, } = offlineParams; +- return await this.execute(programName, functionName, fee, privateFee, [validator_state.toString()], recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery); +- } +- /** +- * Unbond Delegator As Validator +- * @returns string +- * @param {string} address +- * @param options +- */ +- async unbondDelegatorAsValidator(address, options = {}) { +- const { offlineParams = {}, executionParams = {} } = options || {}; +- let { programName = "credits.aleo", functionName = "unbond_delegator_as_validator", fee = 1, privateFee = false, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey } = executionParams; +- if (keySearchParams === undefined) { +- keySearchParams = new AleoKeyProviderParams({ +- proverUri: CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.prover, +- verifierUri: CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.verifier, +- cacheKey: "credits.aleo/unbond_delegator_as_validator" +- }); +- } +- const { offlineQuery, } = offlineParams; +- return await this.execute(programName, functionName, fee, privateFee, [address], recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery); +- } +- /** +- * Verify a proof of execution from an offline execution +- * +- * @param {executionResponse} executionResponse +- * @returns {boolean} True if the proof is valid, false otherwise +- */ +- verifyExecution(executionResponse) { +- try { +- const execution = executionResponse.getExecution(); +- const function_id = executionResponse.getFunctionId(); +- const program = executionResponse.getProgram(); +- const verifyingKey = executionResponse.getVerifyingKey(); +- return verifyFunctionExecution(execution, verifyingKey, program, function_id); +- } +- catch (e) { +- console.warn("The execution was not found in the response, cannot verify the execution"); +- return false; +- } +- } +- /** +- * Create a program object from a program's source code +- * +- * @param {string} program Program source code +- * @returns {Program | Error} The program object +- */ +- createProgramFromSource(program) { +- return Program.fromString(program); +- } +- /** +- * Get the credits program object +- * +- * @returns {Program} The credits program object +- */ +- creditsProgram() { +- return Program.getCreditsProgram(); +- } +- /** +- * Verify a program is valid +- * +- * @param {string} program The program source code +- */ +- verifyProgram(program) { +- try { +- Program.fromString(program); +- return true; +- } +- catch (e) { +- return false; +- } +- } +- // Internal utility function for getting a credits.aleo record +- async getCreditsRecord(amount, nonces, record, params) { +- try { +- return record instanceof RecordPlaintext ? record : RecordPlaintext.fromString(record); +- } +- catch (e) { +- try { +- const recordProvider = this.recordProvider; +- return (await recordProvider.findCreditsRecord(amount, true, nonces, params)); +- } +- catch (e) { +- throw logAndThrow(`Error finding fee record. Record finder response: '${e}'. Please ensure you're connected to a valid Aleo network and a record with enough balance exists.`); +- } +- } +- } ++ account; ++ keyProvider; ++ host; ++ networkClient; ++ recordProvider; ++ /** Create a new instance of the ProgramManager ++ * ++ * @param { string | undefined } host A host uri running the official Aleo API ++ * @param { FunctionKeyProvider | undefined } keyProvider A key provider that implements {@link FunctionKeyProvider} interface ++ * @param { RecordProvider | undefined } recordProvider A record provider that implements {@link RecordProvider} interface ++ */ ++ constructor(host, keyProvider, recordProvider) { ++ if (!host) { ++ this.host = "https://api.explorer.aleo.org/v1"; ++ this.networkClient = new AleoNetworkClient(this.host); ++ } ++ else { ++ this.host = host; ++ this.networkClient = new AleoNetworkClient(host); ++ } ++ if (!keyProvider) { ++ this.keyProvider = new AleoKeyProvider(); ++ } ++ else { ++ this.keyProvider = keyProvider; ++ } ++ this.recordProvider = recordProvider; ++ } ++ /** ++ * Set the account to use for transaction submission to the Aleo network ++ * ++ * @param {Account} account Account to use for transaction submission ++ */ ++ setAccount(account) { ++ this.account = account; ++ } ++ /** ++ * Set the key provider that provides the proving and verifying keys for programs ++ * ++ * @param {FunctionKeyProvider} keyProvider ++ */ ++ setKeyProvider(keyProvider) { ++ this.keyProvider = keyProvider; ++ } ++ /** ++ * Set the host peer to use for transaction submission to the Aleo network ++ * ++ * @param host {string} Peer url to use for transaction submission ++ */ ++ setHost(host) { ++ this.host = host; ++ this.networkClient.setHost(host); ++ } ++ /** ++ * Set the record provider that provides records for transactions ++ * ++ * @param {RecordProvider} recordProvider ++ */ ++ setRecordProvider(recordProvider) { ++ this.recordProvider = recordProvider; ++ } ++ /** ++ * Deploy an Aleo program to the Aleo network ++ * ++ * @param {string} program Program source code ++ * @param {number} fee Fee to pay for the transaction ++ * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance ++ * @param {RecordSearchParams | undefined} recordSearchParams Optional parameters for searching for a record to use ++ * pay the deployment fee ++ * @param {string | RecordPlaintext | undefined} feeRecord Optional Fee record to use for the transaction ++ * @param {PrivateKey | undefined} privateKey Optional private key to use for the transaction ++ * @returns {string | Error} The transaction id of the deployed program or a failure message from the network ++ * ++ * @example ++ * // Create a new NetworkClient, KeyProvider, and RecordProvider ++ * const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1"); ++ * const keyProvider = new AleoKeyProvider(); ++ * const recordProvider = new NetworkRecordProvider(account, networkClient); ++ * ++ * // Initialize a program manager with the key provider to automatically fetch keys for deployments ++ * const program = "program hello_hello.aleo;\n\nfunction hello:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n"; ++ * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, recordProvider); ++ * ++ * // Define a fee in credits ++ * const fee = 1.2; ++ * ++ * // Deploy the program ++ * const tx_id = await programManager.deploy(program, fee); ++ * ++ * // Verify the transaction was successful ++ * const transaction = await programManager.networkClient.getTransaction(tx_id); ++ */ ++ async deploy(program, fee, privateFee, recordSearchParams, feeRecord, privateKey) { ++ // Ensure the program is valid and does not exist on the network ++ try { ++ const programObject = Program.fromString(program); ++ let programSource; ++ try { ++ programSource = await this.networkClient.getProgram(programObject.id()); ++ } ++ catch (e) { ++ // Program does not exist on the network, deployment can proceed ++ console.log(`Program ${programObject.id()} does not exist on the network, deploying...`); ++ } ++ if (typeof programSource == "string") { ++ throw (`Program ${programObject.id()} already exists on the network, please rename your program`); ++ } ++ } ++ catch (e) { ++ throw logAndThrow(`Error validating program: ${e}`); ++ } ++ // Get the private key from the account if it is not provided in the parameters ++ let deploymentPrivateKey = privateKey; ++ if (typeof privateKey === "undefined" && typeof this.account !== "undefined") { ++ deploymentPrivateKey = this.account.privateKey(); ++ } ++ if (typeof deploymentPrivateKey === "undefined") { ++ throw ("No private key provided and no private key set in the ProgramManager"); ++ } ++ // Get the fee record from the account if it is not provided in the parameters ++ try { ++ feeRecord = privateFee ? await this.getCreditsRecord(fee, [], feeRecord, recordSearchParams) : undefined; ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding fee record. Record finder response: '${e}'. Please ensure you're connected to a valid Aleo network and a record with enough balance exists.`); ++ } ++ // Get the proving and verifying keys from the key provider ++ let feeKeys; ++ try { ++ feeKeys = privateFee ? await this.keyProvider.feePrivateKeys() : await this.keyProvider.feePublicKeys(); ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding fee keys. Key finder response: '${e}'. Please ensure your key provider is configured correctly.`); ++ } ++ const [feeProvingKey, feeVerifyingKey] = feeKeys; ++ // Resolve the program imports if they exist ++ let imports; ++ try { ++ imports = await this.networkClient.getProgramImports(program); ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding program imports. Network response: '${e}'. Please ensure you're connected to a valid Aleo network and the program is deployed to the network.`); ++ } ++ // Build a deployment transaction and submit it to the network ++ const tx = await ProgramManager$1.buildDeploymentTransaction(deploymentPrivateKey, program, fee, feeRecord, this.host, imports, feeProvingKey, feeVerifyingKey); ++ return await this.networkClient.submitTransaction(tx); ++ } ++ /** ++ * Build an execution transaction for later submission to the Aleo network. ++ * ++ * @param {string} programName Program name containing the function to be executed ++ * @param {string} functionName Function name to execute ++ * @param {number} fee Fee to pay for the transaction ++ * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance ++ * @param {string[]} inputs Inputs to the function ++ * @param {RecordSearchParams} recordSearchParams Optional parameters for searching for a record to pay the fee for ++ * the execution transaction ++ * @param {KeySearchParams} keySearchParams Optional parameters for finding the matching proving & verifying keys ++ * for the function ++ * @param {string | RecordPlaintext | undefined} feeRecord Optional Fee record to use for the transaction ++ * @param {ProvingKey | undefined} provingKey Optional proving key to use for the transaction ++ * @param {VerifyingKey | undefined} verifyingKey Optional verifying key to use for the transaction ++ * @param {PrivateKey | undefined} privateKey Optional private key to use for the transaction ++ * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment ++ * @param {string | Program | undefined} program Optional program source code to use for the transaction ++ * @param {ProgramImports} imports Programs that the program being executed imports ++ * @returns {Promise} ++ * ++ * @example ++ * // Create a new NetworkClient, KeyProvider, and RecordProvider using official Aleo record, key, and network providers ++ * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); ++ * const keyProvider = new AleoKeyProvider(); ++ * keyProvider.useCache = true; ++ * const recordProvider = new NetworkRecordProvider(account, networkClient); ++ * ++ * // Initialize a program manager with the key provider to automatically fetch keys for executions ++ * const programName = "hello_hello.aleo"; ++ * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); ++ * const keySearchParams = { "cacheKey": "hello_hello:hello" }; ++ * const transaction = await programManager.execute(programName, "hello_hello", 0.020, ["5u32", "5u32"], undefined, undefined, undefined, keySearchParams); ++ * const result = await programManager.networkClient.submitTransaction(transaction); ++ */ ++ async buildExecutionTransaction(programName, functionName, fee, privateFee, inputs, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery, program, imports) { ++ // Ensure the function exists on the network ++ if (program === undefined) { ++ try { ++ program = (await this.networkClient.getProgram(programName)); ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding ${programName}. Network response: '${e}'. Please ensure you're connected to a valid Aleo network the program is deployed to the network.`); ++ } ++ } ++ else if (program instanceof Program) { ++ program = program.toString(); ++ } ++ // Get the private key from the account if it is not provided in the parameters ++ let executionPrivateKey = privateKey; ++ if (typeof privateKey === "undefined" && typeof this.account !== "undefined") { ++ executionPrivateKey = this.account.privateKey(); ++ } ++ if (typeof executionPrivateKey === "undefined") { ++ throw ("No private key provided and no private key set in the ProgramManager"); ++ } ++ // Get the fee record from the account if it is not provided in the parameters ++ try { ++ feeRecord = privateFee ? await this.getCreditsRecord(fee, [], feeRecord, recordSearchParams) : undefined; ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding fee record. Record finder response: '${e}'. Please ensure you're connected to a valid Aleo network and a record with enough balance exists.`); ++ } ++ // Get the fee proving and verifying keys from the key provider ++ let feeKeys; ++ try { ++ feeKeys = privateFee ? await this.keyProvider.feePrivateKeys() : await this.keyProvider.feePublicKeys(); ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding fee keys. Key finder response: '${e}'. Please ensure your key provider is configured correctly.`); ++ } ++ const [feeProvingKey, feeVerifyingKey] = feeKeys; ++ // If the function proving and verifying keys are not provided, attempt to find them using the key provider ++ if (!provingKey || !verifyingKey) { ++ try { ++ [provingKey, verifyingKey] = await this.keyProvider.functionKeys(keySearchParams); ++ } ++ catch (e) { ++ console.log(`Function keys not found. Key finder response: '${e}'. The function keys will be synthesized`); ++ } ++ } ++ // Resolve the program imports if they exist ++ const numberOfImports = Program.fromString(program).getImports().length; ++ if (numberOfImports > 0 && !imports) { ++ try { ++ imports = await this.networkClient.getProgramImports(programName); ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding program imports. Network response: '${e}'. Please ensure you're connected to a valid Aleo network and the program is deployed to the network.`); ++ } ++ } ++ // Build an execution transaction and submit it to the network ++ return await ProgramManager$1.buildExecutionTransaction(executionPrivateKey, program, functionName, inputs, fee, feeRecord, this.host, imports, provingKey, verifyingKey, feeProvingKey, feeVerifyingKey, offlineQuery); ++ } ++ /** ++ * Execute an Aleo program on the Aleo network ++ * ++ * @param {string} programName Program name containing the function to be executed ++ * @param {string} functionName Function name to execute ++ * @param {number} fee Fee to pay for the transaction ++ * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance ++ * @param {string[]} inputs Inputs to the function ++ * @param {RecordSearchParams} recordSearchParams Optional parameters for searching for a record to pay the fee for ++ * the execution transaction ++ * @param {KeySearchParams} keySearchParams Optional parameters for finding the matching proving & verifying keys ++ * for the function ++ * @param {string | RecordPlaintext | undefined} feeRecord Optional Fee record to use for the transaction ++ * @param {ProvingKey | undefined} provingKey Optional proving key to use for the transaction ++ * @param {VerifyingKey | undefined} verifyingKey Optional verifying key to use for the transaction ++ * @param {PrivateKey | undefined} privateKey Optional private key to use for the transaction ++ * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment ++ * @returns {Promise} ++ * ++ * @example ++ * // Create a new NetworkClient, KeyProvider, and RecordProvider using official Aleo record, key, and network providers ++ * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); ++ * const keyProvider = new AleoKeyProvider(); ++ * keyProvider.useCache = true; ++ * const recordProvider = new NetworkRecordProvider(account, networkClient); ++ * ++ * // Initialize a program manager with the key provider to automatically fetch keys for executions ++ * const programName = "hello_hello.aleo"; ++ * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); ++ * const keySearchParams = { "cacheKey": "hello_hello:hello" }; ++ * const tx_id = await programManager.execute(programName, "hello_hello", 0.020, ["5u32", "5u32"], undefined, undefined, undefined, keySearchParams); ++ * const transaction = await programManager.networkClient.getTransaction(tx_id); ++ */ ++ async execute(programName, functionName, fee, privateFee, inputs, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery, program) { ++ const tx = await this.buildExecutionTransaction(programName, functionName, fee, privateFee, inputs, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery, program); ++ return await this.networkClient.submitTransaction(tx); ++ } ++ /** ++ * Run an Aleo program in offline mode ++ * ++ * @param {string} program Program source code containing the function to be executed ++ * @param {string} function_name Function name to execute ++ * @param {string[]} inputs Inputs to the function ++ * @param {number} proveExecution Whether to prove the execution of the function and return an execution transcript ++ * that contains the proof. ++ * @param {string[] | undefined} imports Optional imports to the program ++ * @param {KeySearchParams | undefined} keySearchParams Optional parameters for finding the matching proving & ++ * verifying keys for the function ++ * @param {ProvingKey | undefined} provingKey Optional proving key to use for the transaction ++ * @param {VerifyingKey | undefined} verifyingKey Optional verifying key to use for the transaction ++ * @param {PrivateKey | undefined} privateKey Optional private key to use for the transaction ++ * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment ++ * @returns {Promise} ++ * ++ * @example ++ * import { Account, Program } from '@aleohq/sdk'; ++ * ++ * /// Create the source for the "helloworld" program ++ * const program = "program helloworld.aleo;\n\nfunction hello:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n"; ++ * const programManager = new ProgramManager(); ++ * ++ * /// Create a temporary account for the execution of the program ++ * const account = new Account(); ++ * programManager.setAccount(account); ++ * ++ * /// Get the response and ensure that the program executed correctly ++ * const executionResponse = await programManager.executeOffline(program, "hello", ["5u32", "5u32"]); ++ * const result = executionResponse.getOutputs(); ++ * assert(result === ["10u32"]); ++ */ ++ async run(program, function_name, inputs, proveExecution, imports, keySearchParams, provingKey, verifyingKey, privateKey, offlineQuery) { ++ // Get the private key from the account if it is not provided in the parameters ++ let executionPrivateKey = privateKey; ++ if (typeof privateKey === "undefined" && typeof this.account !== "undefined") { ++ executionPrivateKey = this.account.privateKey(); ++ } ++ if (typeof executionPrivateKey === "undefined") { ++ throw ("No private key provided and no private key set in the ProgramManager"); ++ } ++ // If the function proving and verifying keys are not provided, attempt to find them using the key provider ++ if (!provingKey || !verifyingKey) { ++ try { ++ [provingKey, verifyingKey] = await this.keyProvider.functionKeys(keySearchParams); ++ } ++ catch (e) { ++ console.log(`Function keys not found. Key finder response: '${e}'. The function keys will be synthesized`); ++ } ++ } ++ // Run the program offline and return the result ++ return ProgramManager$1.executeFunctionOffline(executionPrivateKey, program, function_name, inputs, proveExecution, false, imports, provingKey, verifyingKey, this.host, offlineQuery); ++ } ++ /** ++ * Join two credits records into a single credits record ++ * ++ * @param {RecordPlaintext | string} recordOne First credits record to join ++ * @param {RecordPlaintext | string} recordTwo Second credits record to join ++ * @param {number} fee Fee in credits pay for the join transaction ++ * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance ++ * @param {RecordSearchParams | undefined} recordSearchParams Optional parameters for finding the fee record to use ++ * to pay the fee for the join transaction ++ * @param {RecordPlaintext | string | undefined} feeRecord Fee record to use for the join transaction ++ * @param {PrivateKey | undefined} privateKey Private key to use for the join transaction ++ * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment ++ * @returns {Promise} ++ */ ++ async join(recordOne, recordTwo, fee, privateFee, recordSearchParams, feeRecord, privateKey, offlineQuery) { ++ // Get the private key from the account if it is not provided in the parameters ++ let executionPrivateKey = privateKey; ++ if (typeof privateKey === "undefined" && typeof this.account !== "undefined") { ++ executionPrivateKey = this.account.privateKey(); ++ } ++ if (typeof executionPrivateKey === "undefined") { ++ throw ("No private key provided and no private key set in the ProgramManager"); ++ } ++ // Get the proving and verifying keys from the key provider ++ let feeKeys; ++ let joinKeys; ++ try { ++ feeKeys = privateFee ? await this.keyProvider.feePrivateKeys() : await this.keyProvider.feePublicKeys(); ++ joinKeys = await this.keyProvider.joinKeys(); ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding fee keys. Key finder response: '${e}'. Please ensure your key provider is configured correctly.`); ++ } ++ const [feeProvingKey, feeVerifyingKey] = feeKeys; ++ const [joinProvingKey, joinVerifyingKey] = joinKeys; ++ // Get the fee record from the account if it is not provided in the parameters ++ try { ++ feeRecord = privateFee ? await this.getCreditsRecord(fee, [], feeRecord, recordSearchParams) : undefined; ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding fee record. Record finder response: '${e}'. Please ensure you're connected to a valid Aleo network and a record with enough balance exists.`); ++ } ++ // Validate the records provided are valid plaintext records ++ try { ++ recordOne = recordOne instanceof RecordPlaintext ? recordOne : RecordPlaintext.fromString(recordOne); ++ recordTwo = recordTwo instanceof RecordPlaintext ? recordTwo : RecordPlaintext.fromString(recordTwo); ++ } ++ catch (e) { ++ throw logAndThrow('Records provided are not valid. Please ensure they are valid plaintext records.'); ++ } ++ // Build an execution transaction and submit it to the network ++ const tx = await ProgramManager$1.buildJoinTransaction(executionPrivateKey, recordOne, recordTwo, fee, feeRecord, this.host, joinProvingKey, joinVerifyingKey, feeProvingKey, feeVerifyingKey, offlineQuery); ++ return await this.networkClient.submitTransaction(tx); ++ } ++ /** ++ * Split credits into two new credits records ++ * ++ * @param {number} splitAmount Amount in microcredits to split from the original credits record ++ * @param {RecordPlaintext | string} amountRecord Amount record to use for the split transaction ++ * @param {PrivateKey | undefined} privateKey Optional private key to use for the split transaction ++ * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment ++ * @returns {Promise} ++ * ++ * @example ++ * // Create a new NetworkClient, KeyProvider, and RecordProvider ++ * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); ++ * const keyProvider = new AleoKeyProvider(); ++ * const recordProvider = new NetworkRecordProvider(account, networkClient); ++ * ++ * // Initialize a program manager with the key provider to automatically fetch keys for executions ++ * const programName = "hello_hello.aleo"; ++ * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); ++ * const record = "{ owner: aleo184vuwr5u7u0ha5f5k44067dd2uaqewxx6pe5ltha5pv99wvhfqxqv339h4.private, microcredits: 45000000u64.private, _nonce: 4106205762862305308495708971985748592380064201230396559307556388725936304984group.public}" ++ * const tx_id = await programManager.split(25000000, record); ++ * const transaction = await programManager.networkClient.getTransaction(tx_id); ++ */ ++ async split(splitAmount, amountRecord, privateKey, offlineQuery) { ++ // Get the private key from the account if it is not provided in the parameters ++ let executionPrivateKey = privateKey; ++ if (typeof executionPrivateKey === "undefined" && typeof this.account !== "undefined") { ++ executionPrivateKey = this.account.privateKey(); ++ } ++ if (typeof executionPrivateKey === "undefined") { ++ throw ("No private key provided and no private key set in the ProgramManager"); ++ } ++ // Get the split keys from the key provider ++ let splitKeys; ++ try { ++ splitKeys = await this.keyProvider.splitKeys(); ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding fee keys. Key finder response: '${e}'. Please ensure your key provider is configured correctly.`); ++ } ++ const [splitProvingKey, splitVerifyingKey] = splitKeys; ++ // Validate the record to be split ++ try { ++ amountRecord = amountRecord instanceof RecordPlaintext ? amountRecord : RecordPlaintext.fromString(amountRecord); ++ } ++ catch (e) { ++ throw logAndThrow("Record provided is not valid. Please ensure it is a valid plaintext record."); ++ } ++ // Build an execution transaction and submit it to the network ++ const tx = await ProgramManager$1.buildSplitTransaction(executionPrivateKey, splitAmount, amountRecord, this.host, splitProvingKey, splitVerifyingKey, offlineQuery); ++ return await this.networkClient.submitTransaction(tx); ++ } ++ /** ++ * Pre-synthesize proving and verifying keys for a program ++ * ++ * @param program {string} The program source code to synthesize keys for ++ * @param function_id {string} The function id to synthesize keys for ++ * @param inputs {Array} Sample inputs to the function ++ * @param privateKey {PrivateKey | undefined} Optional private key to use for the key synthesis ++ * ++ * @returns {Promise} ++ */ ++ ++ async synthesizeKeys(program, function_id, inputs, privateKey) { ++ // Resolve the program imports if they exist ++ let imports; ++ let executionPrivateKey = privateKey; ++ if (typeof executionPrivateKey === "undefined") { ++ if (typeof this.account !== "undefined") { ++ executionPrivateKey = this.account.privateKey(); ++ } ++ else { ++ executionPrivateKey = new PrivateKey(); ++ } ++ } ++ // Attempt to run an offline execution of the program and extract the proving and verifying keys ++ try { ++ imports = await this.networkClient.getProgramImports(program); ++ const keyPair = await ProgramManager$1.synthesizeKeyPair(executionPrivateKey, program, function_id, inputs, imports); ++ return [keyPair.provingKey(), keyPair.verifyingKey()]; ++ } ++ catch (e) { ++ throw logAndThrow(`Could not synthesize keys - error ${e}. Please ensure the program is valid and the inputs are correct.`); ++ } ++ } ++ /** ++ * Build a transaction to transfer credits to another account for later submission to the Aleo network ++ * ++ * @param {number} amount The amount of credits to transfer ++ * @param {string} recipient The recipient of the transfer ++ * @param {string} transferType The type of transfer to perform - options: 'private', 'privateToPublic', 'public', 'publicToPrivate' ++ * @param {number} fee The fee to pay for the transfer ++ * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance ++ * @param {RecordSearchParams | undefined} recordSearchParams Optional parameters for finding the amount and fee ++ * records for the transfer transaction ++ * @param {RecordPlaintext | string} amountRecord Optional amount record to use for the transfer ++ * @param {RecordPlaintext | string} feeRecord Optional fee record to use for the transfer ++ * @param {PrivateKey | undefined} privateKey Optional private key to use for the transfer transaction ++ * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment ++ * @returns {Promise} The transaction id of the transfer transaction ++ * ++ * @example ++ * // Create a new NetworkClient, KeyProvider, and RecordProvider ++ * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); ++ * const keyProvider = new AleoKeyProvider(); ++ * const recordProvider = new NetworkRecordProvider(account, networkClient); ++ * ++ * // Initialize a program manager with the key provider to automatically fetch keys for executions ++ * const programName = "hello_hello.aleo"; ++ * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); ++ * await programManager.initialize(); ++ * const tx_id = await programManager.transfer(1, "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px", "private", 0.2) ++ * const transaction = await programManager.networkClient.getTransaction(tx_id); ++ */ ++ async buildTransferTransaction(amount, recipient, transferType, fee, privateFee, recordSearchParams, amountRecord, feeRecord, privateKey, offlineQuery) { ++ // Validate the transfer type ++ transferType = validateTransferType(transferType); ++ // Get the private key from the account if it is not provided in the parameters ++ let executionPrivateKey = privateKey; ++ if (typeof executionPrivateKey === "undefined" && typeof this.account !== "undefined") { ++ executionPrivateKey = this.account.privateKey(); ++ } ++ if (typeof executionPrivateKey === "undefined") { ++ throw ("No private key provided and no private key set in the ProgramManager"); ++ } ++ // Get the proving and verifying keys from the key provider ++ let feeKeys; ++ let transferKeys; ++ try { ++ feeKeys = privateFee ? await this.keyProvider.feePrivateKeys() : await this.keyProvider.feePublicKeys(); ++ transferKeys = await this.keyProvider.transferKeys(transferType); ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding fee keys. Key finder response: '${e}'. Please ensure your key provider is configured correctly.`); ++ } ++ const [feeProvingKey, feeVerifyingKey] = feeKeys; ++ const [transferProvingKey, transferVerifyingKey] = transferKeys; ++ // Get the amount and fee record from the account if it is not provided in the parameters ++ try { ++ // Track the nonces of the records found so no duplicate records are used ++ const nonces = []; ++ if (requiresAmountRecord(transferType)) { ++ // If the transfer type is private and requires an amount record, get it from the record provider ++ amountRecord = await this.getCreditsRecord(fee, [], amountRecord, recordSearchParams); ++ nonces.push(amountRecord.nonce()); ++ } ++ else { ++ amountRecord = undefined; ++ } ++ feeRecord = privateFee ? await this.getCreditsRecord(fee, nonces, feeRecord, recordSearchParams) : undefined; ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding fee record. Record finder response: '${e}'. Please ensure you're connected to a valid Aleo network and a record with enough balance exists.`); ++ } ++ // Build an execution transaction and submit it to the network ++ return await ProgramManager$1.buildTransferTransaction(executionPrivateKey, amount, recipient, transferType, amountRecord, fee, feeRecord, this.host, transferProvingKey, transferVerifyingKey, feeProvingKey, feeVerifyingKey, offlineQuery); ++ } ++ /** ++ * Build a transfer_public transaction to transfer credits to another account for later submission to the Aleo network ++ * ++ * @param {number} amount The amount of credits to transfer ++ * @param {string} recipient The recipient of the transfer ++ * @param {string} transferType The type of transfer to perform - options: 'private', 'privateToPublic', 'public', 'publicToPrivate' ++ * @param {number} fee The fee to pay for the transfer ++ * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance ++ * @param {RecordSearchParams | undefined} recordSearchParams Optional parameters for finding the amount and fee ++ * records for the transfer transaction ++ * @param {RecordPlaintext | string} amountRecord Optional amount record to use for the transfer ++ * @param {RecordPlaintext | string} feeRecord Optional fee record to use for the transfer ++ * @param {PrivateKey | undefined} privateKey Optional private key to use for the transfer transaction ++ * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment ++ * @returns {Promise} The transaction id of the transfer transaction ++ * ++ * @example ++ * // Create a new NetworkClient, KeyProvider, and RecordProvider ++ * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); ++ * const keyProvider = new AleoKeyProvider(); ++ * const recordProvider = new NetworkRecordProvider(account, networkClient); ++ * ++ * // Initialize a program manager with the key provider to automatically fetch keys for executions ++ * const programName = "hello_hello.aleo"; ++ * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); ++ * await programManager.initialize(); ++ * const tx_id = await programManager.transfer(1, "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px", "private", 0.2) ++ * const transaction = await programManager.networkClient.getTransaction(tx_id); ++ */ ++ async buildTransferPublicTransaction(amount, recipient, fee, privateKey, offlineQuery) { ++ return this.buildTransferTransaction(amount, recipient, "public", fee, false, undefined, undefined, undefined, privateKey, offlineQuery); ++ } ++ /** ++ * Transfer credits to another account ++ * ++ * @param {number} amount The amount of credits to transfer ++ * @param {string} recipient The recipient of the transfer ++ * @param {string} transferType The type of transfer to perform - options: 'private', 'privateToPublic', 'public', 'publicToPrivate' ++ * @param {number} fee The fee to pay for the transfer ++ * @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance ++ * @param {RecordSearchParams | undefined} recordSearchParams Optional parameters for finding the amount and fee ++ * records for the transfer transaction ++ * @param {RecordPlaintext | string} amountRecord Optional amount record to use for the transfer ++ * @param {RecordPlaintext | string} feeRecord Optional fee record to use for the transfer ++ * @param {PrivateKey | undefined} privateKey Optional private key to use for the transfer transaction ++ * @param {OfflineQuery | undefined} offlineQuery Optional offline query if creating transactions in an offline environment ++ * @returns {Promise} The transaction id of the transfer transaction ++ * ++ * @example ++ * // Create a new NetworkClient, KeyProvider, and RecordProvider ++ * const networkClient = new AleoNetworkClient("https://vm.aleo.org/api"); ++ * const keyProvider = new AleoKeyProvider(); ++ * const recordProvider = new NetworkRecordProvider(account, networkClient); ++ * ++ * // Initialize a program manager with the key provider to automatically fetch keys for executions ++ * const programName = "hello_hello.aleo"; ++ * const programManager = new ProgramManager("https://vm.aleo.org/api", keyProvider, recordProvider); ++ * await programManager.initialize(); ++ * const tx_id = await programManager.transfer(1, "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px", "private", 0.2) ++ * const transaction = await programManager.networkClient.getTransaction(tx_id); ++ */ ++ async transfer(amount, recipient, transferType, fee, privateFee, recordSearchParams, amountRecord, feeRecord, privateKey, offlineQuery) { ++ const tx = await this.buildTransferTransaction(amount, recipient, transferType, fee, privateFee, recordSearchParams, amountRecord, feeRecord, privateKey, offlineQuery); ++ return await this.networkClient.submitTransaction(tx); ++ } ++ /** ++ * Build transaction to bond credits to a staking committee for later submission to the Aleo Network ++ * ++ * @example ++ * // Create a keyProvider to handle key management ++ * const keyProvider = new AleoKeyProvider(); ++ * keyProvider.useCache = true; ++ * ++ * // Create a new ProgramManager with the key that will be used to bond credits ++ * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, undefined); ++ * programManager.setAccount(new Account("YourPrivateKey")); ++ * ++ * // Create the bonding transaction ++ * const tx_id = await programManager.bondPublic("aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px", 2000000); ++ * ++ * @returns string ++ * @param {string} address Address of the validator to bond to, if this address is the same as the signer (i.e. the ++ * executor of this function), it will attempt to bond the credits as a validator. Bonding as a validator currently ++ * requires a minimum of 1,000,000 credits to bond (subject to change). If the address is specified is an existing ++ * validator and is different from the address of the executor of this function, it will bond the credits to that ++ * validator's staking committee as a delegator. A minimum of 10 credits is required to bond as a delegator. ++ * @param {number} amount The amount of credits to bond ++ * @param {Options} options Options for the execution ++ */ ++ async buildBondPublicTransaction(address, amount, options = {}) { ++ amount = Math.trunc(amount * 1000000); ++ const { offlineParams = {}, executionParams = {} } = options || {}; ++ let { programName = "credits.aleo", functionName = "bond_public", fee = executionParams?.fee || 0.86, privateFee = false, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey } = executionParams; ++ if (keySearchParams === undefined) { ++ keySearchParams = new AleoKeyProviderParams({ ++ proverUri: CREDITS_PROGRAM_KEYS.bond_public.prover, ++ verifierUri: CREDITS_PROGRAM_KEYS.bond_public.verifier, ++ cacheKey: "credits.aleo/bond_public" ++ }); ++ } ++ const { offlineQuery, } = offlineParams; ++ return await this.buildExecutionTransaction(programName, functionName, fee, privateFee, [address, `${amount.toString()}u64`], recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery, this.creditsProgram()); ++ } ++ /** ++ * Bond credits to a staking committee ++ * ++ * @example ++ * // Create a keyProvider to handle key management ++ * const keyProvider = new AleoKeyProvider(); ++ * keyProvider.useCache = true; ++ * ++ * // Create a new ProgramManager with the key that will be used to bond credits ++ * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, undefined); ++ * programManager.setAccount(new Account("YourPrivateKey")); ++ * ++ * // Create the bonding transaction ++ * const tx_id = await programManager.bondPublic("aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px", 2000000); ++ * ++ * @returns string ++ * @param {string} address Address of the validator to bond to, if this address is the same as the signer (i.e. the ++ * executor of this function), it will attempt to bond the credits as a validator. Bonding as a validator currently ++ * requires a minimum of 1,000,000 credits to bond (subject to change). If the address is specified is an existing ++ * validator and is different from the address of the executor of this function, it will bond the credits to that ++ * validator's staking committee as a delegator. A minimum of 10 credits is required to bond as a delegator. ++ * @param {number} amount The amount of credits to bond ++ * @param {Options} options Options for the execution ++ */ ++ async bondPublic(address, amount, options = {}) { ++ const tx = await this.buildBondPublicTransaction(address, amount, options); ++ return await this.networkClient.submitTransaction(tx); ++ } ++ /** ++ * Build a transaction to unbond a specified amount of staked credits to be used later ++ * ++ * @example ++ * // Create a keyProvider to handle key management ++ * const keyProvider = new AleoKeyProvider(); ++ * keyProvider.useCache = true; ++ * ++ * // Create a new ProgramManager with the key that will be used to bond credits ++ * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, undefined); ++ * programManager.setAccount(new Account("YourPrivateKey")); ++ * ++ * // Create the bonding transaction ++ * const tx_id = await programManager.unbondPublic(10); ++ * ++ * @returns string ++ * @param {number} amount Amount of credits to unbond. If the address of the executor of this function is an ++ * existing validator, it will subtract this amount of credits from the validator's staked credits. If there are ++ * less than 1,000,000 credits staked pool after the unbond, the validator will be removed from the validator set. ++ * If the address of the executor of this function is not a validator and has credits bonded as a delegator, it will ++ * subtract this amount of credits from the delegator's staked credits. If there are less than 10 credits bonded ++ * after the unbond operation, the delegator will be removed from the validator's staking pool. ++ * @param {Options} options Options for the execution ++ */ ++ async buildUnbondPublicTransaction(amount, options = {}) { ++ amount = Math.trunc(amount * 1000000); ++ const { offlineParams = {}, executionParams = {} } = options || {}; ++ let { programName = "credits.aleo", functionName = "unbond_public", fee = executionParams?.fee || 1.3, privateFee = false, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey } = executionParams; ++ if (keySearchParams === undefined) { ++ keySearchParams = new AleoKeyProviderParams({ ++ proverUri: CREDITS_PROGRAM_KEYS.unbond_public.prover, ++ verifierUri: CREDITS_PROGRAM_KEYS.unbond_public.verifier, ++ cacheKey: "credits.aleo/unbond_public" ++ }); ++ } ++ const { offlineQuery, } = offlineParams; ++ return this.buildExecutionTransaction(programName, functionName, fee, privateFee, [`${amount.toString()}u64`], recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery, this.creditsProgram()); ++ } ++ /** ++ * Unbond a specified amount of staked credits to be used later ++ * ++ * @example ++ * // Create a keyProvider to handle key management ++ * const keyProvider = new AleoKeyProvider(); ++ * keyProvider.useCache = true; ++ * ++ * // Create a new ProgramManager with the key that will be used to bond credits ++ * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, undefined); ++ * programManager.setAccount(new Account("YourPrivateKey")); ++ * ++ * // Create the bonding transaction ++ * const tx_id = await programManager.unbondPublic(10); ++ * ++ * @returns string ++ * @param {number} amount Amount of credits to unbond. If the address of the executor of this function is an ++ * existing validator, it will subtract this amount of credits from the validator's staked credits. If there are ++ * less than 1,000,000 credits staked pool after the unbond, the validator will be removed from the validator set. ++ * If the address of the executor of this function is not a validator and has credits bonded as a delegator, it will ++ * subtract this amount of credits from the delegator's staked credits. If there are less than 10 credits bonded ++ * after the unbond operation, the delegator will be removed from the validator's staking pool. ++ * @param {Options} options Options for the execution ++ */ ++ async unbondPublic(amount, options = {}) { ++ const tx = await this.buildUnbondPublicTransaction(amount, options); ++ return await this.networkClient.submitTransaction(tx); ++ } ++ /** ++ * Build a transaction to Claim unbonded credits for later submission. If credits have been unbonded by the account ++ * executing this function, this method will claim them and add them to the public balance of the account. ++ * ++ * @example ++ * // Create a keyProvider to handle key management ++ * const keyProvider = new AleoKeyProvider(); ++ * keyProvider.useCache = true; ++ * ++ * // Create a new ProgramManager with the key that will be used to bond credits ++ * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, undefined); ++ * programManager.setAccount(new Account("YourPrivateKey")); ++ * ++ * // Create the bonding transaction ++ * const tx_id = await programManager.claimUnbondPublic(); ++ * ++ * @returns string ++ * @param {Options} options ++ */ ++ async buildClaimUnbondPublicTransaction(options = {}) { ++ const { offlineParams = {}, executionParams = {} } = options || {}; ++ let { programName = "credits.aleo", functionName = "claim_unbond_public", fee = executionParams?.fee || 2, privateFee = false, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey } = executionParams; ++ if (keySearchParams === undefined) { ++ keySearchParams = new AleoKeyProviderParams({ ++ proverUri: CREDITS_PROGRAM_KEYS.claim_unbond_public.prover, ++ verifierUri: CREDITS_PROGRAM_KEYS.claim_unbond_public.verifier, ++ cacheKey: "credits.aleo/claim_unbond_public" ++ }); ++ } ++ const { offlineQuery, } = offlineParams; ++ return await this.buildExecutionTransaction(programName, functionName, fee, privateFee, [], recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery, this.creditsProgram()); ++ } ++ /** ++ * Claim unbonded credits. If credits have been unbonded by the account executing this function, this method will ++ * claim them and add them to the public balance of the account. ++ * ++ * @example ++ * // Create a keyProvider to handle key management ++ * const keyProvider = new AleoKeyProvider(); ++ * keyProvider.useCache = true; ++ * ++ * // Create a new ProgramManager with the key that will be used to bond credits ++ * const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, undefined); ++ * programManager.setAccount(new Account("YourPrivateKey")); ++ * ++ * // Create the bonding transaction ++ * const tx_id = await programManager.claimUnbondPublic(); ++ * ++ * @returns string ++ * @param {Options} options ++ */ ++ async claimUnbondPublic(options = {}) { ++ const tx = await this.buildClaimUnbondPublicTransaction(options); ++ return await this.networkClient.submitTransaction(tx); ++ } ++ /** ++ * Set Validator State ++ * @returns string ++ * @param {boolean} validator_state ++ * @param options ++ */ ++ async setValidatorState(validator_state, options = {}) { ++ const { offlineParams = {}, executionParams = {} } = options || {}; ++ let { programName = "credits.aleo", functionName = "set_validator_state", fee = 1, privateFee = false, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey } = executionParams; ++ if (keySearchParams === undefined) { ++ keySearchParams = new AleoKeyProviderParams({ ++ proverUri: CREDITS_PROGRAM_KEYS.set_validator_state.prover, ++ verifierUri: CREDITS_PROGRAM_KEYS.set_validator_state.verifier, ++ cacheKey: "credits.aleo/set_validator_state" ++ }); ++ } ++ const { offlineQuery, } = offlineParams; ++ return await this.execute(programName, functionName, fee, privateFee, [validator_state.toString()], recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery); ++ } ++ /** ++ * Unbond Delegator As Validator ++ * @returns string ++ * @param {string} address ++ * @param options ++ */ ++ async unbondDelegatorAsValidator(address, options = {}) { ++ const { offlineParams = {}, executionParams = {} } = options || {}; ++ let { programName = "credits.aleo", functionName = "unbond_delegator_as_validator", fee = 1, privateFee = false, recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey } = executionParams; ++ if (keySearchParams === undefined) { ++ keySearchParams = new AleoKeyProviderParams({ ++ proverUri: CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.prover, ++ verifierUri: CREDITS_PROGRAM_KEYS.unbond_delegator_as_validator.verifier, ++ cacheKey: "credits.aleo/unbond_delegator_as_validator" ++ }); ++ } ++ const { offlineQuery, } = offlineParams; ++ return await this.execute(programName, functionName, fee, privateFee, [address], recordSearchParams, keySearchParams, feeRecord, provingKey, verifyingKey, privateKey, offlineQuery); ++ } ++ /** ++ * Verify a proof of execution from an offline execution ++ * ++ * @param {executionResponse} executionResponse ++ * @returns {boolean} True if the proof is valid, false otherwise ++ */ ++ verifyExecution(executionResponse) { ++ try { ++ const execution = executionResponse.getExecution(); ++ const function_id = executionResponse.getFunctionId(); ++ const program = executionResponse.getProgram(); ++ const verifyingKey = executionResponse.getVerifyingKey(); ++ return verifyFunctionExecution(execution, verifyingKey, program, function_id); ++ } ++ catch (e) { ++ console.warn("The execution was not found in the response, cannot verify the execution"); ++ return false; ++ } ++ } ++ /** ++ * Create a program object from a program's source code ++ * ++ * @param {string} program Program source code ++ * @returns {Program | Error} The program object ++ */ ++ createProgramFromSource(program) { ++ return Program.fromString(program); ++ } ++ /** ++ * Get the credits program object ++ * ++ * @returns {Program} The credits program object ++ */ ++ creditsProgram() { ++ return Program.getCreditsProgram(); ++ } ++ /** ++ * Verify a program is valid ++ * ++ * @param {string} program The program source code ++ */ ++ verifyProgram(program) { ++ try { ++ Program.fromString(program); ++ return true; ++ } ++ catch (e) { ++ return false; ++ } ++ } ++ // Internal utility function for getting a credits.aleo record ++ async getCreditsRecord(amount, nonces, record, params) { ++ try { ++ return record instanceof RecordPlaintext ? record : RecordPlaintext.fromString(record); ++ } ++ catch (e) { ++ try { ++ const recordProvider = this.recordProvider; ++ return (await recordProvider.findCreditsRecord(amount, true, nonces, params)); ++ } ++ catch (e) { ++ throw logAndThrow(`Error finding fee record. Record finder response: '${e}'. Please ensure you're connected to a valid Aleo network and a record with enough balance exists.`); ++ } ++ } ++ } + } + // Ensure the transfer type requires an amount record + function requiresAmountRecord(transferType) { +- return PRIVATE_TRANSFER_TYPES.has(transferType); ++ return PRIVATE_TRANSFER_TYPES.has(transferType); + } + // Validate the transfer type + function validateTransferType(transferType) { +- return VALID_TRANSFER_TYPES.has(transferType) ? transferType : +- logAndThrow(`Invalid transfer type '${transferType}'. Valid transfer types are 'private', 'privateToPublic', 'public', and 'publicToPrivate'.`); ++ return VALID_TRANSFER_TYPES.has(transferType) ? transferType : ++ logAndThrow(`Invalid transfer type '${transferType}'. Valid transfer types are 'private', 'privateToPublic', 'public', and 'publicToPrivate'.`); + } + + const KEY_STORE = "https://testnet3.parameters.aleo.org/"; + const CREDITS_PROGRAM_KEYS = { +- bond_public: { +- locator: "credits.aleo/bond_public", +- prover: KEY_STORE + "bond_public.prover.9c3547d", +- verifier: "bond_public.verifier.10315ae", +- verifyingKey: VerifyingKey.bondPublicVerifier +- }, +- claim_unbond_public: { +- locator: "credits.aleo/claim_unbond_public", +- prover: KEY_STORE + "claim_unbond_public.prover.f8b64aa", +- verifier: "claim_unbond_public.verifier.8fd7445", +- verifyingKey: VerifyingKey.claimUnbondPublicVerifier +- }, +- fee_private: { +- locator: "credits.aleo/fee_private", +- prover: KEY_STORE + "fee_private.prover.43fab98", +- verifier: "fee_private.verifier.f3dfefc", +- verifyingKey: VerifyingKey.feePrivateVerifier +- }, +- fee_public: { +- locator: "credits.aleo/fee_public", +- prover: KEY_STORE + "fee_public.prover.634f153", +- verifier: "fee_public.verifier.09eeb4f", +- verifyingKey: VerifyingKey.feePublicVerifier +- }, +- inclusion: { +- locator: "inclusion", +- prover: KEY_STORE + "inclusion.prover.cd85cc5", +- verifier: "inclusion.verifier.e6f3add", +- verifyingKey: VerifyingKey.inclusionVerifier +- }, +- join: { +- locator: "credits.aleo/join", +- prover: KEY_STORE + "join.prover.1a76fe8", +- verifier: "join.verifier.4f1701b", +- verifyingKey: VerifyingKey.joinVerifier +- }, +- set_validator_state: { +- locator: "credits.aleo/set_validator_state", +- prover: KEY_STORE + "set_validator_state.prover.5ce19be", +- verifier: "set_validator_state.verifier.730d95b", +- verifyingKey: VerifyingKey.setValidatorStateVerifier +- }, +- split: { +- locator: "credits.aleo/split", +- prover: KEY_STORE + "split.prover.e6d12b9", +- verifier: "split.verifier.2f9733d", +- verifyingKey: VerifyingKey.splitVerifier +- }, +- transfer_private: { +- locator: "credits.aleo/transfer_private", +- prover: KEY_STORE + "transfer_private.prover.2b487c0", +- verifier: "transfer_private.verifier.3a3cbba", +- verifyingKey: VerifyingKey.transferPrivateVerifier +- }, +- transfer_private_to_public: { +- locator: "credits.aleo/transfer_private_to_public", +- prover: KEY_STORE + "transfer_private_to_public.prover.1ff64cb", +- verifier: "transfer_private_to_public.verifier.d5b60de", +- verifyingKey: VerifyingKey.transferPrivateToPublicVerifier +- }, +- transfer_public: { +- locator: "credits.aleo/transfer_public", +- prover: KEY_STORE + "transfer_public.prover.a74565e", +- verifier: "transfer_public.verifier.a4c2906", +- verifyingKey: VerifyingKey.transferPublicVerifier +- }, +- transfer_public_to_private: { +- locator: "credits.aleo/transfer_public_to_private", +- prover: KEY_STORE + "transfer_public_to_private.prover.1bcddf9", +- verifier: "transfer_public_to_private.verifier.b094554", +- verifyingKey: VerifyingKey.transferPublicToPrivateVerifier +- }, +- unbond_delegator_as_validator: { +- locator: "credits.aleo/unbond_delegator_as_validator", +- prover: KEY_STORE + "unbond_delegator_as_validator.prover.115a86b", +- verifier: "unbond_delegator_as_validator.verifier.9585609", +- verifyingKey: VerifyingKey.unbondDelegatorAsValidatorVerifier +- }, +- unbond_public: { +- locator: "credits.aleo/unbond_public", +- prover: KEY_STORE + "unbond_public.prover.9547c05", +- verifier: "unbond_public.verifier.09873cd", +- verifyingKey: VerifyingKey.unbondPublicVerifier +- }, ++ bond_public: { ++ locator: "credits.aleo/bond_public", ++ prover: KEY_STORE + "bond_public.prover.9c3547d", ++ verifier: "bond_public.verifier.10315ae", ++ verifyingKey: VerifyingKey.bondPublicVerifier ++ }, ++ claim_unbond_public: { ++ locator: "credits.aleo/claim_unbond_public", ++ prover: KEY_STORE + "claim_unbond_public.prover.f8b64aa", ++ verifier: "claim_unbond_public.verifier.8fd7445", ++ verifyingKey: VerifyingKey.claimUnbondPublicVerifier ++ }, ++ fee_private: { ++ locator: "credits.aleo/fee_private", ++ prover: KEY_STORE + "fee_private.prover.43fab98", ++ verifier: "fee_private.verifier.f3dfefc", ++ verifyingKey: VerifyingKey.feePrivateVerifier ++ }, ++ fee_public: { ++ locator: "credits.aleo/fee_public", ++ prover: KEY_STORE + "fee_public.prover.634f153", ++ verifier: "fee_public.verifier.09eeb4f", ++ verifyingKey: VerifyingKey.feePublicVerifier ++ }, ++ inclusion: { ++ locator: "inclusion", ++ prover: KEY_STORE + "inclusion.prover.cd85cc5", ++ verifier: "inclusion.verifier.e6f3add", ++ verifyingKey: VerifyingKey.inclusionVerifier ++ }, ++ join: { ++ locator: "credits.aleo/join", ++ prover: KEY_STORE + "join.prover.1a76fe8", ++ verifier: "join.verifier.4f1701b", ++ verifyingKey: VerifyingKey.joinVerifier ++ }, ++ set_validator_state: { ++ locator: "credits.aleo/set_validator_state", ++ prover: KEY_STORE + "set_validator_state.prover.5ce19be", ++ verifier: "set_validator_state.verifier.730d95b", ++ verifyingKey: VerifyingKey.setValidatorStateVerifier ++ }, ++ split: { ++ locator: "credits.aleo/split", ++ prover: KEY_STORE + "split.prover.e6d12b9", ++ verifier: "split.verifier.2f9733d", ++ verifyingKey: VerifyingKey.splitVerifier ++ }, ++ transfer_private: { ++ locator: "credits.aleo/transfer_private", ++ prover: KEY_STORE + "transfer_private.prover.2b487c0", ++ verifier: "transfer_private.verifier.3a3cbba", ++ verifyingKey: VerifyingKey.transferPrivateVerifier ++ }, ++ transfer_private_to_public: { ++ locator: "credits.aleo/transfer_private_to_public", ++ prover: KEY_STORE + "transfer_private_to_public.prover.1ff64cb", ++ verifier: "transfer_private_to_public.verifier.d5b60de", ++ verifyingKey: VerifyingKey.transferPrivateToPublicVerifier ++ }, ++ transfer_public: { ++ locator: "credits.aleo/transfer_public", ++ prover: KEY_STORE + "transfer_public.prover.a74565e", ++ verifier: "transfer_public.verifier.a4c2906", ++ verifyingKey: VerifyingKey.transferPublicVerifier ++ }, ++ transfer_public_to_private: { ++ locator: "credits.aleo/transfer_public_to_private", ++ prover: KEY_STORE + "transfer_public_to_private.prover.1bcddf9", ++ verifier: "transfer_public_to_private.verifier.b094554", ++ verifyingKey: VerifyingKey.transferPublicToPrivateVerifier ++ }, ++ unbond_delegator_as_validator: { ++ locator: "credits.aleo/unbond_delegator_as_validator", ++ prover: KEY_STORE + "unbond_delegator_as_validator.prover.115a86b", ++ verifier: "unbond_delegator_as_validator.verifier.9585609", ++ verifyingKey: VerifyingKey.unbondDelegatorAsValidatorVerifier ++ }, ++ unbond_public: { ++ locator: "credits.aleo/unbond_public", ++ prover: KEY_STORE + "unbond_public.prover.9547c05", ++ verifier: "unbond_public.verifier.09873cd", ++ verifyingKey: VerifyingKey.unbondPublicVerifier ++ }, + }; + const PRIVATE_TRANSFER_TYPES = new Set([ +- "transfer_private", +- "private", +- "transferPrivate", +- "transfer_private_to_public", +- "privateToPublic", +- "transferPrivateToPublic", ++ "transfer_private", ++ "private", ++ "transferPrivate", ++ "transfer_private_to_public", ++ "privateToPublic", ++ "transferPrivateToPublic", + ]); + const VALID_TRANSFER_TYPES = new Set([ +- "transfer_private", +- "private", +- "transferPrivate", +- "transfer_private_to_public", +- "privateToPublic", +- "transferPrivateToPublic", +- "transfer_public", +- "public", +- "transferPublic", +- "transfer_public_to_private", +- "publicToPrivate", +- "transferPublicToPrivate", ++ "transfer_private", ++ "private", ++ "transferPrivate", ++ "transfer_private_to_public", ++ "privateToPublic", ++ "transferPrivateToPublic", ++ "transfer_public", ++ "public", ++ "transferPublic", ++ "transfer_public_to_private", ++ "publicToPrivate", ++ "transferPublicToPrivate", + ]); + const PRIVATE_TRANSFER = new Set([ +- "private", +- "transfer_private", +- "transferPrivate", ++ "private", ++ "transfer_private", ++ "transferPrivate", + ]); + const PRIVATE_TO_PUBLIC_TRANSFER = new Set([ +- "private_to_public", +- "privateToPublic", +- "transfer_private_to_public", +- "transferPrivateToPublic", ++ "private_to_public", ++ "privateToPublic", ++ "transfer_private_to_public", ++ "transferPrivateToPublic", + ]); + const PUBLIC_TRANSFER = new Set([ +- "public", +- "transfer_public", +- "transferPublic", ++ "public", ++ "transfer_public", ++ "transferPublic", + ]); + const PUBLIC_TO_PRIVATE_TRANSFER = new Set([ +- "public_to_private", +- "publicToPrivate", +- "transfer_public_to_private", +- "transferPublicToPrivate", ++ "public_to_private", ++ "publicToPrivate", ++ "transfer_public_to_private", ++ "transferPublicToPrivate", + ]); + function logAndThrow(message) { +- console.error(message); +- throw message; ++ console.error(message); ++ throw message; + } + // @TODO: This function is no longer needed, remove it. + async function initializeWasm() { +- console.warn("initializeWasm is deprecated, you no longer need to use it"); ++ console.warn("initializeWasm is deprecated, you no longer need to use it"); + } + + export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoNetworkClient, BlockHeightSearch, CREDITS_PROGRAM_KEYS, KEY_STORE, NetworkRecordProvider, OfflineKeyProvider, OfflineSearchParams, PRIVATE_TO_PUBLIC_TRANSFER, PRIVATE_TRANSFER, PRIVATE_TRANSFER_TYPES, PUBLIC_TO_PRIVATE_TRANSFER, PUBLIC_TRANSFER, ProgramManager, VALID_TRANSFER_TYPES, createAleoWorker, initializeWasm, logAndThrow }; diff --git a/validators/run-validator/start.js b/validators/run-validator/start.js index ee75c94..bcd2b88 100644 --- a/validators/run-validator/start.js +++ b/validators/run-validator/start.js @@ -1,4 +1,8 @@ -import { sync_db_with_blockchain, synthetize_hash_custody_keys } from "./lib/sync.js"; +import { + sync_db_with_blockchain, + remove_actually_unspent_records +} from "./lib/sync.js"; +import { synthetize_programs_keys, } from "./lib/programs.js"; import { process_requests } from "./lib/process.js"; import { load_database } from "./lib/db.js"; import { load_aleo_account, } from "./lib/aleo.js"; @@ -20,6 +24,7 @@ const load_env = async () => { try { const account = await load_aleo_account(process.env["PRIVATE_KEY"]); const address = account.address().to_string(); + console.log(private_key_success_msg, address) return { account, refresh_period_s, rpc_provider }; } catch (e) { throw new Error(private_key_error_msg + " " + e); @@ -29,6 +34,7 @@ const load_env = async () => { const sync_and_process = async (rpc_provider, db, account) => { await sync_db_with_blockchain(rpc_provider, db, account); + await remove_actually_unspent_records(db); await process_requests(rpc_provider, db, account); } @@ -36,7 +42,7 @@ const sync_and_process = async (rpc_provider, db, account) => { const main = async () => { const { account, refresh_period_s, rpc_provider } = await load_env(); const db = await load_database(); - await synthetize_hash_custody_keys(account); + await synthetize_programs_keys(account); while (true) { try { await sync_and_process(rpc_provider, db, account);