feat(blockchain): 部署 eUSDT 和 fUSDT 代币合约

新增两个 ERC-20 代币合约,部署在 KAVA 主网:

## eUSDT (Energy USDT)
- 合约地址: 0x7C3275D808eFbAE90C06C7E3A9AfDdcAa8563931
- 总供应量: 100.02亿 (10,002,000,000)
- 交易哈希: 0x5bebaa4a35378438ba5c891972024a1766935d2e01397a33502aa99e956a6b19

## fUSDT (Future USDT)
- 合约地址: 0x14dc4f7d3E4197438d058C3D156dd9826A161134
- 总供应量: 1万亿 (1,000,000,000,000)
- 交易哈希: 0x071f535971bc3a134dd26c182b6f05c53f0c3783e91fe6ef471d6c914e4cdb06

## 共同特性
- 固定供应量,不可增发
- 6位小数精度(与USDT一致)
- 标准ERC-20接口
- 部署者: 0x4F7E78d6B7C5FC502Ec7039848690f08c8970F1E

## 文件结构
- eUSDT/: 合约源码、编译脚本、部署脚本、README
- fUSDT/: 合约源码、编译脚本、部署脚本、README
- contracts/README.md: 补充dUSDT说明文档

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-19 05:30:25 -08:00
parent 8619b0bf26
commit 07498271d3
15 changed files with 1178 additions and 0 deletions

View File

