<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Building On-Chain]]></title><description><![CDATA[Building On-Chain]]></description><link>https://blog.andrewkim.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1730733043590/186a0548-cf7f-4278-bb23-9a62c843d38c.png</url><title>Building On-Chain</title><link>https://blog.andrewkim.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 21 Apr 2026 08:50:43 GMT</lastBuildDate><atom:link href="https://blog.andrewkim.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[[UNSAFE] A Simple Node.js Script to Move your cUSD Using a Mnemonic Phrase]]></title><description><![CDATA[Recently, I attended a Code Jam session by the Celo Africa DAO, where I learned about Celo’s ContractKit. Here's what the kit is about, according to their docs:

ContractKit is a library to help developers and validators to interact with the Celo blo...]]></description><link>https://blog.andrewkim.dev/unsafe-a-simple-nodejs-script-to-move-your-cusd-using-a-mnemonic-phrase</link><guid isPermaLink="true">https://blog.andrewkim.dev/unsafe-a-simple-nodejs-script-to-move-your-cusd-using-a-mnemonic-phrase</guid><category><![CDATA[viem]]></category><category><![CDATA[Web3]]></category><category><![CDATA[celo]]></category><category><![CDATA[celoafricadao]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Andrew Kim Joseph]]></dc:creator><pubDate>Tue, 05 Nov 2024 05:12:49 GMT</pubDate><content:encoded><![CDATA[<p>Recently, I attended a Code Jam session by the Celo Africa DAO, where I learned about Celo’s ContractKit. Here's what the kit is about, according to their <a target="_blank" href="https://docs.celo.org/developer/contractkit">docs</a>:</p>
<blockquote>
<p>ContractKit is a library to help developers and validators to interact with the Celo blockchain and is well suited to developers looking for an easy way to integrate Celo Smart Contracts within their applications.</p>
</blockquote>
<p>The developer leading the session showed us how to use ContractKit, especially how to pay fees with a different currency instead of the native token (CELO). He wrote a Node.js script that fascinated me all afternoon. It was great to learn!</p>
<p>So, I decided to practice and write my own, and here it is - LIBERTY!</p>
<h2 id="heading-warning-expose-your-mnemonic-phrase-at-your-own-risk">[WARNING] Expose Your Mnemonic Phrase at Your Own Risk</h2>
<p>This project and code sample expects you to reveal your mnemonic phrase (or secret phrase), which is highly risky. If, for instance, you push your <code>.env</code> file, your phrase will be publicly available, and you run the risk of losing all your assets. Be sure to add your <code>.env</code> file to your <code>.gitignore</code> file in the root of your project, as shown below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730749863861/549d1a05-0dcf-4c37-bf16-b1a951be98f9.png" alt /></p>
<h2 id="heading-liberty-a-nodejs-script">Liberty: A Node.js Script</h2>
<p>My task was to use ContractKit along with other web3 libraries to create a solution that uses mnemonic phrases. That's how Liberty came to be. Basically, Liberty uses Celo’s ContractKit, <code>web3</code>, and <code>viem</code> libraries to:</p>
<ol>
<li><p>Create a <code>Web3</code> client account using a mnemonic phrase.</p>
</li>
<li><p>Get the private key from the client and pass it to Celo’s ContractKit.</p>
</li>
<li><p>Use Celo’s ContractKit to handle the fees.</p>
</li>
<li><p>Transfer the ERC-20 token to a recipient.</p>
</li>
</ol>
<p>Here is the GitHub repo:</p>
<p><a target="_blank" href="https://github.com/andrewkimjoseph/liberty">https://github.com/andrewkimjoseph/liberty</a></p>
<p>Here is a gist of the <code>main.ts</code> file:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="63cb1425f9c805834cdbbfd06a7a4f4b"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/andrewkimjoseph/63cb1425f9c805834cdbbfd06a7a4f4b" class="embed-card">https://gist.github.com/andrewkimjoseph/63cb1425f9c805834cdbbfd06a7a4f4b</a></div><p> </p>
<p>And here is an explanation of how it works. I’ve tried to dumb it down as much as I could!</p>
<h3 id="heading-set-your-environment-variables">Set your environment variables</h3>
<p>After the imports, you need to fetch your environment variables.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> recipientWalletAddress = process.env.RECIPIENT_WALLET_ADDRESS;
<span class="hljs-keyword">const</span> amountIncUSD = process.env.AMOUNT_IN_CUSD;
<span class="hljs-keyword">const</span> infuraAPIKey = process.env.INFURA_API_KEY;
<span class="hljs-keyword">const</span> mnemonicPhrase = process.env.MNEMONIC_PHRASE_MAIN;
</code></pre>
<p>The first two environment variables are straightforward: the wallet address you want to send to and the amount. For example, the wallet address could be "<code>0x5E20682be95cD9319B0557d905384Bb356932116</code>" and the amount could be "<code>1</code>", meaning the address will receive 1 cUSD.</p>
<p>For the Infura API key, you can create one at <a target="_blank" href="https://www.infura.io/">https://www.infura.io/</a>. Once you have it, set it up for both Mainnet and Alfajores (testnet).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730701819145/16f970c3-4a0f-41ac-b665-cad2235ef7b7.png" alt class="image--center mx-auto" /></p>
<p>At the time of this writing, the RPC URL endpoints are:</p>
<ul>
<li><p>Mainnet: <a target="_blank" href="https://celo-mainnet.infura.io/v3"><strong>https://celo-mainnet.infura.io</strong></a><a target="_blank" href="https://celo-alfajores.infura.io/v3/a7188daaf8ab4370ac12fad7e3693e96"><strong>/v3/</strong></a><strong>{YOUR_API_KEY}</strong></p>
</li>
<li><p>Testnet: <a target="_blank" href="https://celo-alfajores.infura.io/v3/a7188daaf8ab4370ac12fad7e3693e96"><strong>https://celo-alfajores.infura.io/v3/</strong></a><strong>{YOUR_API_KEY}</strong></p>
</li>
</ul>
<p>For the mnemonic phrase, it depends on the wallet you use. For this example, you can find your phrase in MetaMask under the "Security and Privacy" section, as shown in the screenshot below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730703124015/482d7960-ff37-4b7e-b43a-700abad48d9f.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-start-off-with-the-script">Start off with the script</h3>
<p>Once you've cloned the repo, run <code>npm i</code> to install the dependencies.</p>
<p>Let's check out the key parts of the script:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> web3 = <span class="hljs-keyword">new</span> Web3(<span class="hljs-string">`https://celo-mainnet.infura.io/v3/<span class="hljs-subst">${infuraAPIKey}</span>`</span>);

