本文へスキップ
このページは英語からの機械翻訳を使用しており、誤りや不明瞭な表現が含まれている可能性があります。最も正確な情報については、オリジナルの英語版をご覧ください。頻繁な更新のため、一部のコンテンツはオリジナルの英語になっている可能性があります。Crowdinでの取り組みに参加して、このページの翻訳改善にご協力ください。 (Crowdin translation page, Contributing guide)

ガスレス

Web3jsにガス抜き機能を追加するために、@kaiachain/web3js-extパッケージからWeb3をインポートする。

ERC20トークンのアドレス(Kairos testnet上のTESTトークン)。

senderAddr:**スワップを行う送信者のウォレットアドレスと、**senderPriv:**トランザクションに署名するための送信者の秘密鍵を宣言する。

KaiaKairosテストネットでJSON-RPCプロバイダとWalletのインスタンスを作成する

送信者秘密鍵からsenderAccount**を宣言する。

ERC20トークンのための最小限のABIで、小数、記号、手当、残高を照会する関数を含む。

送金人がスワップから受け取りたい固定額0.01KAIA(ウェイ)。

アドレスにトークンを表示する:

ERC20トークンコントラクトのインスタンスを作成し、その機能と対話します。

トークンのシンボルを問い合わせる(例えば、TESTトークンなら "TEST")。

トークンの小数点以下の桁数を問い合わせる(例えば、ETHやTESTのようなほとんどのERC20トークンは18)。

ERC20トークンの送信者の残高を照会します。

送信者の初期残高を表示する。

Kaiaブロックチェーン上のガスレストークンスワップを促進するGaslessSwapRouterコントラクトのインスタンスを取得します。

GaslessSwapRouter 契約のブロックチェーンアドレスを取得します。

指定されたERC20トークンがガスレススワップ用のGaslessSwapRouterでサポートされているかどうかをチェックします。

ガスレススワップを促進するために GaslessSwapRouter が請求する手数料率を取得します。

GaslessSwapRouterのアドレス、トークンがサポートされている場合はtrue、手数料率を表示します。

GaslessSwapRouter が送信者に代わって使用できるトークンの数をチェックする。

引当金がゼロかどうかをチェックすることにより、承認トランザクションが必要かどうかを判断する。

後で送信されるトランザクションを格納する空の配列を初期化する。

approveRequired フラグに基づいて、承認トランザクションが必要かどうかをチェックする。 GaslessSwapRouterが送信者のトークンを使用できるように、ERC20の承認トランザクションを生成する。

ブロックチェーンから現在のガス価格を取得し、JavaScriptの数値に変換する。

トランザクションのガスコストを賄うために送金者がブロックマイナーに返済しなければならないKAIAの合計額(ウェイ)を計算する。

スワップが、返済、手数料、希望する申込取引手数料をカバーするために生み出さなければならないKAIAの最低額(ウェイ)を計算します。

スリッページを考慮して、少なくとも minAmountOut KAIA を受け取るためにスワップすべき ERC20 トークンの量を計算します。

送信者の ERC20 トークンの残高が、スワップに必要なトークンの量に不足しているかどうかをチェックします。

指定された量のERC20トークンを少なくとも最低量のKAIAと交換するスワップ取引を生成し、ガスなし返済ロジックを組み込む。 スワップトランザクションをバッチ実行のために txs 配列に追加する。

送信者のウォレットを使用して、txs 配列内のすべてのトランザクションを送信します。 送信されたトランザクションを繰り返し、その詳細を記録する。

署名されたトランザクションの配列をブロックチェーンに送信し、トランザクションの受信を待つ。

送信者に関連するブロックのトランザクションをリストアップする。

送信者の最終残高

Gasless.js

