What does multisig mean? The term "multisig" stands for "multi-signature" and it's used to describe accounts associated with more than one private key. The account is created with a list of owners and a policy ; when transactions are approved by at least m owners, they can be executed. m-out-of-n In blockchain each transaction involves the usage of public-key signature; each blockchain participant owns a private/public key pair. The participants use the private keys to sign a transaction and all other participants can verify that signature using the signer's public key. With a multisig account, each transaction requires the signature of many accounts before being executed. One participant (who is among the multisig account owners) can start the transaction, but only when the other owners approve that transaction, it will be executed. Why? The multisig account eliminates the single point of failure in case of attacks and it allows the implementation of a variety of use cases where one or many parties are involved. Here below some examples. : if a user loses the key, the funds are not lost because the other keys can still be used. Redundancy : a single user can have both a web wallet and a mobile wallet associated with a multisig account, policy 2-of-2. 2FA (two-factor authentication) : two departments must approve each transaction before being published, policy 2-of-2. Departments approval : a kid can spend money only with the approval of either parent. Parents' saving account What we are going to do Create a multisig account Transfer funds to the multisig account Create multisig transactions Approve multisig transactions Execute multisig transactions Reject multisig transactions Update multisig account (owners and threshold) On the you can find an example with some of the features listed above, you can clone it and run it locally. repository clone the : node sample app repository git clone git@github.com:rsksmart/rif-multisig-node-sample.git install dependencies: npm install start the ganache network: npm run network:local to execute the main script npm run start RSK solution architecture Libraries: : it provides the core functionalities required to interact with a Safe @gnosis.pm/safe-core-sdk : it allows the creation of a Safe account without UI interaction @rsksmart/safe-factory-sdk : it facilitates the transaction creation (raw transactions, ERC20 transactions, and rejections) @rsksmart/safe-transactions-sdk (still in alpha version as of June 2021): it facilitates the interaction with . @gnosis.pm/safe-service-client Safe Transaction Service API Smart contracts: Gnosis Safe Contracts Rest API: : it collects all the multisig information using and . Furthermore, it allows collecting off-chain signatures and retrieving multisig pending transactions. Safe transaction service trace_transaction trace_blocks Repository: Node sample app Let’s start Create a multisig account Initialize the signer: provider = providers.JsonRpcProvider() signer = provider.getSigner( ) const new const await 0 Before creating a multisig account, it requires that the contracts have been deployed to the network. Using one of the RSK networks (mainnet or testnet), you can use the addresses of the . pre-deployed contracts { EthersSafeFactory } safeFactory = EthersSafeFactory( signer, proxyFactoryAddress, safeSingletonAddress ) safeSdk = safeFactory.createSafe({ : [signer.getAddress()], : }) import from '@rsksmart/safe-factory-sdk' const new const await owners threshold 1 Transfer funds to the multisig account It is important to understand that, to receive funds, we have to use the multisig account address (instead of the owner's address) as a receiver. safeSdk: Safe; multisigAccountAddress = safeSdk.getAddress() // previously created safe const // address to use as fund receiver const Create multisig transactions There are several ways to create multisig transactions according to our needs. If we need to create raw transactions we could use the createTransaction method on the Safe instance: partialTx: SafeTransactionDataPartial = { : , : , : } safeTransaction = safeSdk.createTransaction(partialTx) const to '0x<address>' data '0x<data>' value '<eth_value_in_wei>' const await or we could use the : RawTransactionBuilder { RawTransactionBuilder } rawTransactionBuilder = RawTransactionBuilder(safe) safeTransaction = rawTransactionBuilder.rawTransaction(to, value, data) import from '@rsksmart/safe-transactions-sdk' const new const await ERC20 transactions Similarly, we can create -related transactions, including . ERC20 RIF Token { ERC20TransactionBuilder } erc20TransactionBuilder = ERC20TransactionBuilder.create(safe, ERC20Token) transferTx = erc20TransactionBuilder.transfer( to, transfer ) transferFromTx = erc20TransactionBuilder.transferFrom( , to, value ) import from '@rsksmart/safe-transactions-sdk' const // create a `transfer` transaction const await // create a `transferFrom` transaction const await from ERC721 transactions The package @rsksmart/safe-transactions-sdk provides also an easy way to create ERC721 transactions. { ERC721TransactionBuilder } ; erc721TransactionBuilder = ERC721TransactionBuilder.create( safe, ERC721Token ); transferFromTx = erc721TransactionBuilder.transferFrom( , to, tokenId ); safeTransferFromTx = erc721TransactionBuilder.safeTransferFrom( , to, tokenId ); import from "@rsksmart/safe-transactions-sdk" const // create a `transferFrom` transaction const await from // create a `safeTransferFrom` transaction const await from Approve multisig transactions Transaction approval can take place both on-chain and off-chain. With the on-chain approval, the signature is added interacting with the safe account, hence the signature is available in the blockchain. Off-chain approval requires the user to publish the signature through the to make it available to other participants. Safe Transaction Service On-chain approval txHash = safeSdk.getTransactionHash(safeTransaction) approveTxResponse = safeSdk.approveTransactionHash(txHash) approveTxResponse.wait() const await const await await Once the transaction is approved on-chain, user can retrieve the list of owners with the method. getOwnersWhoApprovedTx ownersWhoApproved = safeSdk.getOwnersWhoApprovedTx(txHash) const await Off-chain approval The user needs to create the signature first. signature = safeSdk.signTransaction(safeTransaction) const await Once the signature is generated, the user must publish the signature using the . Safe Transaction Service safeService = SafeServiceClient(SAFE_TRANSACTION_SERVICE_URL) safeTxHash = safeCoreSdk.getTransactionHash(transaction) safeServiceClient.confirmTransaction(safeTxHash, signature.data) const new const await await Execute multisig transactions Once a transaction is approved by a number of owners that must be equal or greater than the threshold set, it can be executed. txResponse = safeSDk.executeTransaction(safeTransaction) txResponse.wait() const await await Reject multisig transactions Transaction rejection implies the creation and execution of a new transaction with the same nonce like the one we want to reject. Once the rejection transaction is created, it must be approved and executed like any other multisig transaction. For instance, if the current threshold is set to 2, rejecting a transaction requires the following steps: the creation of a rejection transaction the approval of the rejection transaction by at least 2 owners the execution of the rejection transaction. { rejectTx } rejectionTx = rejectTx(safe, transaction) import from '@rsksmart/safe-transactions-sdk' // creation of the rejection transaction const await Update multisig account (owners and threshold) As per any other transaction, changing the main properties of a multisig account requires the creation of a new transaction and its approval, before being executed. ownerTx = safe.getAddOwnerTx(newOwner, newThreshold) ownerTx = safe.getRemoveOwnerTx(existingOwner, newThreshold) ownerTx = safe.getSwapOwnerTx(oldOwner, newOwner) // Create a transaction to add a new owner const await // Create a transaction to remove an owner const await // Create a transaction to replace an owner const await It is important to keep in mind that must be set according to the current owners. If the current owners are three, and we add a new owner, the cannot be set to four, but it can be at most three, as the current number of owners. newThreshold newThreshold thresholdTx = safe.getChangeThresholdTx(newThreshold) const await Eventually, it’s also possible to change the without changing the owners. threshold The operations listed above won’t change the safe account, they create the related transactions. The changes will be applied only after the transaction is executed. Glossary multisig: account or transaction requiring multiple signatures before being executed threshold: the number of signatures required to execute a transaction owner: address allowed to execute operations on a multisig account References RSK RIF Multisig: https://developers.rsk.co/rif/multisig/ RSK RIF Multisig node sample app: https://github.com/rsksmart/rif-multisig-node-sample RSK RIF Multisig react sample app: https://github.com/rsksmart/multisig-sample-app Gnosis Safe Smart Contracts: https://docs.gnosis.io/safe/docs/contracts_intro/ Do you have further questions? Please contact us through our open Slack for technical questions and support. You can also reach out with any feedback you would like to share with us through our social media channels and forums: Twitter: https://twitter.com/RSKsmart Telegram: https://t.me/RSKsmart Reddit: https://www.reddit.com/r/rootstock/ BitcoinTalk: https://bitcointalk.org/index.php?topic=3189777.0