@ -0,0 +1,78 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @title EnergyUSDT
* @dev Fixed supply ERC-20 token - NO MINTING CAPABILITY
* Total Supply: 10,002,000,000 (100.02 Billion) tokens with 6 decimals (matching USDT)
*
* IMPORTANT: This contract has NO mint function and NO way to increase supply.
* All tokens are minted to the deployer at construction time.
*/
contract EnergyUSDT {
string public constant name = "Energy USDT";
string public constant symbol = "eUSDT";
uint8 public constant decimals = 6;
// Fixed total supply: 100.02 billion tokens (10,002,000,000 * 10^6)
uint256 public constant totalSupply = 10_002_000_000 * 10**6;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Constructor - mints entire fixed supply to deployer
* No mint function exists - supply is permanently fixed
*/
constructor() {
_balances[msg.sender] = totalSupply;
emit Transfer(address(0), msg.sender, totalSupply);
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public returns (bool) {
require(to != address(0), "Transfer to zero address");
require(_balances[msg.sender] >= amount, "Insufficient balance");
unchecked {
_balances[msg.sender] -= amount;
_balances[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public returns (bool) {
require(spender != address(0), "Approve to zero address");
_allowances[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) public returns (bool) {
require(from != address(0), "Transfer from zero address");
require(to != address(0), "Transfer to zero address");
require(_balances[from] >= amount, "Insufficient balance");
require(_allowances[from][msg.sender] >= amount, "Insufficient allowance");
unchecked {
_balances[from] -= amount;
_balances[to] += amount;
_allowances[from][msg.sender] -= amount;
}
emit Transfer(from, to, amount);
return true;
}
}

View File

@ -0,0 +1,81 @@
# eUSDT (Energy USDT)
## 代币信息
| 属性 | 值 |
|------|-----|
| 名称 | Energy USDT |
| 符号 | eUSDT |
| 精度 | 6 decimals |
| 总供应量 | 10,002,000,000 (100.02亿) |
| 标准 | ERC-20 |
| 部署链 | KAVA Mainnet (Chain ID: 2222) |
## 合约特性
- **固定供应量**100.02亿代币,部署时全部铸造给部署者
- **不可增发**:合约中没有 mint 函数,供应量永久固定
- **不可销毁**:合约层面无销毁功能
- **不可升级**:合约逻辑永久固定
- **标准ERC-20**完全兼容所有主流钱包和DEX
## 部署步骤
### 1. 安装依赖
```bash
cd backend/services/blockchain-service/contracts/eUSDT
npm install
```
### 2. 编译合约
```bash
node compile.mjs
```
编译后会在 `build/` 目录生成:
- `EnergyUSDT.abi` - 合约ABI
- `EnergyUSDT.bin` - 合约字节码
### 3. 部署合约
确保部署账户有足够的 KAVA 支付 gas 费(约 0.02 KAVA
```bash
node deploy.mjs
```
## 合约函数
| 函数 | 说明 |
|------|------|
| `name()` | 返回 "Energy USDT" |
| `symbol()` | 返回 "eUSDT" |
| `decimals()` | 返回 6 |
| `totalSupply()` | 返回 10,002,000,000 * 10^6 |
| `balanceOf(address)` | 查询账户余额 |
| `transfer(address, uint256)` | 转账 |
| `approve(address, uint256)` | 授权额度 |
| `transferFrom(address, address, uint256)` | 代理转账 |
| `allowance(address, address)` | 查询授权额度 |
## 事件
| 事件 | 说明 |
|------|------|
| `Transfer(from, to, value)` | 转账事件 |
| `Approval(owner, spender, value)` | 授权事件 |
## 部署信息
| 网络 | 合约地址 | 区块浏览器 |
|------|---------|-----------|
| KAVA Mainnet | `0x7C3275D808eFbAE90C06C7E3A9AfDdcAa8563931` | https://kavascan.com/address/0x7C3275D808eFbAE90C06C7E3A9AfDdcAa8563931 |
**部署详情:**
- 部署者/代币拥有者:`0x4F7E78d6B7C5FC502Ec7039848690f08c8970F1E`
- 私钥:`0x886ea4cffe76c386fecf3ff321ac9ae913737c46c17bc6ce2413752144668a2a`
- 初始持有量10,002,000,000 eUSDT全部代币
- 交易哈希:`0x5bebaa4a35378438ba5c891972024a1766935d2e01397a33502aa99e956a6b19`
- 部署时间2026-01-19

View File

@ -0,0 +1,51 @@
import solc from 'solc';
import fs from 'fs';
const source = fs.readFileSync('EnergyUSDT.sol', 'utf8');
const input = {
language: 'Solidity',
sources: {
'EnergyUSDT.sol': {
content: source
}
},
settings: {
optimizer: {
enabled: true,
runs: 200
},
evmVersion: 'paris', // Use paris to avoid PUSH0
outputSelection: {
'*': {
'*': ['abi', 'evm.bytecode']
}
}
}
};
const output = JSON.parse(solc.compile(JSON.stringify(input)));
if (output.errors) {
output.errors.forEach(err => {
console.log(err.formattedMessage);
});
// Check for actual errors (not just warnings)
const hasErrors = output.errors.some(err => err.severity === 'error');
if (hasErrors) {
process.exit(1);
}
}
const contract = output.contracts['EnergyUSDT.sol']['EnergyUSDT'];
const bytecode = contract.evm.bytecode.object;
const abi = contract.abi;
fs.mkdirSync('build', { recursive: true });
fs.writeFileSync('build/EnergyUSDT.bin', bytecode);
fs.writeFileSync('build/EnergyUSDT.abi', JSON.stringify(abi, null, 2));
console.log('Compiled successfully!');
console.log('Bytecode length:', bytecode.length);
console.log('ABI functions:', abi.filter(x => x.type === 'function').map(x => x.name).join(', '));

View File

@ -0,0 +1,86 @@
import { ethers } from 'ethers';
import fs from 'fs';
// Same deployer account as dUSDT
const PRIVATE_KEY = '0x886ea4cffe76c386fecf3ff321ac9ae913737c46c17bc6ce2413752144668a2a';
const RPC_URL = 'https://evm.kava.io';
// Contract bytecode
const BYTECODE = '0x' + fs.readFileSync('build/EnergyUSDT.bin', 'utf8');
const ABI = JSON.parse(fs.readFileSync('build/EnergyUSDT.abi', 'utf8'));
async function deploy() {
// Connect to Kava mainnet
const provider = new ethers.JsonRpcProvider(RPC_URL);
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
console.log('Deployer address:', wallet.address);
// Check balance
const balance = await provider.getBalance(wallet.address);
console.log('Balance:', ethers.formatEther(balance), 'KAVA');
if (parseFloat(ethers.formatEther(balance)) < 0.01) {
console.error('Insufficient KAVA balance for deployment!');
process.exit(1);
}
// Get network info
const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId.toString());
// Create contract factory
const factory = new ethers.ContractFactory(ABI, BYTECODE, wallet);
console.log('Deploying EnergyUSDT (eUSDT) contract...');
// Deploy
const contract = await factory.deploy();
console.log('Transaction hash:', contract.deploymentTransaction().hash);
// Wait for deployment
console.log('Waiting for confirmation...');
await contract.waitForDeployment();
const contractAddress = await contract.getAddress();
console.log('Contract deployed at:', contractAddress);
// Verify deployment
console.log('\nVerifying deployment...');
const name = await contract.name();
const symbol = await contract.symbol();
const decimals = await contract.decimals();
const totalSupply = await contract.totalSupply();
const ownerBalance = await contract.balanceOf(wallet.address);
console.log('Token name:', name);
console.log('Token symbol:', symbol);
console.log('Decimals:', decimals.toString());
console.log('Total supply:', ethers.formatUnits(totalSupply, 6), 'eUSDT');
console.log('Owner balance:', ethers.formatUnits(ownerBalance, 6), 'eUSDT');
console.log('\n=== DEPLOYMENT COMPLETE ===');
console.log('Contract Address:', contractAddress);
console.log('Explorer:', `https://kavascan.com/address/${contractAddress}`);
// Save deployment info
const deploymentInfo = {
network: 'KAVA Mainnet',
chainId: 2222,
contractAddress,
deployer: wallet.address,
transactionHash: contract.deploymentTransaction().hash,
deployedAt: new Date().toISOString(),
token: {
name,
symbol,
decimals: decimals.toString(),
totalSupply: totalSupply.toString()
}
};
fs.writeFileSync('deployment.json', JSON.stringify(deploymentInfo, null, 2));
console.log('\nDeployment info saved to deployment.json');
}
deploy().catch(console.error);

View File

@ -0,0 +1,14 @@
{
"network": "KAVA Mainnet",
"chainId": 2222,
"contractAddress": "0x7C3275D808eFbAE90C06C7E3A9AfDdcAa8563931",
"deployer": "0x4F7E78d6B7C5FC502Ec7039848690f08c8970F1E",
"transactionHash": "0x5bebaa4a35378438ba5c891972024a1766935d2e01397a33502aa99e956a6b19",
"deployedAt": "2026-01-19T13:25:28.071Z",
"token": {
"name": "Energy USDT",
"symbol": "eUSDT",
"decimals": "6",
"totalSupply": "10002000000000000"
}
}

View File

@ -0,0 +1,222 @@
{
"name": "eusdt-contract",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "eusdt-contract",
"version": "1.0.0",
"dependencies": {
"ethers": "^6.9.0",
"solc": "^0.8.19"
}
},
"node_modules/@adraffy/ens-normalize": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz",
"integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==",
"license": "MIT"
},
"node_modules/@noble/curves": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
"license": "MIT",
"dependencies": {
"@noble/hashes": "1.3.2"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@noble/hashes": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
"license": "MIT",
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@types/node": {
"version": "22.7.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
"integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
}
},
"node_modules/aes-js": {
"version": "4.0.0-beta.5",
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
"integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==",
"license": "MIT"
},
"node_modules/command-exists": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz",
"integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==",
"license": "MIT"
},
"node_modules/commander": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
"license": "MIT",
"engines": {
"node": ">= 12"
}
},
"node_modules/ethers": {
"version": "6.16.0",
"resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz",
"integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/ethers-io/"
},
{
"type": "individual",
"url": "https://www.buymeacoffee.com/ricmoo"
}
],
"license": "MIT",
"dependencies": {
"@adraffy/ens-normalize": "1.10.1",
"@noble/curves": "1.2.0",
"@noble/hashes": "1.3.2",
"@types/node": "22.7.5",
"aes-js": "4.0.0-beta.5",
"tslib": "2.7.0",
"ws": "8.17.1"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/js-sha3": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==",
"license": "MIT"
},
"node_modules/memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
"integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==",
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/semver": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"license": "ISC",
"bin": {
"semver": "bin/semver"
}
},
"node_modules/solc": {
"version": "0.8.19",
"resolved": "https://registry.npmjs.org/solc/-/solc-0.8.19.tgz",
"integrity": "sha512-yqurS3wzC4LdEvmMobODXqprV4MYJcVtinuxgrp61ac8K2zz40vXA0eSAskSHPgv8dQo7Nux39i3QBsHx4pqyA==",
"license": "MIT",
"dependencies": {
"command-exists": "^1.2.8",
"commander": "^8.1.0",
"follow-redirects": "^1.12.1",
"js-sha3": "0.8.0",
"memorystream": "^0.3.1",
"semver": "^5.5.0",
"tmp": "0.0.33"
},
"bin": {
"solcjs": "solc.js"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"license": "MIT",
"dependencies": {
"os-tmpdir": "~1.0.2"
},
"engines": {
"node": ">=0.6.0"
}
},
"node_modules/tslib": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
"license": "0BSD"
},
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"license": "MIT"
},
"node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
}
}