const { Web3 } = require("@kaiachain/web3js-ext");
// Replace with ERC20 token address to be spent
const tokenAddr = "0xcB00BA2cAb67A3771f9ca1Fa48FDa8881B457750"; // Kairos:TEST token
// Replace with your wallet address and private key
const senderAddr = "0x24e8efd18d65bcb6b3ba15a4698c0b0d69d13ff7";
const senderPriv = "0x4a72b3d09c3d5e28e8652e0111f9c4ce252e8299aad95bb219a38eb0a3f4da49";
const provider = new Web3.providers.HttpProvider("https://public-en-kairos.node.kaia.io");
const web3 = new Web3(provider);
const senderAccount = web3.eth.accounts.privateKeyToAccount(senderPriv);
const ERC20_ABI = JSON.parse('[{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"}]');
// senderAddr wants to swap the ERC20 token for at least 0.01 KAIA so she can execute the AppTx.
async function main() {
const appTxFee = web3.utils.toWei("0.01", "ether");
console.log(`Using token at address: ${tokenAddr}`);
const token = new web3.eth.Contract(ERC20_ABI, tokenAddr);
const tokenSymbol = await token.methods.symbol().call();
const tokenDecimals = parseInt(await token.methods.decimals().call());
const tokenBalance = await token.methods.balanceOf(senderAddr).call();
console.log(`\nInitial balance of the sender ${senderAddr}`);
console.log(`- ${web3.utils.fromWei(await web3.eth.getBalance(senderAddr), "ether")} KAIA`);
console.log(`- ${web3.utils.fromWei(tokenBalance, tokenDecimals)} ${tokenSymbol}`);
const router = await web3.gasless.getGaslessSwapRouter();
const routerAddr = await router.options.address;
const isTokenSupported = await router.methods.isTokenSupported(tokenAddr).call();
const commissionRate = await router.methods.commissionRate().call();
console.log(`\nGaslessSwapRouter address: ${routerAddr}`);
console.log(`- The token is supported: ${isTokenSupported}`);
console.log(`- Commission rate: ${commissionRate} bps`);
// If sender hasn't approved, include ApproveTx first.
const allowance = await token.methods.allowance(senderAddr, routerAddr).call();
const approveRequired = (allowance == 0n);
const txs = [];
if (approveRequired) {
console.log("\nAdding ApproveTx because allowance is 0");
const approveTx = await web3.gasless.getApproveTx(
senderAddr,
tokenAddr,
routerAddr,
gasPrice,
);
txs.push(approveTx);
} else {
console.log("\nNo ApproveTx needed");
}
// - amountRepay (KAIA) is the cost of LendTx, ApproveTx, and SwapTx. The block miner shall fund it first,
// then the sender has to repay from the swap output.
// - minAmountOut (KAIA) is the required amount of the swap output. It must be enough to cover the amountRepay
// and pay the commission, still leaving appTxFee.
// - amountIn (token) is the amount of the token to be swapped to produce minAmountOut plus slippage.
console.log(`\nCalculating the amount of the token to be swapped...`);
const gasPrice = await web3.eth.getGasPrice();
console.log(`- gasPrice: ${web3.utils.fromWei(gasPrice, "gwei")} gkei`);
const amountRepay = web3.gasless.getAmountRepay(approveRequired, gasPrice);
console.log(`- amountRepay: ${web3.utils.fromWei(amountRepay, "ether")} KAIA`);
const minAmountOut = web3.gasless.getMinAmountOut(amountRepay, appTxFee, commissionRate);
console.log(`- minAmountOut: ${web3.utils.fromWei(minAmountOut, "ether")} KAIA`);
const slippageBps = 50 // 0.5%
const amountIn = await web3.gasless.getAmountIn(router, tokenAddr, minAmountOut, slippageBps);
console.log(`- amountIn: ${web3.utils.fromWei(amountIn, tokenDecimals)} ${tokenSymbol}`);
if (tokenBalance < amountIn) {
console.log(`\nInsufficient balance of the token: ${web3.utils.fromWei(tokenBalance, tokenDecimals)} ${tokenSymbol}`);
console.log(`- Please transfer more ${tokenSymbol} to the sender ${senderAddr}`);
return;
}
const swapTx = await web3.gasless.getSwapTx(
senderAddr,
tokenAddr,
routerAddr,
amountIn,
minAmountOut,
amountRepay,
gasPrice,
approveRequired,
);
txs.push(swapTx);
console.log("\nSending transactions and waiting for them to be mined...");
const signedTxs = [];
const txHashes = []
for (const tx of txs) {
const signResult = await senderAccount.signTransaction(tx);
signedTxs.push(signResult.rawTransaction);
txHashes.push(signResult.transactionHash);
console.log(`- Tx signed: (nonce: ${tx.nonce}) ${signResult.transactionHash} ${signResult.rawTransaction}`);
}
const receipts = await web3.eth.sendSignedTransactions(signedTxs);
console.log("\nListing the block's transactions related to the sender...");
const block = await web3.eth.getBlock(receipts[0].blockNumber);
const names = {
[senderAddr.toLowerCase()]: "sender",
[tokenAddr.toLowerCase()]: "token",
[routerAddr.toLowerCase()]: "router",
}
for (const txhash of block.transactions) {
const tx = await web3.eth.getTransaction(txhash);
const fromName = names[tx.from.toLowerCase()] || tx.from;
const toName = names[tx.to.toLowerCase()] || tx.to;
if (fromName != tx.from || toName != tx.to) {
console.log(`- Tx ${tx.hash}: ${fromName} => ${toName}`);
}
}
console.log(`\nFinal balance of the sender ${senderAddr}`);
console.log(`- ${web3.utils.fromWei(await web3.eth.getBalance(senderAddr), "ether")} KAIA`);
console.log(`- ${web3.utils.fromWei(await token.methods.balanceOf(senderAddr).call(), tokenDecimals)} ${tokenSymbol}`);
}
main();

