UpdateCustodianMultisigWallet.sol
Overview
The UpdateCustodianMultisigWallet.sol file implements a multisignature wallet smart contract that supports custodianship with flexible key and address management, transaction confirmation, and data update processes. It enables multiple custodians to collectively manage funds and contract ownership, requiring a configurable number of confirmations for both fund transfers and contract data updates. This wallet supports sending native currency (nanograms) and ECC tokens with control over message flags and payloads. It also handles transaction expiration and custodians' request limits.
This contract is designed for secure and collaborative wallet management, allowing for dynamic updates of custodian sets and required confirmations, which enhances governance flexibility. The contract employs bitmask operations for efficient management of confirmation states and queued requests.
Data Structures
Custodian
Represents an individual custodian of the wallet.
Fields:
optional(uint256) owner_pubkey— Public key if the custodian is identified by a key.optional(address) owner_address— Address if the custodian is identified by an address.uint8 index— Custodian's unique index in the wallet.
Transaction
Represents a transaction initiated by a custodian that requires multisignature confirmation.
Fields:
uint64 id— Unique transaction identifier.uint32 confirmationsMask— Bitmask representing which custodians have confirmed.uint8 signsRequired— Number of required confirmations.uint8 signsReceived— Number of confirmations received.Custodian creator— Custodian who created the transaction.address dest— Destination address for the transfer.uint128 value— Amount of nanograms to transfer.mapping(uint32 => varuint32) cc— ECC token amounts to transfer by token ID.uint16 sendFlags— Flags controlling internal message sending behavior.TvmCell payload— Payload data for the internal message.bool bounce— Bounce flag indicating behavior if the destination account does not exist.
UpdateData
Represents a queued update for the wallet's custodian set and confirmation requirements.
Fields:
uint64 id— Unique update identifier.uint32 confirmationsMask— Bitmask of confirmations from custodians.uint8 signsRequired— Number of required confirmations for update.uint8 signsReceived— Number of confirmations received.Custodian creator— Custodian who created the update request.uint256[] owners_pubkey— New custodian keys.address[] owners_address— New custodian addresses.uint8 reqConfirms— Required confirmations for transactions.uint8 reqConfirmsData— Required confirmations for data updates.
Constants and Variables
MAX_QUEUED_REQUESTS (5) — Max number of queued requests per custodian.
EXPIRATION_TIME(3601 seconds) — Lifetime of transactions and updates (~1 hour).MAX_CUSTODIAN_COUNT(32) — Maximum number of custodians.ZERO_TIME(1000000000) — Base time offset used in ID generation.SENDMSG_ALL_BALANCE (128) — Flag to send all remaining balance.
Flags for internal message sending:
FLAG_PAY_FWD_FEE_FROM_BALANCE(1) — Forward fees paid from contract balance.FLAG_SEND_ALL_REMAINING (128) — Send all remaining balance.
Storage Variables
m_ownerKey/m_ownerAddress— Optional single owner key/address used for single-custodian wallets.m_requestsMask/m_requestsMaskData— Bitmasks tracking the number of active requests per custodian.m_transactions— Mapping from transaction ID toTransaction.m_data— Mapping from update ID toUpdateData.m_custodians— Mapping from hashed custodian key+address toCustodian.m_custodianCount— Number of custodians.m_defaultRequiredConfirmations— Default confirmation count for transactions.m_defaultRequiredConfirmationsData— Default confirmation count for data updates._max_cleanup_operations— Maximum operations for cleaning expired requests (default 40).
Constructor and Initialization
constructor
Initializes the wallet with a set of custodians and confirmation requirements.
Parameters:
uint256[] owners_pubkey— Array of custodian public keys.address[] owners_address— Array of custodian addresses.uint8 reqConfirms— Required confirmations for transactions.uint8 reqConfirmsData— Required confirmations for data updates.uint64 value— Initial value (used internally).
Validates the input and calls
_initialize.Requires the sender to have the contract's public key.
_initialize
Internal function to populate custodian data and set default confirmations.
Parameters:
uint256[] owners_pubkeyaddress[] owners_addressuint8 reqConfirmsuint8 reqConfirmsData
Clears existing state and rebuilds custodian mappings.
Stores the first owner as
m_ownerKeyorm_ownerAddressif available.Calculates the required confirmations, ensuring logical consistency.
Throws if no valid custodians or invalid counts.
Public Functions
sendTransaction
Allows a single custodian (only one custodian in wallet) to send funds directly.
Parameters:
address dest— Destination address.uint128 value— Amount to send.mapping(uint32 => varuint32) cc— ECC token amounts.bool bounce— Bounce flag.uint8 flags— Send message flags.TvmCell payload— Message payload.
Returns the destination address.
Validates sender identity matches the sole custodian.
Transfers funds with specified parameters.
submitTransaction
Allows any custodian to submit a new transaction for multisig confirmation.
Parameters identical to
sendTransaction.Returns the transactionId of the queued transaction or 0 if executed immediately.
Enforces max queued requests per custodian.
If only one required signature, executes immediately.
Otherwise, queues transaction and auto-confirms by creator.
confirmTransaction
Allows custodians to confirm a queued transaction.
Parameters:
uint64 transactionId— ID of the transaction to confirm.
Validates transaction existence and prevents double confirmation.
Deletes expired transactions automatically.
If confirmation threshold reached, executes transaction and removes it.
submitDataUpdate
Allows submitting a new custodian and confirmation configuration update.
Parameters:
uint256[] owners_pubkey— New custodian keys.address[] owners_address— New custodian addresses.uint8 reqConfirms— Required transaction confirmations.uint8 reqConfirmsData— Required data update confirmations.
Returns the update ID or 0 if executed immediately.
Validates inputs and queued requests.
Auto-confirms by creator; applies update if only one confirmation required.
confirmDataUpdate
Allows custodians to confirm a pending data update.
Parameters:
uint64 dataUpdateId— ID of the data update to confirm.
Validates existence and double confirmation.
Deletes expired updates.
Applies updates once confirmation threshold is met.
setMaxCleanupOperations
Allows custodians to adjust the maximum cleanup operations for expired requests.
Parameter:
uint value— New maximum number of cleanup operations.
Validates sender as custodian before applying change.
Internal Helper Functions
Bitmask Operations
_getMaskValue(uint256 mask, uint8 index): Returns the queued request count for a custodian by index._incMaskValue(uint256 mask, uint8 index): Increments the queued request count._decMaskValue(uint256 mask, uint8 index): Decrements the queued request count._checkBit(uint32 mask, uint8 index): Checks if a bit is set in a confirmation mask._isConfirmed(uint32 mask, uint8 custodianIndex): Checks if a custodian has confirmed._setConfirmed(uint32 mask, uint8 custodianIndex): Sets a confirmation bit.
Custodian Lookup
_findCustodian(uint256 senderKey, address senderAddress): Returns theCustodianstruct matching the sender's key and/or address. Throws if not found.
ID and Expiration
_generateId(): Generates a unique ID based on current timestamp and logical time._getExpirationBound(): Calculates the timestamp boundary for expired transactions.
Confirmation Handlers
_confirmTransaction(uint64 transactionId, Transaction txn, uint8 custodianIndex): Records a custodian's confirmation. Executes and deletes transaction if threshold met._confirmDataUpdate(uint64 dataUpdateId, UpdateData du, uint8 custodianIndex): Records confirmation for data update. Applies update if threshold met.
Cleanup Functions
_removeExpiredTransactions(): Removes expired transactions from storage, limited by
_max_cleanup_operations._removeExpiredDataUpdate(): Removes expired data updates from storage, limited by
_max_cleanup_operations.
Getters
isConfirmed(uint32 mask, uint8 index): Returns whether a custodian has confirmed an object.getParameters(): Returns wallet configuration, including max queued transactions, custodian count, expiration time, and confirmation requirements.getTransaction(uint64 transactionId): Returns transaction details by ID.getUpdateData(uint64 updateDataId): Returns update data details by ID.getTransactions(): Returns array of non-expired queued transactions.getUpdateDatas(): Returns array of non-expired queued data updates.getTransactionIds(): Returns array of queued transaction IDs.getUpdateCodeIds(): Returns array of queued update IDs.getCustodians(): Returns array of all custodians.
Events
TransferAccepted(bytes payload): Emitted when a transfer is accepted (note: event usage not explicitly shown in code).
Fallback and Receive
Empty fallback and receive functions allow the contract to accept plain transfers and unknown calls.
Versioning
getVersion(): Returns the contract version ("1.0.0") and name ("UpdateCustodianMultisigWallet").
Interaction with Other System Components
This contract manages custodians who approve transactions and data updates.
Uses TVM internal message sending facilities for transfers with customizable flags and payloads.
Interacts with blockchain timestamps and logical time for ID generation and expiration handling.
Employs hashing of custodian keys and addresses for secure custodian identification.
Supports token transfers via a mapping of token IDs to amounts (
cc), integrating with ECC token standards.Requires external callers to provide correct public keys or addresses to verify custodian identity.
Important Implementation Details and Algorithms
Bitmask for Confirmations and Requests:
Custodian confirmations and queued request counts are efficiently tracked using bitmasks and 8-bit segments within 256-bit integers, allowing fast checks and updates without extensive looping.Transaction and Update Expiry:
Transactions and data updates have expiration times (1 hour). Expired entries are cleaned up lazily when custodians submit or confirm new requests, limited by a configurable max cleanup operations count.Dynamic Custodian Set Updates:
Custodian sets and confirmation requirements can be updated through a multisignature process, ensuring governance flexibility without redeploying the contract.Single-Custodian Shortcut:
If only one custodian exists, they can send transactions immediately without confirmations.Unique ID Generation:
IDs are generated from a combination of block.timestamp offset and logical time, ensuring uniqueness and sortable order.
Usage Examples
Submitting a Transaction
uint64 txId = wallet.submitTransaction(
destAddress,
1000000000, // 1 gram in nanograms
ccMapping, // ECC token amounts
true, // bounce flag
0, // flags
payloadCell // TvmCell with payload
);
Returns
0if executed immediately (single custodian), or a transaction ID for multisig confirmation.
Confirming a Transaction
wallet.confirmTransaction(txId);
Confirms the transaction with the caller's custodian identity.
Submitting Data Update
uint64 updateId = wallet.submitDataUpdate(
newOwnersPubkey,
newOwnersAddress,
newReqConfirms,
newReqConfirmsData
);
Queues a custodian change request requiring multisig approval.
Diagram: Contract Structure and Main Workflows
classDiagram
class UpdateCustodianMultisigWallet {
-optional~uint256~ m_ownerKey
-optional~address~ m_ownerAddress
-uint256 m_requestsMask
-uint256 m_requestsMaskData
-mapping~uint64, Transaction~ m_transactions
-mapping~uint64, UpdateData~ m_data
-mapping~uint256, Custodian~ m_custodians
-uint8 m_custodianCount
-uint8 m_defaultRequiredConfirmations
-uint8 m_defaultRequiredConfirmationsData
-uint _max_cleanup_operations
+constructor()
+sendTransaction()
+submitTransaction()
+confirmTransaction()
+submitDataUpdate()
+confirmDataUpdate()
+setMaxCleanupOperations()
+getParameters()
+getTransaction()
+getUpdateData()
+getTransactions()
+getUpdateDatas()
+getTransactionIds()
+getUpdateCodeIds()
+getCustodians()
}
class Custodian {
+optional~uint256~ owner_pubkey
+optional~address~ owner_address
+uint8 index
}
class Transaction {
+uint64 id
+uint32 confirmationsMask
+uint8 signsRequired
+uint8 signsReceived
+Custodian creator
+address dest
+uint128 value
+mapping~uint32, varuint32~ cc
+uint16 sendFlags
+TvmCell payload
+bool bounce
}
class UpdateData {
+uint64 id
+uint32 confirmationsMask
+uint8 signsRequired
+uint8 signsReceived
+Custodian creator
+uint256[] owners_pubkey
+address[] owners_address
+uint8 reqConfirms
+uint8 reqConfirmsData
}
UpdateCustodianMultisigWallet "1" *-- "multiple" Custodian : manages
UpdateCustodianMultisigWallet "1" *-- "multiple" Transaction : queues
UpdateCustodianMultisigWallet "1" *-- "multiple" UpdateData : queues
Transaction o-- Custodian : creator
UpdateData o-- Custodian : creator
This diagram illustrates the main classes and their relationships within the contract, highlighting how transactions and data updates are linked to custodians and managed by the wallet.