View File

@ -0,0 +1,14 @@
{
"name": "eusdt-contract",
"version": "1.0.0",
"type": "module",
"description": "Energy USDT (eUSDT) ERC-20 Token Contract",
"scripts": {
"compile": "node compile.mjs",
"deploy": "node deploy.mjs"
},
"dependencies": {
"ethers": "^6.9.0",
"solc": "^0.8.19"
}
}

View File

@ -0,0 +1,78 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @title FutureUSDT
* @dev Fixed supply ERC-20 token - NO MINTING CAPABILITY
* Total Supply: 1,000,000,000,000 (1 Trillion) tokens with 6 decimals (matching USDT)
*
* IMPORTANT: This contract has NO mint function and NO way to increase supply.
* All tokens are minted to the deployer at construction time.
*/
contract FutureUSDT {
string public constant name = "Future USDT";
string public constant symbol = "fUSDT";
uint8 public constant decimals = 6;
// Fixed total supply: 1 trillion tokens (1,000,000,000,000 * 10^6)
uint256 public constant totalSupply = 1_000_000_000_000 * 10**6;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Constructor - mints entire fixed supply to deployer
* No mint function exists - supply is permanently fixed
*/
constructor() {
_balances[msg.sender] = totalSupply;
emit Transfer(address(0), msg.sender, totalSupply);
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public returns (bool) {
require(to != address(0), "Transfer to zero address");
require(_balances[msg.sender] >= amount, "Insufficient balance");
unchecked {
_balances[msg.sender] -= amount;
_balances[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public returns (bool) {
require(spender != address(0), "Approve to zero address");
_allowances[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) public returns (bool) {
require(from != address(0), "Transfer from zero address");
require(to != address(0), "Transfer to zero address");
require(_balances[from] >= amount, "Insufficient balance");
require(_allowances[from][msg.sender] >= amount, "Insufficient allowance");
unchecked {
_balances[from] -= amount;
_balances[to] += amount;
_allowances[from][msg.sender] -= amount;
}
emit Transfer(from, to, amount);
return true;
}
}

View File

@ -0,0 +1,81 @@
# fUSDT (Future USDT)
## 代币信息
| 属性 | 值 |
|------|-----|
| 名称 | Future USDT |
| 符号 | fUSDT |
| 精度 | 6 decimals |
| 总供应量 | 1,000,000,000,000 (1万亿) |
| 标准 | ERC-20 |
| 部署链 | KAVA Mainnet (Chain ID: 2222) |
## 合约特性
- **固定供应量**1万亿代币部署时全部铸造给部署者
- **不可增发**:合约中没有 mint 函数,供应量永久固定
- **不可销毁**:合约层面无销毁功能
- **不可升级**:合约逻辑永久固定
- **标准ERC-20**完全兼容所有主流钱包和DEX
## 部署步骤
### 1. 安装依赖
```bash
cd backend/services/blockchain-service/contracts/fUSDT
npm install
```
### 2. 编译合约
```bash
node compile.mjs
```
编译后会在 `build/` 目录生成:
- `FutureUSDT.abi` - 合约ABI
- `FutureUSDT.bin` - 合约字节码
### 3. 部署合约
确保部署账户有足够的 KAVA 支付 gas 费(约 0.02 KAVA
```bash
node deploy.mjs
```
## 合约函数
| 函数 | 说明 |
|------|------|
| `name()` | 返回 "Future USDT" |
| `symbol()` | 返回 "fUSDT" |
| `decimals()` | 返回 6 |
| `totalSupply()` | 返回 1,000,000,000,000 * 10^6 |
| `balanceOf(address)` | 查询账户余额 |
| `transfer(address, uint256)` | 转账 |
| `approve(address, uint256)` | 授权额度 |
| `transferFrom(address, address, uint256)` | 代理转账 |
| `allowance(address, address)` | 查询授权额度 |
## 事件
| 事件 | 说明 |
|------|------|
| `Transfer(from, to, value)` | 转账事件 |
| `Approval(owner, spender, value)` | 授权事件 |
## 部署信息
| 网络 | 合约地址 | 区块浏览器 |
|------|---------|-----------|
| KAVA Mainnet | `0x14dc4f7d3E4197438d058C3D156dd9826A161134` | https://kavascan.com/address/0x14dc4f7d3E4197438d058C3D156dd9826A161134 |
**部署详情:**
- 部署者/代币拥有者:`0x4F7E78d6B7C5FC502Ec7039848690f08c8970F1E`
- 私钥:`0x886ea4cffe76c386fecf3ff321ac9ae913737c46c17bc6ce2413752144668a2a`
- 初始持有量1,000,000,000,000 fUSDT全部代币
- 交易哈希:`0x071f535971bc3a134dd26c182b6f05c53f0c3783e91fe6ef471d6c914e4cdb06`
- 部署时间2026-01-19

View File

@ -0,0 +1,51 @@
import solc from 'solc';
import fs from 'fs';
const source = fs.readFileSync('FutureUSDT.sol', 'utf8');
const input = {
language: 'Solidity',
sources: {
'FutureUSDT.sol': {
content: source
}
},
settings: {
optimizer: {
enabled: true,
runs: 200
},
evmVersion: 'paris', // Use paris to avoid PUSH0
outputSelection: {
'*': {
'*': ['abi', 'evm.bytecode']
}
}
}
};
const output = JSON.parse(solc.compile(JSON.stringify(input)));
if (output.errors) {
output.errors.forEach(err => {
console.log(err.formattedMessage);
});
// Check for actual errors (not just warnings)
const hasErrors = output.errors.some(err => err.severity === 'error');
if (hasErrors) {
process.exit(1);
}
}
const contract = output.contracts['FutureUSDT.sol']['FutureUSDT'];
const bytecode = contract.evm.bytecode.object;
const abi = contract.abi;
fs.mkdirSync('build', { recursive: true });
fs.writeFileSync('build/FutureUSDT.bin', bytecode);
fs.writeFileSync('build/FutureUSDT.abi', JSON.stringify(abi, null, 2));
console.log('Compiled successfully!');
console.log('Bytecode length:', bytecode.length);
console.log('ABI functions:', abi.filter(x => x.type === 'function').map(x => x.name).join(', '));

View File

@ -0,0 +1,86 @@
import { ethers } from 'ethers';
import fs from 'fs';
// Same deployer account as dUSDT
const PRIVATE_KEY = '0x886ea4cffe76c386fecf3ff321ac9ae913737c46c17bc6ce2413752144668a2a';
const RPC_URL = 'https://evm.kava.io';
// Contract bytecode
const BYTECODE = '0x' + fs.readFileSync('build/FutureUSDT.bin', 'utf8');
const ABI = JSON.parse(fs.readFileSync('build/FutureUSDT.abi', 'utf8'));
async function deploy() {
// Connect to Kava mainnet
const provider = new ethers.JsonRpcProvider(RPC_URL);
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
console.log('Deployer address:', wallet.address);
// Check balance
const balance = await provider.getBalance(wallet.address);
console.log('Balance:', ethers.formatEther(balance), 'KAVA');
if (parseFloat(ethers.formatEther(balance)) < 0.01) {
console.error('Insufficient KAVA balance for deployment!');
process.exit(1);
}
// Get network info
const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId.toString());
// Create contract factory
const factory = new ethers.ContractFactory(ABI, BYTECODE, wallet);
console.log('Deploying FutureUSDT (fUSDT) contract...');
// Deploy
const contract = await factory.deploy();
console.log('Transaction hash:', contract.deploymentTransaction().hash);
// Wait for deployment
console.log('Waiting for confirmation...');
await contract.waitForDeployment();
const contractAddress = await contract.getAddress();
console.log('Contract deployed at:', contractAddress);
// Verify deployment
console.log('\nVerifying deployment...');
const name = await contract.name();
const symbol = await contract.symbol();
const decimals = await contract.decimals();
const totalSupply = await contract.totalSupply();
const ownerBalance = await contract.balanceOf(wallet.address);
console.log('Token name:', name);
console.log('Token symbol:', symbol);
console.log('Decimals:', decimals.toString());
console.log('Total supply:', ethers.formatUnits(totalSupply, 6), 'fUSDT');
console.log('Owner balance:', ethers.formatUnits(ownerBalance, 6), 'fUSDT');
console.log('\n=== DEPLOYMENT COMPLETE ===');
console.log('Contract Address:', contractAddress);
console.log('Explorer:', `https://kavascan.com/address/${contractAddress}`);
// Save deployment info
const deploymentInfo = {
network: 'KAVA Mainnet',
chainId: 2222,
contractAddress,
deployer: wallet.address,
transactionHash: contract.deploymentTransaction().hash,
deployedAt: new Date().toISOString(),
token: {
name,
symbol,
decimals: decimals.toString(),
totalSupply: totalSupply.toString()
}
};
fs.writeFileSync('deployment.json', JSON.stringify(deploymentInfo, null, 2));
console.log('\nDeployment info saved to deployment.json');
}
deploy().catch(console.error);

View File

@ -0,0 +1,14 @@
{
"network": "KAVA Mainnet",
"chainId": 2222,
"contractAddress": "0x14dc4f7d3E4197438d058C3D156dd9826A161134",
"deployer": "0x4F7E78d6B7C5FC502Ec7039848690f08c8970F1E",
"transactionHash": "0x071f535971bc3a134dd26c182b6f05c53f0c3783e91fe6ef471d6c914e4cdb06",
"deployedAt": "2026-01-19T13:26:05.111Z",
"token": {
"name": "Future USDT",
"symbol": "fUSDT",
"decimals": "6",
"totalSupply": "1000000000000000000"
}
}

View File

@ -0,0 +1,222 @@
{
"name": "fusdt-contract",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "fusdt-contract",
"version": "1.0.0",
"dependencies": {
"ethers": "^6.9.0",
"solc": "^0.8.19"
}
},
"node_modules/@adraffy/ens-normalize": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz",
"integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==",
"license": "MIT"
},
"node_modules/@noble/curves": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
"license": "MIT",
"dependencies": {
"@noble/hashes": "1.3.2"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@noble/hashes": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
"license": "MIT",
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@types/node": {
"version": "22.7.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
"integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
}
},
"node_modules/aes-js": {
"version": "4.0.0-beta.5",
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
"integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==",
"license": "MIT"
},
"node_modules/command-exists": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz",
"integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==",
"license": "MIT"
},
"node_modules/commander": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
"license": "MIT",
"engines": {
"node": ">= 12"
}
},
"node_modules/ethers": {
"version": "6.16.0",
"resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz",
"integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/ethers-io/"
},
{
"type": "individual",
"url": "https://www.buymeacoffee.com/ricmoo"
}
],
"license": "MIT",
"dependencies": {
"@adraffy/ens-normalize": "1.10.1",
"@noble/curves": "1.2.0",
"@noble/hashes": "1.3.2",
"@types/node": "22.7.5",
"aes-js": "4.0.0-beta.5",
"tslib": "2.7.0",
"ws": "8.17.1"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/js-sha3": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==",
"license": "MIT"
},
"node_modules/memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
"integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==",
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/semver": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"license": "ISC",
"bin": {
"semver": "bin/semver"
}
},
"node_modules/solc": {
"version": "0.8.19",
"resolved": "https://registry.npmjs.org/solc/-/solc-0.8.19.tgz",
"integrity": "sha512-yqurS3wzC4LdEvmMobODXqprV4MYJcVtinuxgrp61ac8K2zz40vXA0eSAskSHPgv8dQo7Nux39i3QBsHx4pqyA==",
"license": "MIT",
"dependencies": {
"command-exists": "^1.2.8",
"commander": "^8.1.0",
"follow-redirects": "^1.12.1",
"js-sha3": "0.8.0",
"memorystream": "^0.3.1",
"semver": "^5.5.0",
"tmp": "0.0.33"
},
"bin": {
"solcjs": "solc.js"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"license": "MIT",
"dependencies": {
"os-tmpdir": "~1.0.2"
},
"engines": {
"node": ">=0.6.0"
}
},
"node_modules/tslib": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
"license": "0BSD"
},
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"license": "MIT"
},
"node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
}
}

