Queue operations
Methods for creating, listing, and managing queue operations in B2BINPAY DeFi API, including multisig approvals, nonces, and execution control
Use these methods to list, inspect, and manage queue operations for a deployment, including multisig configuration changes, rejects, and signatures.
Authorization
ApiKeyAuth Provide API key in X-API-Key header
In: header
Path Parameters
UUID
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidQuery Parameters
Page number (starts from 1)
0 < value <= 90071992547409911Number of items per page (max 100)
0 < value <= 10010Value in
- "asc"
- "desc"
Filter by createdAt date starting from this date
Filter by createdAt date up to this date
Response Body
application/json
curl -X GET "https://example.com/api/v1/deployments/123e4567-e89b-12d3-a456-426614174000/operations"{ "total": 100, "page": 1, "pageSize": 10, "items": [ { "id": "187654321987654321", "executeOperationId": "0x123e4567e89b12d3a45642661417400000000000000000000000000000000000", "nonce": "5", "operationType": "MULTISIG_CONFIG_CHANGE", "status": "PENDING", "calls": [ { "to": "0xa0b86a33e6c3b4c0b7b8c4e6f2d8e9f1a2b3c4d5", "value": "0", "data": "0xa9059cbb000000000000000000000000742d35cc6635c0532925a3b8d0a7f79ec35bdc52" } ], "payload": { "approvers": [ "0x123..." ], "threshold": 2 }, "signaturesCollected": 2, "signaturesRequired": 3, "txHash": "0x5555666677778888999900001111222233334444555566667777888899990000", "userSigned": false, "canSign": true, "canExecute": false, "canDelete": true, "canReject": true, "isBlocked": false, "createdAt": "2024-01-01T00:00:00.000Z", "createdBy": "0x0000000000000000000000000000000000000000", "signatures": [ { "user": "0x111d35cc6635c0532925a3b8d0a7f79ec35bdc11", "sign": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12" } ], "signatureBlob": "0x000000000000000000000000000000000000dead0041...", "expiresAt": "2024-01-01T01:00:00.000Z", "dappMetadata": { "dappName": "string", "dappUrl": "http://example.com", "icon": "http://example.com" } } ], "nextExecutableNonce": "5"}Authorization
ApiKeyAuth Provide API key in X-API-Key header
In: header
Path Parameters
UUID
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidEntity ID
Response Body
application/json
curl -X GET "https://example.com/api/v1/deployments/123e4567-e89b-12d3-a456-426614174000/operations/1234567890123456789"{ "id": "187654321987654321", "executeOperationId": "0x123e4567e89b12d3a45642661417400000000000000000000000000000000000", "nonce": "5", "operationType": "MULTISIG_CONFIG_CHANGE", "status": "PENDING", "calls": [ { "to": "0xa0b86a33e6c3b4c0b7b8c4e6f2d8e9f1a2b3c4d5", "value": "0", "data": "0xa9059cbb000000000000000000000000742d35cc6635c0532925a3b8d0a7f79ec35bdc52" } ], "payload": { "approvers": [ "0x123..." ], "threshold": 2 }, "signaturesCollected": 2, "signaturesRequired": 3, "txHash": "0x5555666677778888999900001111222233334444555566667777888899990000", "userSigned": false, "canSign": true, "canExecute": false, "canDelete": true, "canReject": true, "isBlocked": false, "createdAt": "2024-01-01T00:00:00.000Z", "createdBy": "0x0000000000000000000000000000000000000000", "signatures": [ { "user": "0x111d35cc6635c0532925a3b8d0a7f79ec35bdc11", "sign": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12" } ], "signatureBlob": "0x000000000000000000000000000000000000dead0041...", "expiresAt": "2024-01-01T01:00:00.000Z", "dappMetadata": { "dappName": "string", "dappUrl": "http://example.com", "icon": "http://example.com" }}Authorization
ApiKeyAuth Provide API key in X-API-Key header
In: header
Path Parameters
UUID
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidEntity ID
Response Body
curl -X DELETE "https://example.com/api/v1/deployments/123e4567-e89b-12d3-a456-426614174000/operations/1234567890123456789"Authorization
ApiKeyAuth Provide API key in X-API-Key header
In: header
Path Parameters
UUID
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidRequest Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
curl -X POST "https://example.com/api/v1/deployments/123e4567-e89b-12d3-a456-426614174000/operations/multisig-config" \ -H "Content-Type: application/json" \ -d '{ "approvers": [ "0x0000000000000000000000000000000000000000" ], "threshold": 1, "calls": [ { "to": "0xa0b86a33e6c3b4c0b7b8c4e6f2d8e9f1a2b3c4d5", "value": "0", "data": "0xa9059cbb000000000000000000000000742d35cc6635c0532925a3b8d0a7f79ec35bdc52" } ] }'{ "id": "187654321987654321", "executeOperationId": "0x123e4567e89b12d3a45642661417400000000000000000000000000000000000", "nonce": "5", "operationType": "MULTISIG_CONFIG_CHANGE", "status": "PENDING", "calls": [ { "to": "0xa0b86a33e6c3b4c0b7b8c4e6f2d8e9f1a2b3c4d5", "value": "0", "data": "0xa9059cbb000000000000000000000000742d35cc6635c0532925a3b8d0a7f79ec35bdc52" } ], "payload": { "approvers": [ "0x123..." ], "threshold": 2 }, "signaturesCollected": 2, "signaturesRequired": 3, "txHash": "0x5555666677778888999900001111222233334444555566667777888899990000", "userSigned": false, "canSign": true, "canExecute": false, "canDelete": true, "canReject": true, "isBlocked": false, "createdAt": "2024-01-01T00:00:00.000Z", "createdBy": "0x0000000000000000000000000000000000000000", "signatures": [ { "user": "0x111d35cc6635c0532925a3b8d0a7f79ec35bdc11", "sign": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12" } ], "signatureBlob": "0x000000000000000000000000000000000000dead0041...", "expiresAt": "2024-01-01T01:00:00.000Z", "dappMetadata": { "dappName": "string", "dappUrl": "http://example.com", "icon": "http://example.com" }}Authorization
ApiKeyAuth Provide API key in X-API-Key header
In: header
Path Parameters
UUID
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidRequest Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
curl -X POST "https://example.com/api/v1/deployments/123e4567-e89b-12d3-a456-426614174000/operations/reject" \ -H "Content-Type: application/json" \ -d '{ "nonce": "0" }'{ "id": "187654321987654321", "executeOperationId": "0x123e4567e89b12d3a45642661417400000000000000000000000000000000000", "nonce": "5", "operationType": "MULTISIG_CONFIG_CHANGE", "status": "PENDING", "calls": [ { "to": "0xa0b86a33e6c3b4c0b7b8c4e6f2d8e9f1a2b3c4d5", "value": "0", "data": "0xa9059cbb000000000000000000000000742d35cc6635c0532925a3b8d0a7f79ec35bdc52" } ], "payload": { "approvers": [ "0x123..." ], "threshold": 2 }, "signaturesCollected": 2, "signaturesRequired": 3, "txHash": "0x5555666677778888999900001111222233334444555566667777888899990000", "userSigned": false, "canSign": true, "canExecute": false, "canDelete": true, "canReject": true, "isBlocked": false, "createdAt": "2024-01-01T00:00:00.000Z", "createdBy": "0x0000000000000000000000000000000000000000", "signatures": [ { "user": "0x111d35cc6635c0532925a3b8d0a7f79ec35bdc11", "sign": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12" } ], "signatureBlob": "0x000000000000000000000000000000000000dead0041...", "expiresAt": "2024-01-01T01:00:00.000Z", "dappMetadata": { "dappName": "string", "dappUrl": "http://example.com", "icon": "http://example.com" }}Authorization
ApiKeyAuth Provide API key in X-API-Key header
In: header
Path Parameters
UUID
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidEntity ID
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
curl -X POST "https://example.com/api/v1/deployments/123e4567-e89b-12d3-a456-426614174000/operations/1234567890123456789/sign" \ -H "Content-Type: application/json" \ -d '{ "signature": "string" }'{ "signaturesCollected": 2, "signaturesRequired": 3, "canExecute": false, "userSigned": false, "signatures": [ { "user": "0x111d35cc6635c0532925a3b8d0a7f79ec35bdc11", "sign": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12" } ], "operationId": "187654321987654321"}Authorization
ApiKeyAuth Provide API key in X-API-Key header
In: header
Path Parameters
UUID
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidEntity ID
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
curl -X PATCH "https://example.com/api/v1/deployments/123e4567-e89b-12d3-a456-426614174000/operations/1234567890123456789/nonce" \ -H "Content-Type: application/json" \ -d '{ "nonce": "0" }'{ "id": "187654321987654321", "executeOperationId": "0x123e4567e89b12d3a45642661417400000000000000000000000000000000000", "nonce": "5", "operationType": "MULTISIG_CONFIG_CHANGE", "status": "PENDING", "calls": [ { "to": "0xa0b86a33e6c3b4c0b7b8c4e6f2d8e9f1a2b3c4d5", "value": "0", "data": "0xa9059cbb000000000000000000000000742d35cc6635c0532925a3b8d0a7f79ec35bdc52" } ], "payload": { "approvers": [ "0x123..." ], "threshold": 2 }, "signaturesCollected": 2, "signaturesRequired": 3, "txHash": "0x5555666677778888999900001111222233334444555566667777888899990000", "userSigned": false, "canSign": true, "canExecute": false, "canDelete": true, "canReject": true, "isBlocked": false, "createdAt": "2024-01-01T00:00:00.000Z", "createdBy": "0x0000000000000000000000000000000000000000", "signatures": [ { "user": "0x111d35cc6635c0532925a3b8d0a7f79ec35bdc11", "sign": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12" } ], "signatureBlob": "0x000000000000000000000000000000000000dead0041...", "expiresAt": "2024-01-01T01:00:00.000Z", "dappMetadata": { "dappName": "string", "dappUrl": "http://example.com", "icon": "http://example.com" }}Sign a queue operation with a private key (EIP-712)
Queue operations are signed using EIP‑712 typed data. The signature is created off‑chain with a raw private key, without a wallet UI, and authorizes execution of a multisig operation on‑chain.
What is signed
Only the following data is signed:
Execute {
Call[] calls;
uint256 nonce;
}No other fields from the queue operation are included in the signature.
Input data sources
From queue operation (API)
To build the signed payload, load the queue operation from the API:
GET /api/v1/deployments/{deploymentId}/operationsGET /api/v1/deployments/{deploymentId}/operations/{operationId}
From the queue operation object, use only:
{
"nonce": "1",
"calls": [
{
"to": "0xf127e5b7666f51aa346f374213113298014f5969",
"value": "100000000000000",
"data": "0x"
}
]
}When building the typed data:
- Treat
nonceasuint256. - Treat
valueasuint256. - Treat
dataas a hex‑encodedbytesvalue (the literal"0x"is valid for empty data).
From deployment and network
The EIP‑712 domain uses deployment and network data:
name— alwaysMultiSigWallet.version— current smart contract version.chainId— blockchain chain ID of the deployment.verifyingContract— address of the multisig contract.
You can obtain verifyingContract from the account:
GET /api/v1/accountsGET /api/v1/accounts/{accountId}
Use the value from the account.contract field for the multisig contract address.
EIP-712 typed data structure
The exact typed data that is signed has the following structure:
{
"domain": {
"name": "MultiSigWallet",
"version": "1.0.0",
"chainId": "11155111",
"verifyingContract": "0x71db8821df07d95f35d7c3bef22987397a965060"
},
"primaryType": "Execute",
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Execute": [
{ "name": "calls", "type": "Call[]" },
{ "name": "nonce", "type": "uint256" }
],
"Call": [
{ "name": "to", "type": "address" },
{ "name": "value", "type": "uint256" },
{ "name": "data", "type": "bytes" }
]
},
"message": {
"calls": [
{
"to": "0xf127e5b7666f51aa346f374213113298014f5969",
"value": "100000000000000",
"data": "0x"
}
],
"nonce": "1"
}
}Use this structure as a template. Do not change field names, types, or their order when building the typed data object.
Signing algorithm
Step 1. Build EIP-712 typed data
- Use the structure shown above with
domain,types,primaryType, andmessage. - Encode all numeric values (
chainId,nonce,value) asuint256.
Step 2. Compute the EIP-712 digest
The digest is computed as:
keccak256(
"\x19\x01" ||
hashDomain(domain) ||
hashStruct(Execute(message))
)Standard EIP‑712 libraries perform this step automatically when you sign typed data.
Step 3. Sign the digest with a private key
Sign the digest using ECDSA over secp256k1:
signature = sign(digest, privateKey)The resulting signature has the format:
0x{r}{s}{v}Where:
r— 32 bytes.s— 32 bytes.v— 1 byte.
Example signature
Example of a valid signature value:
0xf8d5a66ed464b5d39bf2b3f6c45932c901467b84bdfc4d534a24dcc532569bf3\
27b3f19289912d223f69aceeab7a61edbffb1fc26d755e1db53f68263cbe03491bSubmit the signature to the API
After computing the signature, submit it using the Sign operation endpoint:
POST /api/v1/deployments/{deploymentId}/operations/{operationId}/sign
x-api-key: {your-api-key}
Content-Type: application/json
Accept: application/json
{
"signature": "0x..."
}On success, the API returns the updated signature status for the operation. If the same signer submits another signature for the same operation, the API returns a conflict error.
Common errors when signing
Common issues when building or submitting signatures include:
Invalid signature— incorrect domain (chainIdorverifyingContractdo not match the deployment).Invalid signature— wrong data types in the message (for example,noncepassed as a string instead ofuint256in the typed data).Invalid signature—callsarray order does not match the operation in the queue.You have already signed this operation— the same address already submitted a signature.canSign = falsein the operation — the signer address is not an approver or is not allowed to sign.
Summary
- Extract
calls[]andnoncefrom the queue operation. - Build the EIP‑712
Executetyped data (domain,types,message). - Sign the EIP‑712 digest with a private key.
- Submit the resulting signature to the B2BINPAY DeFi API.
Execute a READY queue operation with a private key
When a queue operation reaches the READY status and canExecute = true, you execute it by sending a regular Ethereum transaction to the deployed MultiSigWallet contract and calling:
function execute(Operation[] operations) external returns (bytes[][] results);
struct Operation {
Call[] calls;
bytes signatures; // packed signatures
bytes32 id;
}
struct Call {
address to;
uint256 value;
bytes data;
}Preconditions
The queue operation must satisfy all of the following:
status = "READY".canExecute = true.signaturesCollected >= signaturesRequired.- The
signaturesarray in the API response contains at least the threshold number of signatures.
Required inputs
From API (queue operation)
executeOperationId— used asOperation.id.calls[]— used asOperation.calls.signatures[]— used to build packed bytes forOperation.signatures.
From deployment and network
verifyingContract— multisig contract address for the deployment:GET /api/v1/accountsGET /api/v1/accounts/{accountId}- use
account.contract.
chainId— chain ID of the network where the multisig is deployed.rpcUrl— RPC endpoint for sending the transaction.executorPrivateKey— private key of the externally owned account (EOA) that sends the transaction.
Build Operation.calls
Convert each API call object into the Solidity Call struct:
to→Call.to.value(decimal string) →Call.value(uint256).data(hex string) →Call.data(bytes).
Keep the order of calls exactly the same as in the queue operation and in the EIP‑712 signing step.
Build Operation.signatures (packed bytes)
In the API response, signatures are returned as separate entries:
"signatures": [
{ "user": "0x...", "sign": "0x<65 bytes>" }
]The contract expects a single bytes value:
bytes signatures; // NOT bytes[]Signature format
Each signature is a standard 65‑byte ECDSA signature:
r (32 bytes) || s (32 bytes) || v (1 byte)For example:
0xf8d5...3491bPacking rule
Build Operation.signatures as:
packedSignatures = sig1 || sig2 || ... || sigNSort signatures by signer address in ascending alphabetical order before concatenation.
Build the operations array
Even if you execute a single queue operation, you must pass an array with one element:
operations = [
Operation({
calls: [...],
signatures: packedSignatures,
id: executeOperationId
})
];ABI-encode execute(operations)
Encode the function call data for:
execute((Call[] calls, bytes signatures, bytes32 id)[] operations)This produces the transaction data field that you send to the multisig contract.
Build, sign, and broadcast the Ethereum transaction
Transaction fields
Set the transaction fields as follows:
to— multisig contract address (verifyingContract).data— ABI‑encodedexecute(operations)call.value—0.chainId— correct chain ID (for example, Sepolia11155111).- Gas parameters — EIP‑1559 fields (
maxFeePerGas,maxPriorityFeePerGas) appropriate for the network. nonce— EOA nonce of the executor account (this is not the multisig queue nonce).
Sign
Sign the transaction with executorPrivateKey using ECDSA (secp256k1).
Broadcast
Send the raw signed transaction through the RPC endpoint, for example using eth_sendRawTransaction. The result is a txHash.
Expected on-chain result
If the transaction succeeds:
- The contract verifies the packed signatures internally (for example, via
checkSignatures(hash, signatures)). - All
callsare executed in order. - An
ExecuteSuccess(nonce, digest, id)event is emitted. - The function returns operation and call‑level results as
bytes[][] results.
The backend then updates the queue operation:
statuschanges toEXECUTED.txHashis populated with the resulting on‑chain transaction hash.
Common reverts and errors
Common revert classes when executing operations include:
InsufficientSignatures(signatures, threshold)— packed signatures contain fewer signatures than the required threshold.InvalidSignature(owner)— signature bytes, signed digest, or ordering are incorrect for at least one signer.DuplicateSignature(owner)— the same signer appears more than once in the packed signatures.FailedCall— one of the internal calls reverted.InsufficientBalance(balance, needed)— the multisig contract lacks enough ETH for thevaluetransfers.ReentrancyGuardReentrantCall— a reentrancy attempt was detected during execution.
Última actualización