NOTE: This repository is currently not maintained.
This repository is the source code for the OnChainMultiSig
contract.
The OnChainMultiSig
contract is designed to address the need for
multiple signature to authorise transactions without [time constraint] or gas balance.
The motivation for this contract is in three parts:
-
Limited Time Constraint Natively, Flow suports multiple signers to authorise account transaction with the innovative
Weighted Keys
in theAccounts
system. However, transactions all have expiration window (measured in blocks). This is about 10 minutes on the Mainnet. It may not always be feasible or user friendly to require multisig key holder to be present to sign everytime a transaction is required. -
Standardisation It is common for an account to have multiple resources in their storage path and that these resources all require the multisig feature. It will be easier for frontend developers or users to compose signatures that captures the intention of the signer securely.
-
Gas requirement It should not be required that the signers of a multisig resource must all have balance in an account, the signatures themselves should be enough to authorise transactions of which some other
payer
(or themselves) can pay for.
To address the time constraint, as the name suggests, the signatures are temporarily stored on chain. Once all required signatures are ready, anyone can call the public method to execute the transaction.
Interfaces are defined to facilitate standardising this onchain signature storage across different resources.
Finally, following Flow's decoupling principle between account and keys,
the signature for a multisig transaction can be sumbitted by a trusted payer
,
independent to the account that owns the resource1 or the key.
This allows signers to simply be some entity that holds some private key where the corresponding public
key has been added as part of the resource's multisig public key list with some weight.
OnChainMultiSig
contract provides a Manager
resource which is intended to be created and stored by resources that
supports onchain multisig.
In addition, PublicSigner
interface is provided for the resources as a standard interface for transactions to:
addNewPayload
: Create a new payload and signature for it to be stored. TheTxIndex
must be the current index incremented by one and is included in the signature. Signature must be produced by the public key in@Manager.keyList
addPayloadSignature
: Submit a signature for a payload that was added. Signature must be produced by the public key in@Manager.keyList
executeTx
: Execute a transaction (if all signatures required have been submitted)
and queries for:
UUID
: gets the uuid of the multisig resourcegetTxIndex
: gets the sequentially assigned current txIndex of multisig pending tx of this resourcegetSignerKeys
: gets the list of public keys for the resource's multisig signersgetSignerKeyAttr
: gets the stored key attributes
Internal to the Manager
resource, it implements the SignatureManager
interface which allows the implementation of PublicSigner
functions on the multisig supported resources to work with the Manager
.
We have used a simple Vault
resource in the MultiSigFlowToken
contract to demonstrate the usage of the PublicSigner
,
how to form a onchain-multisig signature,
transacting with the MultiSigFlowToken
contract and resource owner account management.
A happy path is demostrated in this diagram:
The message in the signature verified by the Manager
resource are as such, in order:
txIndex: UInt64
: The txIndex of the payload. For a new payload, this must be the latest txIndex + 1method: String
: The name of the method the multisig supported resource usesarg: AnyStructure
: The arguments that are needed (currently supports:String
,UInt64
,UFix64
,Address
)
Example of how the signer may construct their message to ensure the encoding to bytes align with the cadence
encoding in the contract can be found in GetSignableDataFromScript
in util.go
,
which uses the script in scripts/calc_signable_data.cdc
.
The signing example can be found in SignPayloadOffline
in util.go
.
Note: The current version only supports hashAlgorithm: HashAlgorithm.SHA3_256
Whilst it is possible to allow for onchain multisig feature to be available for resources, to limit the use to just be in that way will ultimately depend on the account that owns the resources.
As such, the account with such a resource should itself have all the keys added so that the weights
of each authorizer is consistent for the resource and the account. This is because if one key
is added to the account, that key has the ability to directly call functions in Manager
to alter the states.
Another approach may be that once the resource has been added, all keys for the owner account is revoked. This limits the flexibility of the account but it may be neccessary, similar to immutable contracts in Flow.
Footnotes
-
Please see resource owner account management for details ↩