Gelato Network
Search
⌃K

Writing Web3 Functions

Web3 Function example

This web3 function updates an oracle smart contract with data returned by Coingecko's price API at an interval. Check out more examples here.
import { Web3Function, Web3FunctionContext } from "@gelatonetwork/web3-functions-sdk";
import { Contract, ethers } from "ethers";
import ky from "ky"; // we recommend using ky as axios doesn't support fetch by default
const ORACLE_ABI = [
"function lastUpdated() external view returns(uint256)",
"function updatePrice(uint256)",
];
Web3Function.onRun(async (context: Web3FunctionContext) => {
const { userArgs, gelatoArgs, provider } = context;
// Retrieve Last oracle update time
const oracleAddress = "0x71b9b0f6c999cbbb0fef9c92b80d54e4973214da";
const oracle = new Contract(oracleAddress, ORACLE_ABI, provider);
const lastUpdated = parseInt(await oracle.lastUpdated());
console.log(`Last oracle update: ${lastUpdated}`);
// Check if it's ready for a new update
const nextUpdateTime = lastUpdated + 300; // 5 min
const timestamp = gelatoArgs.blockTime;
console.log(`Next oracle update: ${nextUpdateTime}`);
if (timestamp < nextUpdateTime) {
return { canExec: false, message: `Time not elapsed` };
}
// Get current price on coingecko
const currency = "ethereum";
const priceData: any = await ky
.get(
`https://api.coingecko.com/api/v3/simple/price?ids=${currency}&vs_currencies=usd`,
{ timeout: 5_000, retry: 0 }
)
.json();
price = Math.floor(priceData[currency].usd);
console.log(`Updating price: ${price}`);
// Return execution call data
return {
canExec: true,
callData: oracle.interface.encodeFunctionData("updatePrice", [price]),
};
});
Create your function schema.json to specify your runtime configuration.
{
"web3FunctionVersion": "1.0.0",
"runtime": "js-1.0",
"memory": 128,
"timeout": 30,
"userArgs": {}
}
Note: For now the configuration is fixed and cannot be changed.

User arguments

  1. 1.
    Declare your expected userArgs in you schema, accepted types are 'string', 'string[]', 'number', 'number[]', 'boolean', 'boolean[]':
{
"web3FunctionVersion": "1.0.0",
"runtime": "js-1.0",
"memory": 128,
"timeout": 30,
"userArgs": {
"currency": "string",
"oracle": "string"
}
}
  1. 2.
    Access your userArgs from the Web3Function context:
Web3Function.onRun(async (context: Web3FunctionContext) => {
const { userArgs, gelatoArgs, secrets } = context;
// User args:
console.log('Currency:', userArgs.currency)
console.log('Oracle:', userArgs.oracle)
});
  1. 3.
    Pass user-args to the CLI to test your web3 function:
npx w3f test src/web3-functions/examples/oracle/index.ts --show-logs --user-args=currency:ethereum --user-args=oracle:0x6a3c82330164822A8a39C7C0224D20DB35DD030a
To pass array argument (eg string[]), you can use:
--user-args=arr:\[\"a\"\,\"b\"\]

State / Storage

Web3Functions are stateless scripts, that will run in a new & empty memory context on every execution. If you need to manage some state variable, we provide a simple key/value store that you can access from your web3 function context.
See the above example to read & update values from your storage:
import {
Web3Function,
Web3FunctionContext,
} from "@gelatonetwork/web3-functions-sdk";
Web3Function.onRun(async (context: Web3FunctionContext) => {
const { storage, provider } = context;
// Use storage to retrieve previous state (stored values are always string)
const lastBlockStr = (await storage.get("lastBlockNumber")) ?? "0";
const lastBlock = parseInt(lastBlockStr);
console.log(`Last block: ${lastBlock}`);
const newBlock = await provider.getBlockNumber();
console.log(`New block: ${newBlock}`);
if (newBlock > lastBlock) {
// Update storage to persist your current state (values must be cast to string)
await storage.set("lastBlockNumber", newBlock.toString());
}
return {
canExec: false,
message: `Updated block number: ${newBlock.toString()}`,
};
});
Test storage execution: npx w3f test src/web3-functions/examples/storage/index.ts --show-logs
You will see your updated key/values:
Simulated Web3Function Storage update:
✓ lastBlockNumber: '8321923'

Secrets

  1. 1.
    Fill up your secrets in .env file with SECRETS_ as prefix.
SECRETS_COINGECKO_API=https://api.coingecko.com/api/v3
  1. 2.
    Access your secrets from the Web3Function context:
// Get api from secrets
const coingeckoApi = await context.secrets.get("COINGECKO_API");
if (!coingeckoApi)
return { canExec: false, message: `COINGECKO_API not set in secrets` };
  1. 3.
    Store your secrets by using (Variables with the SECRETS_ prefix in .env will be stored):
yarn set-secrets
  1. 4.
    Test your resolver using secrets:
npx w3f test src/web3-functions/examples/secrets/index.ts --show-logs
  1. 5.
    View complete list of your secrets by using:
yarn list-secrets
  1. 6.
    To delete secrets, use:
yarn delete-secrets SECRET_KEY SECRET_KEY2