Withdraw ERC20 (Myria) Tokens
- Learn how to withdraw ERC20 tokens from Myria L2 network to Ethereum L1 network.
- To inspect the function in the SDK with details payload and response format you can reference at SDK Docs.
Prerequisites
- Make sure that you have ERC-20 tokens (such as Myria tokens) in the L2 wallet
- You can deposit ERC20 (ex: MYR tokens) from L1 to L2 wallet, can reference at depositERC20 step.
- Or if your L2 wallet received the ERC-20 tokens from Airdrop / Campaign events.
Withdrawal process
- Available balance of ERC-20 tokens in the L2 wallet
- Initiate the withdrawal
- Get withdraw balance
- Complete withdraw
Implementation
- Myria SDK (React)
You can find the full React implementation for ERC20 withdrawals in the Myria React Samples repository.
1. Set up a React project
Withdrawing ERC20 tokens requires client-side interaction with the MetaMask wallet. It's recommended to use React to implement such behavior.
You can create a React app via Create React App. Note, the below project relies on the Web3.js library and needs custom configuration.
2. Create a myria-client.ts
helper
It's recommended to have a separate .ts
file for quick access to the MyriaClient
.
For more details, use the Myria Core SDK overview.
3. Withdraw ERC20 tokens
- withdraw-erc20.ts
- Wallet.tsx
The withdrawErc20()
function has the following parameters:
params
object:
tokenType
- TokenType.ERC20 as an enum TokenTypeamount
- the Wei amount that you'd to withdrawtokenAddress
- The smart contract address of your ERC-20 tokensenderPublicKey
- The Stark Key that you registered in Myria L2senderEthAddress
- Your wallet address in L1receiverPublicKey
- Your wallet address in L1quantum
- Default constants 10^10 as pre-defined value in Myria
sendOptions
object:
from
- public key of your walletconfirmationType
- Recommendation type isConfirmed
as the request is awaiting until transaction is confirmed at on-chain and received transaction receipts
import { ConfirmationType, TokenType, WithdrawOffchainParamsV2, WithdrawalModule, MyriaClient, SendOptions } from "myria-core-sdk";
import Web3 from 'web3';
const QUANTUM = 10000000000; // 10^10 as pre-defined rules in Myria
function convertEthToWei(amount: string): string {
if (!amount || Number(amount) === 0) return '0';
return Web3.utils.toWei(amount.toString()).toString();
}
export async function withdrawERC20(client: MyriaClient, starkKey: string, account: string, contractAddress: string, amount: string) {
const withdrawalModule: WithdrawalModule = new WithdrawalModule(client);
const withdrawErc20Params : WithdrawOffchainParamsV2 = {
tokenType: TokenType.ERC20,
amount: String(convertEthToWei(amount.toString())),
tokenAddress: contractAddress, // Your ERC-20 smart contract of tokens
senderPublicKey: `0x${pKey}`,
senderEthAddress: account,
receiverPublicKey: account,
quantum: QUANTUM.toString(),
};
const sendOptions: SendOptions = {
from: account,
confirmationType: ConfirmationType.Confirmed,
}
const responseWithdraw: TransactionData = await withdrawModule.withdrawalOffchainV2(withdrawErc20Params, sendOptions);
console.log(JSON.stringify(responseWithdraw, null, 2));
}
To withdraw ERC20 tokens, you need to know the contract address of that token. You can find the address using one of the blockchain explorers, such as Etherscan. Here's an example of Myria token on Sepolia network.
import { MyriaClient } from "myria-core-sdk";
import { useState } from "react";
import { withdrawERC20 } from "./withdraw-erc20";
type Props = {
isConnected: boolean,
account: string,
starkKey: string
client: MyriaClient
}
const Wallet = ({ isConnected, account, starkKey, client }: Props) => {
const [contractAddress, setContractAddress] = useState<any>("0x83a795e1e91560aae4207fdae9199d384f11d9d2");
const [amount, setAmount] = useState<any>("5");
const onWithdrawERC20Token = async () => {
return await withdrawErc20(client, starkKey, account, contractAddress, amount);
};
const onContractAddressChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setContractAddress(event.target.value);
};
const onAmountChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setAmount(event.target.value);
};
return (
<div className="container">
<div className="row">
<div className="col-lg-4 list-form py-3 mt-3">
<h4 className="text-white">Withdraw tokens</h4>
<div className="form-row">
<div className="col">
<input type="text" value={contractAddress} onChange={onContractAddressChange} name="contractAddress" className="form-control" placeholder="Erc20 contract address" />
</div>
<div className="col">
<input type="text" value={amount} onChange={onAmountChange} name="amount" className="form-control" placeholder="Amount" />
</div>
<div className="col">
<button onClick={() => onWithdrawERC20Token()} className="btn-mry">Withdraw ERC20 tokens</button>
</div>
</div>
</div>
</div>
</div>
);
}
export default Wallet;
4. Get available withdraw balance
- At this stage, the system have tracked your off-chain withdraw transactions and depend on the batch job that Myria processing internally with Starkware so your withdraw balance would be available along at that time
- The maximum estimated time would be 35-48 hous for batch job timing to be processing.
Important note: You're only able to Complete The Withdraw as next step (Withdraw On-chain) if the withdraw balance is available and greater > 0 in L1.
- get-withdraw-balance-erc20.ts
The getWithdrawBalance()
function has the following parameters:
params
object:
tokenType
- TokenType.ERC20 as an enum TokenTypeassetId
- The computed hex string with Starkware's algorithm by combination of ERC-20 tokens smart contract and token type + quantumtokenAddress
- The smart contract address of your ERC-20 tokenquantum
- Default constants 10^10 as pre-defined value in Myria
import { ConfirmationType, TokenType, WithdrawalModule, MyriaClient } from "myria-core-sdk";
import Web3 from 'web3';
// Reference at this link: https://github.com/starkware-libs/starkware-crypto-utils
const StarkwareLib = require('@starkware-industries/starkware-crypto-utils');
const { asset } = StarkwareLib;
const QUANTUM = 10000000000; // 10^10 as pre-defined rules in Myria
export async function getWithdrawBalance(client: MyriaClient, account: string, contractAddress: string) {
const withdrawalModule: WithdrawalModule = new WithdrawalModule(client);
// Computed asset type by combination of Smart contract address and tokens type, Quantum
const assetType = asset.getAssetType({
type: 'ERC20',
data: {
quantum: QUANTUM.toString(),
tokenAddress: contractAddress
}
});
const availableWithdrawBalance = await withdrawModule.getWithdrawalBalance(account, assetId);
console.log(JSON.stringify(availableWithdrawBalance, null, 2));
}
4. Complete Withdraw - Withdraw fund to your L1 wallet
- This step is final step of withdraw as it would move your fund from Myria L1 to your wallet (ex: Metamask) in L1
- The process of withdraw on-chain would required the gas fee in your L1 wallet (Metamask).
Important note: Your withdrawal transaction would cost gas fee based on ethereum networks gas and it could be fluctuated in time.
- get-withdraw-balance-erc20.ts
The withdrawOnchainErc20()
function has the following parameters:
params
object:
tokenType
- TokenType.ERC20 as an enum TokenTypeassetId
- The computed hex string with Starkware's algorithm by combination of ERC-20 tokens smart contract and token type + quantumtokenAddress
- The smart contract address of your ERC-20 tokenquantum
- Default constants 10^10 as pre-defined value in Myria
import { ConfirmationType, TokenType, WithdrawalModule, MyriaClient, WithdrawOnchainParams } from "myria-core-sdk";
import Web3 from 'web3';
// Reference at this link: https://github.com/starkware-libs/starkware-crypto-utils
const StarkwareLib = require('@starkware-industries/starkware-crypto-utils');
const { asset } = StarkwareLib;
const QUANTUM = 10000000000; // 10^10 as pre-defined rules in Myria
export async function withdrawOnchainErc20(client: MyriaClient, account: string, contractAddress: string) {
const withdrawalModule: WithdrawalModule = new WithdrawalModule(client);
// Computed asset type by combination of Smart contract address and tokens type, Quantum
const assetType: string = asset.getAssetType({
type: TokenType.ERC20,
data: {
quantum: QUANTUM,
tokenAddress: contractAddress
}
});
const withdrawOnchainErc20Payload: WithdrawOnchainParams = {
starkKey: walletAddress,
assetType
};
const sendOptions = {
from: account,
nonce: new Date().getTime(), // It's optional but it's recommend to pass the unique nonce by get timestamp
confirmationType: ConfirmationType.Confirmed
};
const result = await withdrawModule.withdrawalOnchain(withdrawOnchainErc20Payload, sendOptions);
const withdrawOnchainResult = await withdrawModule.getWithdrawalBalance(account, assetId);
console.log(JSON.stringify(withdrawOnchainResult, null, 2));
}