From 0c5a0b7dc1e0117ec4159bc6165692042d0fef09 Mon Sep 17 00:00:00 2001 From: arthurgousset <46296830+arthurgousset@users.noreply.github.com> Date: Fri, 16 Feb 2024 17:03:31 +0000 Subject: [PATCH] feat(web3js): adds ERC20 Transfer function Tested: Works as expected Transaction: https://alfajores.celoscan.io/tx/0x7c3d89e1c89affe40837a85292ac363a7a7d47fe856199f2c8978d314be51826 --- erc20Abi.ts | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++ web3.ts | 49 ++++++++- 2 files changed, 347 insertions(+), 5 deletions(-) create mode 100644 erc20Abi.ts diff --git a/erc20Abi.ts b/erc20Abi.ts new file mode 100644 index 0000000..168fdcb --- /dev/null +++ b/erc20Abi.ts @@ -0,0 +1,303 @@ +export const ERC20ABI = [ + { + "constant": true, + "inputs": [], + "name": "mintingFinished", + "outputs": [{ "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [{ "name": "", "type": "string" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "_spender", "type": "address" }, + { "name": "_value", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "name": "_token", "type": "address" }], + "name": "reclaimToken", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [{ "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "_from", "type": "address" }, + { "name": "_to", "type": "address" }, + { "name": "_value", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [{ "name": "", "type": "uint8" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "unpause", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "_to", "type": "address" }, + { "name": "_amount", "type": "uint256" } + ], + "name": "mint", + "outputs": [{ "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "name": "value", "type": "uint256" }], + "name": "burn", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "claimOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "paused", + "outputs": [{ "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "_spender", "type": "address" }, + { "name": "_subtractedValue", "type": "uint256" } + ], + "name": "decreaseApproval", + "outputs": [{ "name": "success", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "_owner", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "finishMinting", + "outputs": [{ "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "pause", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [{ "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [{ "name": "", "type": "string" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "_to", "type": "address" }, + { "name": "_value", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "_spender", "type": "address" }, + { "name": "_addedValue", "type": "uint256" } + ], + "name": "increaseApproval", + "outputs": [{ "name": "success", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "name": "_owner", "type": "address" }, + { "name": "_spender", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pendingOwner", + "outputs": [{ "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { "anonymous": false, "inputs": [], "name": "Pause", "type": "event" }, + { "anonymous": false, "inputs": [], "name": "Unpause", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "burner", "type": "address" }, + { "indexed": false, "name": "value", "type": "uint256" } + ], + "name": "Burn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "to", "type": "address" }, + { "indexed": false, "name": "amount", "type": "uint256" } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "MintFinished", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "previousOwner", "type": "address" } + ], + "name": "OwnershipRenounced", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "previousOwner", "type": "address" }, + { "indexed": true, "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "owner", "type": "address" }, + { "indexed": true, "name": "spender", "type": "address" }, + { "indexed": false, "name": "value", "type": "uint256" } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "from", "type": "address" }, + { "indexed": true, "name": "to", "type": "address" }, + { "indexed": false, "name": "value", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/web3.ts b/web3.ts index 2903cdb..5e648aa 100644 --- a/web3.ts +++ b/web3.ts @@ -1,7 +1,46 @@ -import { Web3 } from 'web3'; -import { Connection, CeloProvider } from '@celo/connect'; +import Web3 from "web3"; +import { Connection } from "@celo/connect"; +import { ERC20ABI } from "./erc20Abi"; +import "dotenv/config"; // use to read private key from environment variable -const web3 = new Web3("https://alfajores-forno.celo-testnet.org") // Celo testnet -const connection = new Connection(web3) +const PRIVATE_KEY = process.env.PRIVATE_KEY; +if (!PRIVATE_KEY) { + throw new Error( + "PRIVATE_KEY is not set in .env file. Please set PRIVATE_KEY= in .env file." + ); +} +const RECIPIENT = "0x22579CA45eE22E2E16dDF72D955D6cf4c767B0eF"; // arbitrary address +const CONTRACT_ADDRESS = "0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1"; // cUSD contract address -connection.setProvider(CeloProvider) \ No newline at end of file +// Set up web3js client +const web3 = new Web3("https://alfajores-forno.celo-testnet.org"); // Celo testnet +const connection = new Connection(web3); + +// Set up account +const account = web3.eth.accounts.wallet.add(`0x${PRIVATE_KEY}`); +const sender = web3.eth.accounts.wallet[0].address; + +// Set up ERC20 contract +const contract = new web3.eth.Contract(ERC20ABI, CONTRACT_ADDRESS); + +async function erc20Transfer() { + console.log(`Initiating fee currency transaction...`); + + // TODO: Adjust the amount to send based on the token's decimals (USDC has 6 decimals) + const transactionReceipt = await contract.methods + .transfer(RECIPIENT, web3.utils.toWei("0.01", "ether")) + .send({ + from: sender, + // gasLimit: // TODO: implement gas estimation + maxPriorityFeePerGas: web3.utils.toWei("10", "gwei"), + maxFeePerGas: web3.utils.toWei("10", "gwei"), + // feeCurrency: // TODO: implement fee currency + }); + + console.log(transactionReceipt); +} + +// Initiate the transfer +erc20Transfer().catch((err) => { + console.error("An error occurred:", err); +});