<span class="hljs-keyword">const</span> kit = newKitFromWeb3(web3);
</code></pre>
<p>To use ContractKit, you need a <code>kit</code> instance and a network to connect to. Use the RPC URL from Infura with your API key to make a <code>Web3</code> instance, then pass it to the <code>newKitFromWeb3</code> method. Now you have a valid kit instance.</p>
<p>To create an account with a mnemonic phrase, use viem’s <code>mnemonicToAccount</code> method and provide the phrase.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> mnemonicAccount = mnemonicToAccount(mnemonicPhrase);
</code></pre>
<h3 id="heading-use-the-transfercusd-method">Use the <code>transferCUSD</code> Method</h3>
<p>The <code>kit</code> instance you made has the contract for the token you want to transfer, which is the Celo Dollar (cUSD):</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> cUSDcontract = <span class="hljs-keyword">await</span> kit.contracts.getStableToken();
</code></pre>
<p>Now, you can add the private key from the mnemonic account to the <code>addAccount</code> method of the <code>kit</code> instance.</p>
<pre><code class="lang-typescript">kit.addAccount(toHex(mnemonicAccount.getHdKey().privateKey <span class="hljs-keyword">as</span> <span class="hljs-built_in">Uint8Array</span>));
</code></pre>
<p>The <code>mnemonicAccount</code> you created has a method called <code>getHdKey</code>, which holds the private key we need. The private key is in <code>Uint8Array</code> format, so we use the <code>toHex</code> method to change it into a valid private key format.</p>
<p>Now, you can make the account you added the default account:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> accounts = <span class="hljs-keyword">await</span> kit.web3.eth.getAccounts();
kit.defaultAccount = accounts[<span class="hljs-number">0</span>] <span class="hljs-keyword">as</span> <span class="hljs-string">`0x<span class="hljs-subst">${<span class="hljs-built_in">string</span>}</span>`</span>;
</code></pre>
<h3 id="heading-utilize-fee-abstraction-one-of-celos-superpowers">Utilize Fee Abstraction - one of Celo’s superpowers</h3>
<p>Once that's done, set the fee currency to the token (cUSD). This is what makes Celo a powerful blockchain because wallets built on it don't need users to have a specific token, usually the native one, to pay for gas. You can read more about Celo’s Fee Abstraction <a target="_blank" href="https://docs.celo.org/developer/fee-currency">here</a>.</p>
<pre><code class="lang-typescript">kit.setFeeCurrency(cUSDcontract.address);
</code></pre>
<p>At this point, you’re ready to send the cUSD:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> txnResult = <span class="hljs-keyword">await</span> cUSDcontract.transfer(
recipientWalletAddress <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>,
parseEther(amountIncUSD <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>).toString()
).send({ feeCurrency: cUSDcontract.address });
</code></pre>
<p>And that’s pretty much it, you have liberty over your tokens.</p>
<p>If you found this helpful, be sure to follow this blog, and follow me on my social channels. Let us build for Web 3 together!</p>
]]></content:encoded></item></channel></rss>