output

❯ node Gasless.js
Using token at address: 0xcB00BA2cAb67A3771f9ca1Fa48FDa8881B457750
Initial balance of the sender 0x24e8efd18d65bcb6b3ba15a4698c0b0d69d13ff7
- 49.9969537425 KAIA
- 3.0 TEST
GaslessSwapRouter address: 0x4b41783732810b731569E4d944F59372F411BEa2
- The token is supported: true
- Commission rate: 0 bps
- 3.0 TEST
GaslessSwapRouter address: 0x4b41783732810b731569E4d944F59372F411BEa2
- The token is supported: true
- Commission rate: 0 bps
GaslessSwapRouter address: 0x4b41783732810b731569E4d944F59372F411BEa2
- The token is supported: true
- Commission rate: 0 bps
- The token is supported: true
- Commission rate: 0 bps
- Commission rate: 0 bps
Adding ApproveTx because allowance is 0
Calculating the amount of the token to be swapped...
- gasPrice: 27.5 gkei
- amountRepay: 0.0170775 KAIA
- minAmountOut: 0.0270775 KAIA
- amountIn: 0.027300931296609197 TEST
Sending transactions and waiting for them to be mined...
- Tx signed: (nonce: 5) 0x1d2bd9e5ae11653b8cddb297d040074b189fe456ae986197c4c2bbf74a51e6ef
- Tx signed: (nonce: 6) 0x96dd81962d7ae14baf31bd0a8afb900be1a6c9c8d30ad854011a4120fb0efbaf
Listing the block's transactions related to the sender...
- Tx 0x50769b14c7814f4e6b169f63595c1c19d9c46ce1c626c14b6b3c5610f691f58a: 0xB74Ff9DEa397fE9E231df545eb53fE2ADF776cb2 => sender
- Tx 0x1d2bd9e5ae11653b8cddb297d040074b189fe456ae986197c4c2bbf74a51e6ef: sender => token
- Tx 0x96dd81962d7ae14baf31bd0a8afb900be1a6c9c8d30ad854011a4120fb0efbaf: sender => router
Final balance of the sender 0x24e8efd18d65bcb6b3ba15a4698c0b0d69d13ff7
- 50.016275725 KAIA
- 2.972699068703390803 TEST

ページを改善してください。