Nhảy tới nội dung
This page uses machine translation from English, which may contain errors or unclear language. For the most accurate information, please see the original English version. Some content may be in the original English due to frequent updates. Help us improve this page's translation by joining our effort on Crowdin. (Crowdin translation page, Contributing guide)

Không sử dụng khí gas

Nhập gói Web3 từ gói @kaiachain/web3js-ext để thêm các tính năng không cần gas vào web3js.

Địa chỉ token ERC20 (token TEST trên mạng thử nghiệm Kairos).

Khai báo senderAddr: Địa chỉ ví của người gửi thực hiện giao dịch hoán đổi và senderPriv: Khóa riêng tư của người gửi để ký giao dịch.

Tạo một nhà cung cấp JSON-RPC và một thực thể Wallet với mạng thử nghiệm Kaia Kairos.

Tuyên bố senderAccount từ khóa riêng của người gửi

Một giao diện ứng dụng cơ bản (ABI) tối thiểu cho token ERC20, bao gồm các hàm để tra cứu số thập phân, ký hiệu, giới hạn giao dịch và số dư.

Một số lượng cố định là 0.01 KAIA (đơn vị wei) mà người gửi muốn nhận từ giao dịch hoán đổi để tài trợ cho giao dịch ứng dụng tiếp theo.

Hiển thị token tại địa chỉ:

Tạo một thực thể của hợp đồng token ERC20 để tương tác với các chức năng của nó.

Tra cứu ký hiệu của token (ví dụ: “TEST” cho token TEST).

Tra cứu số chữ số thập phân của token (ví dụ: 18 cho hầu hết các token ERC20 như ETH hoặc TEST).

Tra cứu số dư của token ERC20 của người gửi.

Hiển thị số dư ban đầu của người gửi.

Lấy một thực thể của hợp đồng GaslessSwapRouter, cho phép thực hiện các giao dịch hoán đổi token mà không tốn gas trên blockchain Kaia.

Lấy địa chỉ blockchain của hợp đồng GaslessSwapRouter.

Kiểm tra xem token ERC20 được chỉ định có được GaslessSwapRouter hỗ trợ cho các giao dịch không tốn gas hay không.

Lấy tỷ lệ hoa hồng mà GaslessSwapRouter tính phí cho việc thực hiện các giao dịch swap không tốn gas.

Hiển thị địa chỉ GaslessSwapRouter, true nếu token được hỗ trợ và tỷ lệ hoa hồng.

Kiểm tra số lượng token mà GaslessSwapRouter được phép chi tiêu thay mặt cho người gửi.

Xác định xem có cần thực hiện giao dịch phê duyệt hay không bằng cách kiểm tra xem hạn mức có bằng không hay không.

Khởi tạo một mảng rỗng để lưu trữ các giao dịch sẽ được gửi sau này.

Kiểm tra xem có cần giao dịch phê duyệt hay không dựa trên cờ approveRequired. Tạo giao dịch ERC20 để phê duyệt cho phép GaslessSwapRouter chi tiêu các token của người gửi.

Lấy giá gas hiện tại từ blockchain và chuyển đổi nó thành số JavaScript.

Tính toán tổng số KAIA (đơn vị wei) mà người gửi phải trả lại cho thợ đào khối để chi trả chi phí gas của các giao dịch.

Tính toán số lượng tối thiểu của KAIA (đơn vị wei) mà giao dịch hoán đổi phải tạo ra để thanh toán khoản vay, phí hoa hồng và phí giao dịch ứng dụng mong muốn.

Tính toán số lượng token ERC20 cần hoán đổi để nhận được ít nhất minAmountOut KAIA, bao gồm cả chênh lệch giá.

Kiểm tra xem số dư token ERC20 của người gửi có đủ để thanh toán số lượng token cần thiết cho giao dịch hoán đổi hay không.

Tạo giao dịch hoán đổi để đổi một lượng ERC20 tokens đã chỉ định lấy ít nhất một lượng KAIA tối thiểu, bao gồm logic thanh toán không tốn gas. Thêm giao dịch hoán đổi vào mảng txs để thực thi theo lô.

Gửi tất cả các giao dịch trong mảng txs bằng ví của người gửi. Lặp qua các giao dịch đã gửi để ghi lại chi tiết của chúng.

Gửi một mảng các giao dịch đã ký đến blockchain và chờ nhận xác nhận giao dịch.

Danh sách các giao dịch của khối liên quan đến người gửi

Số dư cuối cùng của người gửi

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

Cải thiện trang này