This repo shows how to create Gelato Web3 Functions tasks programmatically from an EOA and from a SAFE.
This is straightforward forward we will use the automate sdk to create and cancel the tasks.
const cid="QmSBdgzCUYcpwAWQPZc4oFn1zYwb4LovCXMPyrHUncBQ7S"
const { taskId, tx } = await automate.createBatchExecTask({
name: "Heartbeat 30 sec",
web3FunctionHash: cid,
web3FunctionArgs: {
// "arg1":"value",
},
trigger: {
interval: 30 * 1000,
type: TriggerType.TIME
},
});Code here
const automate = new AutomateSDK(chainId, deployer);
const taskId = "0xc35e11031c59558b2c4a9c35d9ab23fb4feae7f3e9f5fac689d95bdc9cb0d77d"
const { tx } = await automate.cancelTask(taskId)Code here
In order to crete tasks from a safe we will need to use the Safe Transaction Service API. We will instantiate Apikit following:
const txServiceUrl = 'https://safe-transaction-sepolia.safe.global'
const service = new SafeApiKit({ txServiceUrl, ethAdapter: ethAdapter })The custom txServiceUrl is for Sepolia, for other networks please visit here
For creating or cancelling the task we will follow a similar process:
- Propose tx
- Confirm tx (sent by all required signers);
- Execute tx
const automate = new AutomateSDK(chainId, deployer);
const cid="QmSBdgzCUYcpwAWQPZc4oFn1zYwb4LovCXMPyrHUncBQ7S"
const { taskId, tx } = await automate.prepareBatchExecTask({
name: "heartbeat",
web3FunctionHash: cid,
web3FunctionArgs: {
// "arg1":"value",
},
trigger: {
interval: 30 * 1000,
type: TriggerType.TIME,
},
},
{},
safeAddress // important to pass the safe address as task creator
);
Code here
$ npx hardhat run ./scripts/safe/create-task/propose-create.tsResults
{ predictedSafeAddress: '0x6b594E0eD457654FD3F129de134d343ab3bf8957' }
{ isSafeDeployed: true }
Proposed a transaction with Safe: 0x6b594E0eD457654FD3F129de134d343ab3bf8957
- safeTxHash: 0x72fd3bf3cc4f1040daace6f2c5c2990e0aedaaa6aef9f4dbdd55aad64ecff875
- Sender: 0x903918bB1903714E0518Ea2122aCeBfa27f11b6F
- Sender signature: 0xf7b5e057d2720ebbb5792da973c48194f0df6fde2b9e1334e2556dec8cc28b51505b287bb76587143ac23d6ac5b45cca98dbac3a7c8d7d4c94e255d9d871b1f21f
- TaskId: 0x6314532f55943780432bd60d1c2a25313db5c9ecf3662f93b6ee2c6b2e69bcb1
✨ Done in 9.11s.Every required signer has to confirm the transaction, this can be done programatically as shown below or in the safe UI
We will need to grab the SafeTxHash from previous script and run
- safeTxHash: 0x72fd3bf3cc4f1040daace6f2c5c2990e0aedaaa6aef9f4dbdd55aad64ecff875Code here
$ npx hardhat run ./scripts/safe/create-task/confirm-create.tsResults:
{ predictedSafeAddress: '0x6b594E0eD457654FD3F129de134d343ab3bf8957' }
{ isSafeDeployed: true }
Confirmed a transaction with Safe: 0x6b594E0eD457654FD3F129de134d343ab3bf8957
- safeTxHash: 0x72fd3bf3cc4f1040daace6f2c5c2990e0aedaaa6aef9f4dbdd55aad64ecff875
- Sender: 0x903918bB1903714E0518Ea2122aCeBfa27f11b6F
- Sender signature: 0xf7b5e057d2720ebbb5792da973c48194f0df6fde2b9e1334e2556dec8cc28b51505b287bb76587143ac23d6ac5b45cca98dbac3a7c8d7d4c94e255d9d871b1f21f
✨ Done in 5.96s.Once all signatures have been confirmed we are ready to execute. We will need here also to pass the txHash
Code here
$ npx hardhat run ./scripts/safe/create-task/execute-create.tsResults:
{ predictedSafeAddress: '0x6b594E0eD457654FD3F129de134d343ab3bf8957' }
{ isSafeDeployed: true }
Confirmed a transaction with Safe: 0x6b594E0eD457654FD3F129de134d343ab3bf8957
- txHash: 0xdee0a7b4d3f2ae3d163fee82c545ea76151b9ad2138f91af55edc0b310bc8b3a
✨ Done in 22.49s.In order to cancel the task we will require the TaskId and the process will be the same: propose, confirm and cancel.
When proposing the the tx in this case the payload is:
const automate = new AutomateSDK(chainId, deployer);
const taskId= "0x6314532f55943780432bd60d1c2a25313db5c9ecf3662f93b6ee2c6b2e69bcb1"
const {tx} = await automate.prepareCancelTask(taskId)$ npx hardhat run ./scripts/safe/create-task/propose-cancel.ts$ npx hardhat run ./scripts/safe/create-task/confirm-cancel.ts$ npx hardhat run ./scripts/safe/create-task/execute-cancel.tsThe withdrawal process from Gelato 1Balance consists of two on-chain transactions with an off-chain settlement step in between.
Important: Update the
safeAddressin ./scripts/safe/safe.ts to your Safe address on Polygon before running these scripts.
UpdatewithdrawalAmountin the propose scripts to the amount you wish to withdraw (USDC has 6 decimals, e.g.10000000= 10 USDC).
Contract: Gelato1Balance on Polygon
Token: USDC (0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359)
This submits a requestWithdrawal transaction to the 1Balance contract, signaling your intent to withdraw.
$ yarn withdrawal:propose-initiateCode here
Grab the safeTxHash from the propose output and paste it into confirm-withdrawal.ts.
$ yarn withdrawal:confirmPaste the same safeTxHash into execute-withdrawal.ts.
$ yarn withdrawal:executeAfter the requestWithdrawal transaction is confirmed on-chain, the Gelato backend needs to process and settle the request. This can take several hours.
During settlement, Gelato's backend:
- Detects the
LogRequestWithdrawalevent emitted by the contract. - Validates the withdrawal amount against your deposited balance.
- Updates the Merkle tree to include your withdrawal allocation.
- Settles a new Merkle root on-chain via the
settlefunction.
You can check if settlement is complete by querying:
https://api.gelato.digital/1balance/networks/mainnets/sponsors/<your-safe-address>
Look for _totalValidRequestedWithdrawAmount in the response. Once this value is greater than 0, your withdrawal is settled and ready to finalize.
The finalize script automatically handles the off-chain steps before proposing the on-chain withdraw transaction:
- Checks settlement status - Queries the Gelato API to verify
_totalValidRequestedWithdrawAmount > 0. If not yet settled, it exits with a message to retry later. - Fetches Merkle Proof - Retrieves the
_merkleProoffrom:The proof cryptographically validates your withdrawal against the current Merkle root stored in the contract.https://api.gelato.digital/1balance/networks/137/tokens/<usdc-address>/sponsors/<your-safe-address>/proof - Proposes the withdraw transaction - Encodes a call to the contract's
withdrawfunction with_token,_amount,_totalValidRequestedWithdrawAmount, and_merkleProof, then proposes it through the Safe.
$ yarn withdrawal:propose-finalizeCode here
Grab the safeTxHash from the propose output and paste it into confirm-withdrawal.ts.
$ yarn withdrawal:confirmPaste the same safeTxHash into execute-withdrawal.ts.
$ yarn withdrawal:executeOnce the transaction is confirmed, your USDC funds will be transferred to the Safe.