Execute & Broadcast
Note: "safe" is sometimes used in method names or param names for the Avocado RPC, "safe" there refers to an "avocado".
Execution differs between Avocado Personal (1 signer, index 0) and Avocado Multisigs.
Personal (index == 0 && requiredSigners == 1)
index 0 is treated as AvocadoPpersonal on https://avocado.instadapp.io/
const chainId = (await polygonProvider.getNetwork()).chainId; // e.g. when executing on Polygon provider
const txHash = await avocadoProvider.send("txn_broadcast", [
{
signatures: [
{
signature: "0xsignature", // signature as built in previous step
signer: "0xsigner", // signer address that signed the signature
},
],
message: txPayload, // transaction payload as built in previous step
owner: "avocado owner", // avocado owner EOA address
safe: "avocado address", // avocado address
index: "0",
targetChainId: chainId,
executionSignature: undefined, // only required when index > 0 || signatures.length > 1
},
]);
Multisig (index > 0 || signatures.length > 1)
Attention:
executionSignature
might be subject to later changes, it is not final yet.const executionTypes = {
Cast: [
{ name: "params", type: "CastParams" },
{ name: "forwardParams", type: "CastForwardParams" },
{ name: "signatures", type: "SignatureParams[]" },
],
CastParams: [
{ name: "actions", type: "Action[]" },
{ name: "id", type: "uint256" },
{ name: "avoNonce", type: "int256" },
{ name: "salt", type: "bytes32" },
{ name: "source", type: "address" },
{ name: "metadata", type: "bytes" },
],
Action: [
{ name: "target", type: "address" },
{ name: "data", type: "bytes" },
{ name: "value", type: "uint256" },
{ name: "operation", type: "uint256" },
],
CastForwardParams: [
{ name: "gas", type: "uint256" },
{ name: "gasPrice", type: "uint256" },
{ name: "validAfter", type: "uint256" },
{ name: "validUntil", type: "uint256" },
{ name: "value", type: "uint256" },
],
SignatureParams: [
{ name: "signature", type: "bytes" },
{ name: "signer", type: "address" },
],
};
const avocadoRPCChainId = "634";
const chainId = (await polygonProvider.getNetwork()).chainId; // e.g. when executing later on Polygon
const domain = {
name: domainName, // see previous steps
version: domainVersion, // see previous steps
chainId: avocadoRPCChainId,
verifyingContract: avocadoAddress, // see previous steps
salt: ethers.utils.solidityKeccak256(["uint256"], [chainId]), // salt is set to actual chain id where execution happens
};
// the execution signature is used to verify that given enough valid signatures have been collected,
// one of the allowed signers is triggering the actual execution of the signed actions
const avoSigner = provider.getSigner();
const executionSignature = await avoSigner._signTypedData(domain, executionTypes, txPayload);
const txHash = await avocadoProvider.send("txn_broadcast", [
{
signatures: [
{
signature: "0xsignature1", // signature 1 as built in previous step
signer: "0xsigner1", // signer address that signed the signature 1
},
{
signature: "0xsignature2", // signature 2 as built in previous step by some other allowed signer
signer: "0xsigner2", // signer address that signed the signature 2
},
],
message: txPayload, // transaction payload as built in previous step
owner: "avocado owner", // avocado owner EOA address
safe: "avocado address", // avocado address
index: "0",
targetChainId: chainId,
executionSignature,
},
]);