Skip to content

Commit

Permalink
Adds README and ContractKit demo (#5)
Browse files Browse the repository at this point in the history
* docs(README): adds link to docs.celo.org fee currency page

* chore(contractkit): adds demo ERC20 fee currency transfer

A bit hacky, might need to be refactored. But CIP64 transaction works as expected.
For example: https://alfajores.celoscan.io/tx/0x15aa538d97b85eef035915b4a30b2a247b77747e5e87aa11c80128b065c7575c

* nit(web3js): better comments and variable names

* docs(README): adds usage instructions, recommendations, and link to demos
  • Loading branch information
arthurgousset authored Feb 22, 2024
1 parent c479d05 commit 88baa3d
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 9 deletions.
50 changes: 49 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,51 @@
# Fee Currencies on Celo

Code examples for [docs.celo.org > Paying for Gas in Tokens](https://docs.celo.org/protocol/transaction/erc20-transaction-fees#alfajores-testnet). Visit that page for more information.
> [!TIP]
> Code examples for [docs.celo.org > Paying for Gas in Tokens](https://docs.celo.org/protocol/transaction/erc20-transaction-fees#alfajores-testnet). Visit that page for more information.
Fee currency transactions are unique to Celo. Fee currency transactions are made using a
custom transaction type described here: `celo-org/txtypes` (TODO(Arthur): link repo). Visit that repository for an explainer
and more context on the lower-level implementation of fee currency transactions.

This repo provides as a higher-level explainer on making fee currency transactions with popular
JS/TS client libraries.

## Usage

### `viem` (Recommended ✅)

We recommend you build with `viem`, if you are starting from scratch.
See demo in [`viem.ts`](/viem.ts).

## RPC client (Experts-only 🟠)

We don't recommend constructing fee currency transactions without client libraries, if you are
not an expert.

That's because constructing fee currency transactions without client libraries requires a thorough
understanding of cryptographic signatures, transaction serialization, and typed transaction
envelopes.

But, if you would really like to construct fee currency transactions this way, you
can learn more about the transaction arguments and format here: `celo-org/txtypes`.

### `web3js` + `@celo/connect` (Discouraged ❌)

We don't recommend you build with `web3js` and `@celo/connect`, if you are starting from scratch.

That's because `@celo/connect` only supports `[email protected]`, and not the latest version
`[email protected]`.

Instead, we recommend you build with `viem`. But, for completeness, we included a demo in
[`web3.ts`](/web3.ts) so you can see usage patterns.

### `@celo/contractkit` (Discouraged ❌)

We don't recommend you build with `@celo/contractkit`, if you are starting from scratch.

That's because `@celo/contractkit` is a library for developers who want to
interact with core contracts (TODO(Arthur): link docs.celo.org) like `Governance.sol` or
`Election.sol`.

Instead, we recommend you build with `viem`. But, for completeness, we included a demo in
[`contractkit.ts`](/contractkit.ts) so you can see usage patterns.
56 changes: 56 additions & 0 deletions contractkit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { newKit } from "@celo/contractkit";
import "dotenv/config";

/**
* Constants
*/
const RECIPIENT = "0x22579CA45eE22E2E16dDF72D955D6cf4c767B0eF"; // arbitrary address
const cUSD_CONTRACT_ADDRESS = "0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1"; // ERC20
const USDC_CONTRACT_ADDRESS = "0x780c1551C2Be3ea3B1f8b1E4CeDc9C3CE40da24E"; // ERC20
const USDC_ADAPTER_ADDRESS = "0xDB93874fE111F5a87Acc11Ff09Ee9450Ac6509AE"; // Adapter
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."
);
}

/**
* Boilerplate to create a ContractKit instance and ContractKit-compatible wallet
*/
const kit = newKit("https://alfajores-forno.celo-testnet.org"); // Celo testnet
kit.connection.addAccount(`0x${PRIVATE_KEY}`);

/**
* Makes a transaction to transfer ERC20 tokens using a fee currency
*/
async function erc20Transfer() {
/**
* Set up ERC20 contract
*/
const contract = await kit.contracts.getErc20(cUSD_CONTRACT_ADDRESS);

console.log(`Initiating fee currency transaction...`);

const transactionObject = contract.transfer(
RECIPIENT,
// TODO: Adjust the amount to send based on the token's decimals (USDC has 6 decimals)
kit.web3.utils.toWei("0.01", "ether")
);

// Get the sender's address
const accounts = await kit.connection.getAccounts();
const sender = accounts[0];

const transactionReceipt = await transactionObject.sendAndWaitForReceipt({
from: sender,
to: RECIPIENT,
feeCurrency: cUSD_CONTRACT_ADDRESS,
});

console.log(transactionReceipt);
}

erc20Transfer().catch((err) => {
console.error("An error occurred:", err);
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
},
"dependencies": {
"@celo/connect": "^5.1.2",
"@celo/contractkit": "^7.0.0",
"@celo/wallet-local": "^5.1.2",
"dotenv": "^16.4.4",
"viem": "^2.7.9",
Expand Down
28 changes: 20 additions & 8 deletions web3.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
import Web3 from "web3";
import { Connection } from "@celo/connect";
import { LocalWallet } from "@celo/wallet-local"
import "dotenv/config"; // use to read private key from environment variable
import "dotenv/config";
import { AbiItem } from 'web3-utils';
import { ERC20ABI } from "./erc20Abi";

/**
* Constants
*/
const RECIPIENT = "0x22579CA45eE22E2E16dDF72D955D6cf4c767B0eF"; // arbitrary address
const cUSD_CONTRACT_ADDRESS = "0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1"; // ERC20
const USDC_CONTRACT_ADDRESS = "0x780c1551C2Be3ea3B1f8b1E4CeDc9C3CE40da24E"; // ERC20
const USDC_ADAPTER_ADDRESS = "0xDB93874fE111F5a87Acc11Ff09Ee9450Ac6509AE"; // Adapter
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
const CONTRACT_ADDRESS = "0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1"; // cUSD contract address

// Set up web3js client and wallet
/**
* Boilerplate to create a web3js client and web3js-compatible wallet
*/
const web3 = new Web3("https://alfajores-forno.celo-testnet.org"); // Celo testnet
const celoWallet = new LocalWallet();
celoWallet.addAccount(`0x${PRIVATE_KEY}`);
const connection = new Connection(web3, celoWallet);

// Set up ERC20 contract
const contract = new web3.eth.Contract(ERC20ABI as AbiItem[], CONTRACT_ADDRESS);
/**
* Set up ERC20 contract
*/
const contract = new web3.eth.Contract(ERC20ABI as AbiItem[], cUSD_CONTRACT_ADDRESS);

/**
* Makes a transaction to transfer ERC20 tokens using a fee currency
*/
async function erc20Transfer() {
console.log(`Initiating fee currency transaction...`);

Expand All @@ -38,8 +50,8 @@ async function erc20Transfer() {
const transactionReceipt = await connection
.sendTransaction({
from: sender,
to: CONTRACT_ADDRESS,
feeCurrency: "0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1", // cUSD fee currency
to: cUSD_CONTRACT_ADDRESS,
feeCurrency: cUSD_CONTRACT_ADDRESS,
data: transactionObject.encodeABI(),
})
.then((tx) => tx.waitReceipt())
Expand Down
57 changes: 57 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7"
integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==

"@celo/[email protected]":
version "10.0.0"
resolved "https://registry.yarnpkg.com/@celo/abis/-/abis-10.0.0.tgz#2c1002f2e82b29ca22cec70c988bf90d26fadc68"
integrity sha512-DC8UAEz89+1yEQqKzkxOWLYGUv/XWaqPAOkU0lKuQzhvN25ndP3fitawQl53WYn8i3ZPfRWfLO4w75l//tDSbg==

"@celo/base@^6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@celo/base/-/base-6.0.0.tgz#23811b0bc8730a0d13fa90df55a7ec0e90d370cd"
Expand All @@ -29,6 +34,27 @@
web3-eth "1.10.0"
web3-eth-contract "1.10.0"

"@celo/contractkit@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@celo/contractkit/-/contractkit-7.0.0.tgz#6878ce9c2b0c381703cfc26195db0678f50b6854"
integrity sha512-Knmg2TeO7W363xMNgOC5ZEKWn8RpsO4ARsq8SDLRq2O4v84GnTMPCh43+sIwmckx/d3tklhXrcHq/oLWiNLXYg==
dependencies:
"@celo/abis" "10.0.0"
"@celo/base" "^6.0.0"
"@celo/connect" "^5.1.2"
"@celo/utils" "^6.0.0"
"@celo/wallet-local" "^5.1.2"
"@types/bn.js" "^5.1.0"
"@types/debug" "^4.1.5"
bignumber.js "^9.0.0"
cross-fetch "3.0.6"
debug "^4.1.1"
fp-ts "2.1.1"
io-ts "2.0.1"
semver "^7.3.5"
web3 "1.10.0"
web3-core-helpers "1.10.0"

"@celo/utils@^6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@celo/utils/-/utils-6.0.0.tgz#869f45a66c9e13789ca4b61d88dcf5a247f37d5c"
Expand Down Expand Up @@ -978,6 +1004,13 @@ create-require@^1.1.0:
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==

[email protected]:
version "3.0.6"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.0.6.tgz#3a4040bc8941e653e0e9cf17f29ebcd177d3365c"
integrity sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==
dependencies:
node-fetch "2.6.1"

cross-fetch@^3.1.4:
version "3.1.8"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82"
Expand Down Expand Up @@ -1794,6 +1827,13 @@ lowercase-keys@^3.0.0:
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2"
integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==

lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"

make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
Expand Down Expand Up @@ -1991,6 +2031,11 @@ node-addon-api@^2.0.0:
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32"
integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==

[email protected]:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==

node-fetch@^2.6.12:
version "2.7.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
Expand Down Expand Up @@ -2278,6 +2323,13 @@ secp256k1@^4.0.1:
node-addon-api "^2.0.0"
node-gyp-build "^4.2.0"

semver@^7.3.5:
version "7.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d"
integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==
dependencies:
lru-cache "^6.0.0"

[email protected]:
version "0.18.0"
resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
Expand Down Expand Up @@ -3197,6 +3249,11 @@ yallist@^3.0.0, yallist@^3.1.1:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==

yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==

[email protected]:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
Expand Down

0 comments on commit 88baa3d

Please sign in to comment.