diff --git a/examples/example.js b/examples/example.js index 0d2acdc3..16718753 100644 --- a/examples/example.js +++ b/examples/example.js @@ -3,7 +3,8 @@ const grpc = require("@grpc/grpc-js"); const protoLoader = require("@grpc/proto-loader"); const { ethers } = require("ethers"); const { Wallet } = ethers; -const { UlidMonotonic } = require('id128'); +const { UlidMonotonic } = require("id128"); +const util = require("util"); const { TaskType, TriggerType } = require("./static_codegen/avs_pb"); @@ -17,6 +18,8 @@ const packageDefinition = protoLoader.loadSync("../protobuf/avs.proto", { }); const env = process.env.ENV || "development"; + +console.log("Current environment is: ", env); const privateKey = process.env.PRIVATE_KEY; // Make sure to provide your private key with or without the '0x' prefix const config = { @@ -109,14 +112,18 @@ async function listTask(owner, token) { const metadata = new grpc.Metadata(); metadata.add("authkey", token); - const result = await asyncRPC(client, "ListTasks", { - smart_wallet_address: process.argv[3] - }, metadata); - + const result = await asyncRPC( + client, + "ListTasks", + { + smart_wallet_address: process.argv[3], + }, + metadata + ); console.log(`Found ${result.tasks.length} tasks created by`, process.argv[3]); for (const item of result.tasks) { - console.log("\n\ntask id:", item.id, "taskdata", item,"\n=================================\n"); + console.log(util.inspect(item, { depth: 4, colors: true })); } } @@ -126,24 +133,7 @@ async function getTask(owner, token, taskId) { const result = await asyncRPC(client, "GetTask", { bytes: taskId }, metadata); - console.log("Inspect Task ID: ", taskId, "\n"); - for (const [key, value] of Object.entries(result)) { - if (key == "nodes") { - continue; - } - - console.log(`${key}:`.padEnd(25, " "), JSON.stringify(value, null, 2)); - } - - result.nodes.filter(e => e != null).map(node => { - for (const [key, value] of Object.entries(node)) { - if (!value) { - continue; - } - - console.log(`${key}:`.padEnd(25, " "), JSON.stringify(value, null, 2)); - } - }); + console.log(util.inspect(result, { depth: 4, colors: true })); } async function cancel(owner, token, taskId) { @@ -157,7 +147,7 @@ async function cancel(owner, token, taskId) { metadata ); - console.log("Canceled Task Data for ", taskId, "\n", result); + console.log("Response:\n", result); } async function deleteTask(owner, token, taskId) { @@ -171,20 +161,27 @@ async function deleteTask(owner, token, taskId) { metadata ); - console.log("Delete Task ", taskId, "\n", result); + console.log("Response:\n", result); } async function getWallets(owner, token) { const metadata = new grpc.Metadata(); metadata.add("authkey", token); - const walletsResp = await asyncRPC( + const walletsResp = await asyncRPC( client, "GetSmartAccountAddress", - { }, + {}, metadata ); + console.log( + `Response:\n`, + walletsResp + ); + + console.log("Fetching balances from RPC provider ..."); + // Update the provider creation const provider = new ethers.JsonRpcProvider(config[env].RPC_PROVIDER); @@ -199,22 +196,29 @@ async function getWallets(owner, token) { let wallets = []; for (const wallet of walletsResp.wallets) { - const balance = await provider.getBalance( - wallet.address - ); + const balance = await provider.getBalance(wallet.address); const balanceInEth = _.floor(ethers.formatEther(balance), 2); const tokenBalance = await tokenContract.balanceOf(wallet.address); const tokenDecimals = await tokenContract.decimals(); const tokenSymbol = await tokenContract.symbol(); - const tokenBalanceFormatted = _.floor(ethers.formatUnits(tokenBalance, tokenDecimals),2); - wallets.push({...wallet, balances: [ - `${balanceInEth} ETH`, - `${tokenBalanceFormatted} ${tokenSymbol}`, - ]}); + const tokenBalanceFormatted = _.floor( + ethers.formatUnits(tokenBalance, tokenDecimals), + 2 + ); + wallets.push({ + ...wallet, + balances: [ + `${balanceInEth} ETH`, + `${tokenBalanceFormatted} ${tokenSymbol}`, + ], + }); } - console.log("Smart wallet address for ", owner, "\n", wallets); + console.log( + `Listing smart wallet addresses for ${owner} ...\n`, + wallets + ); return wallets; } @@ -229,7 +233,7 @@ const createWallet = async (owner, token, salt, factoryAddress) => { { salt, factoryAddress }, metadata ); -} +}; const main = async (cmd) => { // 1. Generate the api token to interact with aggregator @@ -240,8 +244,16 @@ const main = async (cmd) => { switch (cmd) { case "create-wallet": salt = process.argv[3] || 0; - let smartWalletAddress = await createWallet(owner, token, process.argv[3], process.argv[4]); - console.log("generated smart wallet", smartWalletAddress) + let smartWalletAddress = await createWallet( + owner, + token, + process.argv[3], + process.argv[4] + ); + console.log( + `A new smart wallet with salt ${salt} is created for ${owner}:\nResponse:\n`, + smartWalletAddress + ); break; case "schedule": case "schedule-cron": @@ -256,14 +268,24 @@ const main = async (cmd) => { priceChainlink("${config[env].ORACLE_PRICE_CONTRACT}"), toBigInt("10000") ) > 0`; - await scheduleERC20TransferJob(owner, token, taskCondition); + const resultSchedule = await scheduleERC20TransferJob( + owner, + token, + taskCondition + ); + console.log("Response: \n", resultSchedule); break; case "schedule2": taskCondition = `bigCmp( priceChainlink("${config[env].ORACLE_PRICE_CONTRACT}"), toBigInt("99228171987813")) > 0`; - await scheduleERC20TransferJob(owner, token, taskCondition); + const resultSchedule2 = await scheduleERC20TransferJob( + owner, + token, + taskCondition + ); + console.log("Response: \n", resultSchedule2); break; case "schedule-generic": @@ -287,7 +309,13 @@ const main = async (cmd) => { )[0], toBigInt("2000") ) > 0`; - await scheduleERC20TransferJob(owner, token, taskCondition); + const resultScheduleGeneric = await scheduleERC20TransferJob( + owner, + token, + taskCondition + ); + + console.log("Response: \n", resultScheduleGeneric); break; case "tasks": @@ -331,7 +359,7 @@ const main = async (cmd) => { cancel : to cancel a task delete : to completely remove a task`); } -} +}; function getTaskData() { let ABI = ["function transfer(address to, uint amount)"]; @@ -355,25 +383,23 @@ async function scheduleERC20TransferJob(owner, token, taskCondition) { const smartWalletAddress = process.argv[3]; if (!smartWalletAddress) { console.log("invalid smart wallet address. check usage"); - return + return; } - console.log("\n\nTask body:", taskBody); + console.log("Task body:", taskBody); - console.log("\n\nTask condition:", taskCondition); + console.log("\nTask condition:", taskCondition); const metadata = new grpc.Metadata(); metadata.add("authkey", token); - console.log("Trigger type", TriggerType.EXPRESSIONTRIGGER); - let trigger = { - trigger_type: TriggerType.BLOCKTRIGGER, - block: { - interval: 5, // run every 5 block - }, - }; - + trigger_type: TriggerType.BLOCKTRIGGER, + block: { + interval: 5, // run every 5 block + }, + }; + if (process.argv[2] == "schedule-cron") { trigger = { trigger_type: TriggerType.TIMETRIGGER, @@ -383,78 +409,90 @@ async function scheduleERC20TransferJob(owner, token, taskCondition) { "0 */5 * * *", ], }, - } + }; } else if (process.argv[2] == "schedule-event") { trigger = { trigger_type: TriggerType.EVENTTRIGGER, event: { expression: taskCondition, - } - } + }, + }; } else if (process.argv[2] == "schedule-fixed") { trigger = { trigger_type: TriggerType.FIXEDEPOCHTRIGGER, at: { - epoches: [Math.floor(new Date().getTime() / 1000 + 3600 ), Math.floor(new Date().getTime() / 1000 + 7200 )] - } - } + epoches: [ + Math.floor(new Date().getTime() / 1000 + 3600), + Math.floor(new Date().getTime() / 1000 + 7200), + ], + }, + }; } else if (process.argv[2] == "schedule-manual") { trigger = { trigger_type: TriggerType.MANUALTRIGGER, manual: true, - } + }; } - const nodeIdOraclePrice = UlidMonotonic.generate().toCanonical(); - const nodeIdTransfer = UlidMonotonic.generate().toCanonical(); + const nodeIdOraclePrice = UlidMonotonic.generate().toCanonical(); + const nodeIdTransfer = UlidMonotonic.generate().toCanonical(); const nodeIdNotification = UlidMonotonic.generate().toCanonical(); + console.log("\nTrigger type", trigger.trigger_type); + const result = await asyncRPC( client, - 'CreateTask', + "CreateTask", { smart_wallet_address: smartWalletAddress, - nodes: [{ - task_type: TaskType.BRANCHTASK, - id: nodeIdOraclePrice, - name: 'check price', - branch: { - "if": { - expression: `bigCmp(priceChainlink("${config[env].ORACLE_PRICE_CONTRACT}"),toBigInt("10000") > 0`, - next: 'transfer_erc20_1' - } - } - }, { - task_type: TaskType.CONTRACTWRITETASK, - // id need to be unique. it will be assign to the variable - id: nodeIdTransfer, - // name is for our note only. use for display a humand friendly version - name: 'transfer token', - contract_write: { - // Our ERC20 test token - contract_address: config[env].TEST_TRANSFER_TOKEN, - call_data: taskBody, - } - }, { - task_type: TaskType.RESTAPITASK, - id: nodeIdNotification, - name: 'notification', - rest_api: { - url: "https://webhook.site/fd02e579-a58c-4dbd-8a74-0afa399c0912", - } - }], - - edges: [{ - id: UlidMonotonic.generate().toCanonical(), - // __TRIGGER__ is a special node. It doesn't appear directly in the task data, but it should be draw on the UI to show what is the entrypoint - source: '__TRIGGER__', - target: nodeIdOraclePrice, - }, { - id: UlidMonotonic.generate().toCanonical(), - // __trigger__ is a special node. It doesn't appear directly in the task nodes, but it should be draw on the UI to show what is the entrypoint - source: nodeIdOraclePrice, - target: nodeIdNotification, - }], + nodes: [ + { + task_type: TaskType.BRANCHTASK, + id: nodeIdOraclePrice, + name: "check price", + branch: { + if: { + expression: `bigCmp(priceChainlink("${config[env].ORACLE_PRICE_CONTRACT}"),toBigInt("10000") > 0`, + next: "transfer_erc20_1", + }, + }, + }, + { + task_type: TaskType.CONTRACTWRITETASK, + // id need to be unique. it will be assign to the variable + id: nodeIdTransfer, + // name is for our note only. use for display a humand friendly version + name: "transfer token", + contract_write: { + // Our ERC20 test token + contract_address: config[env].TEST_TRANSFER_TOKEN, + call_data: taskBody, + }, + }, + { + task_type: TaskType.RESTAPITASK, + id: nodeIdNotification, + name: "notification", + rest_api: { + url: "https://webhook.site/fd02e579-a58c-4dbd-8a74-0afa399c0912", + }, + }, + ], + + edges: [ + { + id: UlidMonotonic.generate().toCanonical(), + // __TRIGGER__ is a special node. It doesn't appear directly in the task data, but it should be draw on the UI to show what is the entrypoint + source: "__TRIGGER__", + target: nodeIdOraclePrice, + }, + { + id: UlidMonotonic.generate().toCanonical(), + // __trigger__ is a special node. It doesn't appear directly in the task nodes, but it should be draw on the UI to show what is the entrypoint + source: nodeIdOraclePrice, + target: nodeIdNotification, + }, + ], trigger, start_at: Math.floor(Date.now() / 1000) + 30, @@ -464,15 +502,15 @@ async function scheduleERC20TransferJob(owner, token, taskCondition) { metadata ); - console.log("Expression Task ID is:", result); + return result; } async function scheduleTimeTransfer(owner, token) { // Now we can schedule a task // 1. Generate the calldata to check condition const taskBody = getTaskData(); - console.log("\n\nTask body:", taskBody); - console.log("\n\nTask condition: Timeschedule", "*/2"); + console.log("Task body:", taskBody); + console.log("\nTask condition: Timeschedule", "*/2"); const metadata = new grpc.Metadata(); metadata.add("authkey", token); @@ -504,8 +542,6 @@ async function scheduleTimeTransfer(owner, token) { event: { expression: `topic0 == "123" && topic2 == "334"`, }, - - }, start_at: Math.floor(Date.now() / 1000) + 30, @@ -518,7 +554,6 @@ async function scheduleTimeTransfer(owner, token) { console.log("Expression Task ID is:", result); } - (async () => { try { main(process.argv[2]);