View File

@ -0,0 +1,14 @@
{
"name": "fusdt-contract",
"version": "1.0.0",
"type": "module",
"description": "Future USDT (fUSDT) ERC-20 Token Contract",
"scripts": {
"compile": "node compile.mjs",
"deploy": "node deploy.mjs"
},
"dependencies": {
"ethers": "^6.9.0",
"solc": "^0.8.19"
}
}

86
contracts/README.md Normal file
View File

@ -0,0 +1,86 @@
# dUSDT (Durian USDT)
## 代币信息
| 属性 | 值 |
|------|-----|
| 名称 | Durian USDT |
| 符号 | dUSDT |
| 精度 | 6 decimals |
| 总供应量 | 1,000,000,000,000 (1万亿) |
| 标准 | ERC-20 |
| 部署链 | KAVA Mainnet (Chain ID: 2222) |
## 合约特性
- **固定供应量**1万亿代币部署时全部铸造给部署者
- **不可增发**:合约中没有 mint 函数,供应量永久固定
- **不可销毁**:合约层面无销毁功能
- **不可升级**:合约逻辑永久固定
- **标准ERC-20**完全兼容所有主流钱包和DEX
## 部署步骤
### 1. 安装依赖
```bash
cd contracts
npm install
```
### 2. 编译合约
```bash
node compile.mjs
```
编译后会在 `build/` 目录生成:
- `DurianUSDT.abi` - 合约ABI
- `DurianUSDT.bin` - 合约字节码
### 3. 部署合约
确保部署账户有足够的 KAVA 支付 gas 费(约 0.02 KAVA
```bash
node deploy-ethers.mjs
```
## 合约函数
| 函数 | 说明 |
|------|------|
| `name()` | 返回 "Durian USDT" |
| `symbol()` | 返回 "dUSDT" |
| `decimals()` | 返回 6 |
| `totalSupply()` | 返回 1,000,000,000,000 * 10^6 |
| `balanceOf(address)` | 查询账户余额 |
| `transfer(address, uint256)` | 转账 |
| `approve(address, uint256)` | 授权额度 |
| `transferFrom(address, address, uint256)` | 代理转账 |
| `allowance(address, address)` | 查询授权额度 |
## 事件
| 事件 | 说明 |
|------|------|
| `Transfer(from, to, value)` | 转账事件 |
| `Approval(owner, spender, value)` | 授权事件 |
## 部署信息
| 网络 | 合约地址 | 区块浏览器 |
|------|---------|-----------|
| KAVA Mainnet | `0xA9F3A35dBa8699c8C681D8db03F0c1A8CEB9D7c3` | https://kavascan.com/address/0xA9F3A35dBa8699c8C681D8db03F0c1A8CEB9D7c3 |
**部署详情:**
- 部署者/代币拥有者:`0x4F7E78d6B7C5FC502Ec7039848690f08c8970F1E`
- 私钥:`0x886ea4cffe76c386fecf3ff321ac9ae913737c46c17bc6ce2413752144668a2a`
- 初始持有量1,000,000,000,000 dUSDT全部代币
## 其他工具脚本
| 脚本 | 说明 |
|------|------|
| `transfer-all.mjs` | 批量转账工具 |
| `verify-sig.mjs` | 签名验证工具 |