Advanced use-cases

Getting Avocado smart wallet details

To get all detail information for a certain Avocado, like the index, deployment information, signers etc. simply directly ask data from the provider:

// getting Avocado details
const avocadoDetails = await avocadoProvider.send("api_getSafe", ["avocado address"]);

Getting signers <> Avocado

To get all signers for an Avocado you can query the details also through the provider, which has a property signers:

// getting Avocado details
const avocadoDetails = await avocadoProvider.send("api_getSafe", ["avocado address"]);

const signers = avocadoDetails.signers;

To get all Avocados for a signer:

const avocados = await avocadoProvider.send("api_getSafes", [{ address: "signer address", multisig: true }]);

// `avocados.data` is an array of avocado details

Get USDC balance by avocado address

const balance = await avocadoProvider.getBalance("0xavocadoAddress");
// or const balance = await avocadoProvider.send('api_getBalance', ["0xavocadoAddress", "success"]);

const balanceWithPendingDeposits = await avocadoProvider.send("api_getBalance", ["0xavocadoAddress", "pending"]);

// !! balance will be in hex and 10**18 !! so to get to the amount, e.g. use:
console.log("Amount: " + (Number(balance) / 1e18).toFixed(2));

// or use bignumber.js etc:
// console.log("Amount: " + new BigNumber(balance).dividedBy(10 ** 18).toFormat());

Participate in Reveune Sharing Program:

Make sure to configure the source param to earn half of the Avocado up-charge through the Revenue Sharing Program.

In step build transaction payload just make sure to set the source address:

const referralAddress = "0x**_**"; // Default: "0x000000000000000000000000000000000000Cad0" // If Source address is passed, then half of the Avocado up-charge is shared with the referral address.

const txPayload: ITransactionPayload = {
  params: {
    // [...]
    // source for referral system
    source: referralAddress, // <-------------- Set this !!
    // [...]
  },
};

Top-up USDC Gas Balance:

The unified USDC gas balance for an Avocado smart wallet can be topped-up by sending funds to the USDC deposit address on any supported chain.

Note: On Avalanche, USDC is utilized as gas, not USDC.e.

!!   Attention   !!: The transfer must be initiated from the Avocado smart wallet itself!

In step build transaction payload create the action as follows:

// Top-up USDC gas (transfer must be initiated from the Avocado smart wallet itself!)

const USDC_DEPOSIT_ADDRESS = "0xE8385fB3A5F15dED06EB5E20E5A81BF43115eb8E";

// Set this to the correct USDC token address on the chain that the transfer is happening on:
const usdcAddress = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";

// Replace "10" with the amount of USDC to top-up (USDC has 6 decimals)
const usdcAmount = ethers.utils.parseUnits("10", 6);

const usdcInterface = new ethers.utils.Interface(["function transfer(address to, uint amount) returns (bool)"]);
const calldata = usdcInterface.encodeFunctionData("transfer", [
  USDC_DEPOSIT_ADDRESS, // to
  usdcAmount,
]); // create calldata from interface

const txPayload: ITransactionPayload = {
  params: {
    actions: [
      {
        target: usdcAddress,
        data: calldata,
        value: "0",
        operation: "0",
      },
    ],
    // [...]
  },
};

// 2. sign payload
// 3. execute

And then follow the standard steps to execute the tx thereafter as explained in Getting started.

Checking if the transaction was successful

See Handling errors.

Time-limiting validity

For Avocado transactions it is possible to time limit the validity of a signed payload.

This is possible with the optional params validUntil & validAfter, you can set either one or both params:

// get current time in milliseconds divided by 1000 -> seconds
const currentTimeInSeconds = parseInt(Number(new Date().getTime() / 1000).toFixed(0));

// example transaction
const txPayload: ITransactionPayload = {
  params: {
    // ...
  },

  forwardParams: {
    gas: "0",
    gasPrice: "0",
    // e.g. limiting time validity for 1 hour starting in 10 minutes
    validAfter: (currentTimeInSeconds + 10 * 60).toString(), // only valid starting in 10 minutes
    validUntil: (currentTimeInSeconds + 70 * 60).toString(), // valid until 70 minutes from now
    value: "0",
  },
};

// 2. sign payload
// 3. execute (in valid timeframe)

Verifying signatures / simulating execution

Note that executing a transaction with avocadoProvider.send("txn_broadcast", [...] will automatically verify validity of the signatures first.

If you explicitly want to manually verify the validty of signatures and simulate if execution will (likely) pass for a certain transaction you can do so by passing dryRun set to true:

// will throw an RPC error if execution fails for any reason, otherwise returns expected gasLimit:
// (Note: behavior might be different if not using ethers@v5)
const gasLimit = await avocadoProvider.send("txn_broadcast", [
  {
    signatures: [], // signatures
    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,
    dryRun: true, // <----- Set dryRun to true
  },
]);

// gas limit is in hex (if successful), convert with Number(gasLimit)

Using a non-sequential nonce

Every transaction in the Avocado smart wallet uses up a sequential nonce. You can use a predictable non-sequential nonce instead if needed. This might be useful for cases where transactions have to be executed in a non-predicatable order.

To use a non-sequential nonce when sending the transaction set avoNonce to -1:

// example transaction
const txPayload: ITransactionPayload = {
  params: {
    // [...]
    avoNonce: "-1", // set avoNonce to `-1` to use a non-sequential nonce
    // [...]
  },
};

// 2. sign payload
// 3. execute

To predict the non-sequential nonce you can use the getSigDigest() method directly interacting with the Avocado contract:

const expectedNonce = await avocado.getSigDigest(
  txPayload.params, // as set when building the transaction payload
  txPayload.forwardParams // as set when building the transaction payload
);

Executing config methods

Some methods on the Avocado smart wallet can only be self-called, meaning only the Avocado smart wallet itself can execute them. Those methods are usually config methods such as:

  • trigger an upgrade
  • adding a smart contract signature
  • occupying nonces (=cancel previously signed transactions)
  • adding / removing a signer
  • configuring the number of required signers for Multisigs

E.g. to add a signer:

// adding Vitalik as a signer (& setting required signers to 1)
const calldata = avocado.interface.encodeFunctionData("addSigners", [
  ["0xd8da6bf26964af9d7eed9e03e53415d37aa96045"], // signers to add (must be sorted ascending)
  1, // required signatures
]);

// transaction with action to add signer
const txPayload: ITransactionPayload = {
  params: {
    actions: [
      {
        target: avocadoAddress, // target is Avocado itself
        data: calldata,
        value: "0",
        operation: "0",
      },
    ],
    // [...]
  },
};
// 2. sign payload
// 3. execute

You can also interact this way directly with other Avocado contracts (might not be sending the transaction through the Avocado though), e.g. to manually trigger a deployment at the AvoFactory etc.

!!   Attention   !!: Be aware of the different possible versions of Avocado smart wallets! Not all versions might support the things you want to do, e.g. legacy versions do not support signers. You can find out about this through the Contract docs section or by directly looking at the source code.