Skip to content

Commit

Permalink
USDC: @celo/connect + web3js demo (#3)
Browse files Browse the repository at this point in the history
* refactor(viem): renames function to `nativeTransfer()`

* chore(web3js): imports `@celo/connect` and `web3`

* chore(web3js): initialises web3js demo with @celo/connect

* feat(web3js): adds ERC20 Transfer function

Tested: Works as expected
Transaction: https://alfajores.celoscan.io/tx/0x7c3d89e1c89affe40837a85292ac363a7a7d47fe856199f2c8978d314be51826

* chore(viem): adds TODO comments

- implement gas estimation
- adjust send amount based on ERC20 decimals

* feat(web3js): adds feeCurrency field in transaction object

Unfortunately, transaction is still EIP1559 and not CIP64.
For example: https://alfajores.celoscan.io/tx/0x3f8881bcf2c15e30b18d4e465d3865224071a5ee21e8f701dc6be377794d00dc

* chore(web3js): adds `LocalWallet` to make CIP64 tx

* chore(web3js): set `web3js` from `^4.5.0` to `1.10`

This fixes a bug with gas estimation. The `@celo/connect` library is calling a method from web3js.

```ts
estimateGas = async (
    tx: CeloTx,
    gasEstimator: (tx: CeloTx) => Promise<number> = this.web3.eth.estimateGas,
    caller: (tx: CeloTx) => Promise<string> = this.web3.eth.call
  ): Promise<number>
```

Source: https://github.com/celo-org/developer-tooling/blob/a884b24a242829a9425580e0b75f40526228838f/packages/sdk/connect/src/connection.ts#L358

Because of the version mismatch, the call fails silently.

* chore(web3js): removes gas related fields and fixes ERC20 ABI

- gas estimation is done automatically
- with web3js@1.10, ERC20 ABI has to be of type `AbiItem[]`
  • Loading branch information
arthurgousset authored Feb 21, 2024
1 parent 51ee2d7 commit d0cd7c8
Show file tree
Hide file tree
Showing 5 changed files with 3,405 additions and 38 deletions.
303 changes: 303 additions & 0 deletions erc20Abi.ts
Original file line number Diff line number Diff line change
@@ -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"
}
]
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
"typescript": "^5.3.3"
},
"dependencies": {
"@celo/connect": "^5.1.2",
"@celo/wallet-local": "^5.1.2",
"dotenv": "^16.4.4",
"viem": "^2.7.9"
"viem": "^2.7.9",
"web3": "1.10",
"web3-utils": "1.10"
}
}
13 changes: 9 additions & 4 deletions viem.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { createPublicClient, createWalletClient, http, parseEther, parseGwei } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { celoAlfajores } from "viem/chains";

import "dotenv/config"; // use to read private key from environment variable

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=<your_private_key> in .env file."
);
}
const RECIPIENT = "0x22579CA45eE22E2E16dDF72D955D6cf4c767B0eF"; // arbitrary address

/**
Expand All @@ -20,13 +24,15 @@ const walletClient = createWalletClient({
transport: http(),
});

async function feeCurrencyTransfer() {
async function nativeTransfer() {
console.log(`Initiating fee currency transaction...`);
const transactionHash = await walletClient.sendTransaction({
account, // Sender
to: RECIPIENT, // recipient
// TODO: Adjust the amount to send based on the token's decimals (USDC has 6 decimals)
value: parseEther("0.01"), // 0.01 CELO
feeCurrency: "0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1", // cUSD fee currency
// gas: // TODO: implement gas estimation
maxFeePerGas: parseGwei("10"), // Special field for dynamic fee transaction type (EIP-1559)
maxPriorityFeePerGas: parseGwei("10"), // Special field for dynamic fee transaction type (EIP-1559)
});
Expand All @@ -38,7 +44,6 @@ async function feeCurrencyTransfer() {
console.log(transactionReceipt);
}

feeCurrencyTransfer().catch((err) => {
// Handle any errors that might occur in the demos
nativeTransfer().catch((err) => {
console.error("An error occurred:", err);
});
Loading

0 comments on commit d0cd7c8

Please sign in to comment.