@@ -2626,6 +2626,352 @@ Flow for Creating Guarded Relayed Transactions:
262626264 . Then, the guardian signs.
262726275 . Finally, the relayer signs before broadcasting.
26282628
2629+ ### Multisig
2630+
2631+ The sdk contains components to interact with the [ Multisig Contract] ( https://github.com/multiversx/mx-contracts-rs/releases/tag/v0.45.5 ) .
2632+ We can deploy a multisig smart contract, add members, propose and execute actions and query the contract.
2633+ The same as the other components, to interact with a multisig smart contract we can use either the MultisigController or the MultisigTransactionsFactory.
2634+
2635+ These operations can be performed using both the ** controller** and the ** factory** . For a complete list of supported methods, please refer to the autogenerated documentation:
2636+ - [ ` MultisigController ` ] ( https://multiversx.github.io/mx-sdk-js-core/v14/classes/MultisigController.html )
2637+ - [ ` MultisigTransactionsFactory ` ] ( https://multiversx.github.io/mx-sdk-js-core/v14/classes/MultisigTransactionsFactory.html )
2638+
2639+ #### Deploying a Multisig Smart Contract using the controller
2640+ ``` js
2641+ {
2642+ const abi = await loadAbiRegistry (" src/testdata/multisig-full.abi.json" );
2643+ const bytecode = await loadContractCode (" src/testdata/multisig-full.wasm" );
2644+
2645+ // create the entrypoint and the multisig controller
2646+ const entrypoint = new DevnetEntrypoint ();
2647+ const controller = entrypoint .createMultisigController (abi);
2648+
2649+ const filePath = path .join (" ../src" , " testdata" , " testwallets" , " alice.pem" );
2650+ const alice = await Account .newFromPem (filePath);
2651+
2652+ // fetch the nonce of the network
2653+ alice .nonce = await entrypoint .recallAccountNonce (alice .address );
2654+
2655+ const transaction = await controller .createTransactionForDeploy (alice, alice .getNonceThenIncrement (), {
2656+ quorum: 2 ,
2657+ board: [
2658+ alice .address ,
2659+ Address .newFromBech32 (" erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx" ),
2660+ ],
2661+ bytecode: bytecode .valueOf (),
2662+ gasLimit: 100000000n ,
2663+ });
2664+
2665+ // sending the transaction
2666+ const txHash = await entrypoint .sendTransaction (transaction);
2667+
2668+ // wait for transaction completion, extract multisig contract's address
2669+ const outcome = await controller .awaitCompletedDeploy (txHash);
2670+
2671+ const contractAddress = outcome[0 ].contractAddress ;
2672+ }
2673+ ```
2674+
2675+ #### Deploying a Multisig Smart Contract using the factory
2676+ ``` js
2677+ {
2678+ const abi = await loadAbiRegistry (" src/testdata/multisig-full.abi.json" );
2679+ const bytecode = await loadContractCode (" src/testdata/multisig-full.wasm" );
2680+
2681+ // create the entrypoint and the multisig factory
2682+ const entrypoint = new DevnetEntrypoint ();
2683+ const factory = entrypoint .createMultisigTransactionsFactory (abi);
2684+
2685+ const filePath = path .join (" ../src" , " testdata" , " testwallets" , " alice.pem" );
2686+ const alice = await Account .newFromPem (filePath);
2687+
2688+ // fetch the nonce of the network
2689+ alice .nonce = await entrypoint .recallAccountNonce (alice .address );
2690+
2691+ const transaction = factory .createTransactionForDeploy (alice .address , {
2692+ quorum: 2 ,
2693+ board: [
2694+ alice .address ,
2695+ Address .newFromBech32 (" erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx" ),
2696+ ],
2697+ bytecode: bytecode .valueOf (),
2698+ gasLimit: 100000000n ,
2699+ });
2700+
2701+ transaction .nonce = alice .getNonceThenIncrement ();
2702+ transaction .signature = await alice .signTransaction (transaction);
2703+ // sending the transaction
2704+ const txHash = await entrypoint .sendTransaction (transaction);
2705+ }
2706+ ```
2707+
2708+ #### Propose an action using the controller
2709+ We'll propose an action to send some EGLD to Carol. After we sent the proposal, we'll also parse the outcome of the transaction to get the ` proposal id ` .
2710+ The id can be used later for signing and performing the proposal.
2711+
2712+ ``` js
2713+ {
2714+ // create the entrypoint and the multisig controller
2715+ const entrypoint = new DevnetEntrypoint ();
2716+ const abi = await loadAbiRegistry (" src/testdata/multisig-full.abi.json" );
2717+ const controller = entrypoint .createMultisigController (abi);
2718+
2719+ const filePath = path .join (" ../src" , " testdata" , " testwallets" , " alice.pem" );
2720+ const alice = await Account .newFromPem (filePath);
2721+
2722+ // fetch the nonce of the network
2723+ alice .nonce = await entrypoint .recallAccountNonce (alice .address );
2724+
2725+ const contract = Address .newFromBech32 (" erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqf8llllswuedva" );
2726+
2727+ const transaction = await controller .createTransactionForProposeTransferExecute (
2728+ alice,
2729+ alice .getNonceThenIncrement (),
2730+ {
2731+ multisigContract: contract,
2732+ to: Address .newFromBech32 (" erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8" ),
2733+ gasLimit: 10000000n ,
2734+ nativeTokenAmount: 1000000000000000000n ,
2735+ },
2736+ );
2737+
2738+ // sending the transaction
2739+ const txHash = await entrypoint .sendTransaction (transaction);
2740+
2741+ // parse the outcome and get the proposal id
2742+ const actionId = await controller .awaitCompletedPerformAction (txHash);
2743+ }
2744+ ```
2745+
2746+ #### Propose an action using the factory
2747+ Proposing an action for a multisig contract using the MultisigFactory is very similar to using the controller, but in order to get the proposal id, we need to use MultisigTransactionsOutcomeParser.
2748+
2749+ ``` js
2750+ {
2751+ const abi = await loadAbiRegistry (" src/testdata/multisig-full.abi.json" );
2752+
2753+ // create the entrypoint and the multisig factory
2754+ const entrypoint = new DevnetEntrypoint ();
2755+ const provider = entrypoint .createNetworkProvider ();
2756+ const factory = entrypoint .createMultisigTransactionsFactory (abi);
2757+
2758+ const filePath = path .join (" ../src" , " testdata" , " testwallets" , " alice.pem" );
2759+ const alice = await Account .newFromPem (filePath);
2760+
2761+ const contract = Address .newFromBech32 (" erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqf8llllswuedva" );
2762+
2763+ const transaction = factory .createTransactionForProposeTransferExecute (alice .address , {
2764+ multisigContract: contract,
2765+ to: Address .newFromBech32 (" erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8" ),
2766+ gasLimit: 10000000n ,
2767+ nativeTokenAmount: 1000000000000000000n ,
2768+ });
2769+ // fetch the nonce of the network
2770+ alice .nonce = await entrypoint .recallAccountNonce (alice .address );
2771+
2772+ // set the nonce
2773+ transaction .nonce = alice .getNonceThenIncrement ();
2774+
2775+ // sign the transaction
2776+ transaction .signature = await alice .signTransaction (transaction);
2777+
2778+ // sending the transaction
2779+ const txHash = await entrypoint .sendTransaction (transaction);
2780+
2781+ // wait for the transaction to execute
2782+ const transactionAwaiter = new TransactionWatcher (provider);
2783+ const transactionOnNetwork = await transactionAwaiter .awaitCompleted (txHash);
2784+
2785+ // parse the outcome of the transaction
2786+ const parser = new MultisigTransactionsOutcomeParser ({ abi });
2787+ const actionId = parser .parseProposeAction (transactionOnNetwork);
2788+ }
2789+ ```
2790+
2791+ #### Querying the Multisig Smart Contract
2792+ Unlike creating transactions, querying the multisig can be performed only using the controller.
2793+ Let's query the contract to get all board members.
2794+
2795+ ``` js
2796+ {
2797+ const abi = await loadAbiRegistry (" src/testdata/multisig-full.abi.json" );
2798+
2799+ // create the entrypoint and the multisig controller
2800+ const entrypoint = new DevnetEntrypoint ();
2801+ const controller = entrypoint .createMultisigController (abi);
2802+
2803+ const contract = Address .newFromBech32 (" erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqf8llllswuedva" );
2804+
2805+ const boardMembers = await controller .getAllBoardMembers ({ multisigAddress: contract .toBech32 () });
2806+ }
2807+ ```
2808+
2809+ ### Governance
2810+
2811+ We can create transactions for creating a new governance proposal, vote for a proposal or query the governance contract.
2812+
2813+ These operations can be performed using both the ** controller** and the ** factory** . For a complete list of supported methods, please refer to the autogenerated documentation:
2814+ - [ ` GovernanceController ` ] ( https://multiversx.github.io/mx-sdk-js-core/v14/classes/GovernanceController.html )
2815+ - [ ` GovernanceTransactionsFactory ` ] ( https://multiversx.github.io/mx-sdk-js-core/v14/classes/GovernanceTransactionsFactory.html )
2816+
2817+ #### Creating a new proposal using the controller
2818+ ``` js
2819+ {
2820+ // create the entrypoint and the governance controller
2821+ const entrypoint = new DevnetEntrypoint ();
2822+ const controller = entrypoint .createGovernanceController ();
2823+
2824+ const filePath = path .join (" ../src" , " testdata" , " testwallets" , " alice.pem" );
2825+ const alice = await Account .newFromPem (filePath);
2826+
2827+ // fetch the nonce of the network
2828+ alice .nonce = await entrypoint .recallAccountNonce (alice .address );
2829+ const commitHash = " 1db734c0315f9ec422b88f679ccfe3e0197b9d67" ;
2830+
2831+ const transaction = await controller .createTransactionForNewProposal (alice, alice .getNonceThenIncrement (), {
2832+ commitHash: commitHash,
2833+ startVoteEpoch: 10 ,
2834+ endVoteEpoch: 15 ,
2835+ nativeTokenAmount: 500_000000000000000000n ,
2836+ });
2837+
2838+ // sending the transaction
2839+ const txHash = await entrypoint .sendTransaction (transaction);
2840+
2841+ // wait for transaction completion, extract proposal's details
2842+ const outcome = await controller .awaitCompletedProposeProposal (txHash);
2843+
2844+ const proposalNonce = outcome[0 ].proposalNonce ;
2845+ const proposalCommitHash = outcome[0 ].commitHash ;
2846+ const proposalStartVoteEpoch = outcome[0 ].startVoteEpoch ;
2847+ const proposalEndVoteEpoch = outcome[0 ].endVoteEpoch ;
2848+ }
2849+ ```
2850+
2851+ #### Creating a new proposal using the factory
2852+ ``` js
2853+ {
2854+ // create the entrypoint and the governance factory
2855+ const entrypoint = new DevnetEntrypoint ();
2856+ const factory = entrypoint .createGovernanceTransactionsFactory ();
2857+
2858+ const filePath = path .join (" ../src" , " testdata" , " testwallets" , " alice.pem" );
2859+ const alice = await Account .newFromPem (filePath);
2860+
2861+ const commitHash = " 1db734c0315f9ec422b88f679ccfe3e0197b9d67" ;
2862+
2863+ const transaction = factory .createTransactionForNewProposal (alice .address , {
2864+ commitHash: commitHash,
2865+ startVoteEpoch: 10 ,
2866+ endVoteEpoch: 15 ,
2867+ nativeTokenAmount: 500_000000000000000000n ,
2868+ });
2869+ // fetch the nonce of the network
2870+ alice .nonce = await entrypoint .recallAccountNonce (alice .address );
2871+
2872+ // set the nonce
2873+ transaction .nonce = alice .getNonceThenIncrement ();
2874+
2875+ // sign the transaction
2876+ transaction .signature = await alice .signTransaction (transaction);
2877+
2878+ // sending the transaction
2879+ const txHash = await entrypoint .sendTransaction (transaction);
2880+
2881+ // waits until the transaction is processed and fetches it from the network
2882+ const transactionOnNetwork = await entrypoint .awaitCompletedTransaction (txHash);
2883+
2884+ const parser = new GovernanceTransactionsOutcomeParser ({});
2885+ const outcome = parser .parseNewProposal (transactionOnNetwork);
2886+ const proposalNonce = outcome[0 ].proposalNonce ;
2887+ const proposalCommitHash = outcome[0 ].commitHash ;
2888+ const proposalStartVoteEpoch = outcome[0 ].startVoteEpoch ;
2889+ const proposalEndVoteEpoch = outcome[0 ].endVoteEpoch ;
2890+ }
2891+ ```
2892+
2893+ #### Vote for a proposal using the controller
2894+
2895+ ``` js
2896+ {
2897+ // create the entrypoint and the governance controller
2898+ const entrypoint = new DevnetEntrypoint ();
2899+ const controller = entrypoint .createGovernanceController ();
2900+
2901+ const filePath = path .join (" ../src" , " testdata" , " testwallets" , " alice.pem" );
2902+ const alice = await Account .newFromPem (filePath);
2903+
2904+ // fetch the nonce of the network
2905+ alice .nonce = await entrypoint .recallAccountNonce (alice .address );
2906+
2907+ const transaction = await controller .createTransactionForVoting (alice, alice .getNonceThenIncrement (), {
2908+ proposalNonce: 1 ,
2909+ vote: Vote .YES ,
2910+ });
2911+
2912+ // sending the transaction
2913+ const txHash = await entrypoint .sendTransaction (transaction);
2914+
2915+ // wait for transaction completion, extract proposal's details
2916+ const outcome = await controller .awaitCompletedVote (txHash);
2917+ const proposalNonce = outcome[0 ].proposalNonce ;
2918+ const vote = outcome[0 ].vote ;
2919+ const voteTotalStake = outcome[0 ].totalStake ;
2920+ const voteVotingPower = outcome[0 ].votingPower ;
2921+ }
2922+ ```
2923+
2924+ #### Vote for a proposal using the factory
2925+ ``` js
2926+ {
2927+ // create the entrypoint and the governance factory
2928+ const entrypoint = new DevnetEntrypoint ();
2929+ const factory = entrypoint .createGovernanceTransactionsFactory ();
2930+
2931+ const filePath = path .join (" ../src" , " testdata" , " testwallets" , " alice.pem" );
2932+ const alice = await Account .newFromPem (filePath);
2933+
2934+ const transaction = factory .createTransactionForVoting (alice .address , {
2935+ proposalNonce: 1 ,
2936+ vote: Vote .YES ,
2937+ });
2938+ // fetch the nonce of the network
2939+ alice .nonce = await entrypoint .recallAccountNonce (alice .address );
2940+
2941+ // set the nonce
2942+ transaction .nonce = alice .getNonceThenIncrement ();
2943+
2944+ // sign the transaction
2945+ transaction .signature = await alice .signTransaction (transaction);
2946+
2947+ // sending the transaction
2948+ const txHash = await entrypoint .sendTransaction (transaction);
2949+
2950+ // wait for transaction completion, extract proposal's details
2951+ const transactionOnNetwork = await entrypoint .awaitCompletedTransaction (txHash);
2952+ const parser = new GovernanceTransactionsOutcomeParser ({});
2953+ const outcome = parser .parseVote (transactionOnNetwork);
2954+ const proposalNonce = outcome[0 ].proposalNonce ;
2955+ const vote = outcome[0 ].vote ;
2956+ const voteTotalStake = outcome[0 ].totalStake ;
2957+ const voteVotingPower = outcome[0 ].votingPower ;
2958+ }
2959+ ```
2960+
2961+ #### Querying the governance contract
2962+ Unlike creating transactions, querying the contract is only possible using the controller. Let's query the contract to get more details about a proposal.
2963+
2964+ ``` js
2965+ {
2966+ // create the entrypoint and the governance controller
2967+ const entrypoint = new DevnetEntrypoint ();
2968+ const controller = entrypoint .createGovernanceController ();
2969+
2970+ const proposalInfo = await controller .getProposal (1 );
2971+ console .log ({ proposalInfo });
2972+ }
2973+ ```
2974+
26292975## Addresses
26302976
26312977Create an ` Address ` object from a bech32-encoded string:
0 commit comments