diff --git a/backend/services/blockchain-service/contracts/eUSDT/EnergyUSDT.sol b/backend/services/blockchain-service/contracts/eUSDT/EnergyUSDT.sol new file mode 100644 index 00000000..ff0f90b4 --- /dev/null +++ b/backend/services/blockchain-service/contracts/eUSDT/EnergyUSDT.sol @@ -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; + } +} diff --git a/backend/services/blockchain-service/contracts/eUSDT/README.md b/backend/services/blockchain-service/contracts/eUSDT/README.md new file mode 100644 index 00000000..bc29581e --- /dev/null +++ b/backend/services/blockchain-service/contracts/eUSDT/README.md @@ -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 diff --git a/backend/services/blockchain-service/contracts/eUSDT/compile.mjs b/backend/services/blockchain-service/contracts/eUSDT/compile.mjs new file mode 100644 index 00000000..e1c8a268 --- /dev/null +++ b/backend/services/blockchain-service/contracts/eUSDT/compile.mjs @@ -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(', ')); diff --git a/backend/services/blockchain-service/contracts/eUSDT/deploy.mjs b/backend/services/blockchain-service/contracts/eUSDT/deploy.mjs new file mode 100644 index 00000000..5e8d6a3a --- /dev/null +++ b/backend/services/blockchain-service/contracts/eUSDT/deploy.mjs @@ -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); diff --git a/backend/services/blockchain-service/contracts/eUSDT/deployment.json b/backend/services/blockchain-service/contracts/eUSDT/deployment.json new file mode 100644 index 00000000..851f5134 --- /dev/null +++ b/backend/services/blockchain-service/contracts/eUSDT/deployment.json @@ -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" + } +} \ No newline at end of file diff --git a/backend/services/blockchain-service/contracts/eUSDT/package-lock.json b/backend/services/blockchain-service/contracts/eUSDT/package-lock.json new file mode 100644 index 00000000..124b96d6 --- /dev/null +++ b/backend/services/blockchain-service/contracts/eUSDT/package-lock.json @@ -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 + } + } + } + } +} diff --git a/backend/services/blockchain-service/contracts/eUSDT/package.json b/backend/services/blockchain-service/contracts/eUSDT/package.json new file mode 100644 index 00000000..b8618ace --- /dev/null +++ b/backend/services/blockchain-service/contracts/eUSDT/package.json @@ -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" + } +} diff --git a/backend/services/blockchain-service/contracts/fUSDT/FutureUSDT.sol b/backend/services/blockchain-service/contracts/fUSDT/FutureUSDT.sol new file mode 100644 index 00000000..29dd172b --- /dev/null +++ b/backend/services/blockchain-service/contracts/fUSDT/FutureUSDT.sol @@ -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; + } +} diff --git a/backend/services/blockchain-service/contracts/fUSDT/README.md b/backend/services/blockchain-service/contracts/fUSDT/README.md new file mode 100644 index 00000000..bdd497d3 --- /dev/null +++ b/backend/services/blockchain-service/contracts/fUSDT/README.md @@ -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 diff --git a/backend/services/blockchain-service/contracts/fUSDT/compile.mjs b/backend/services/blockchain-service/contracts/fUSDT/compile.mjs new file mode 100644 index 00000000..dff00fcb --- /dev/null +++ b/backend/services/blockchain-service/contracts/fUSDT/compile.mjs @@ -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(', ')); diff --git a/backend/services/blockchain-service/contracts/fUSDT/deploy.mjs b/backend/services/blockchain-service/contracts/fUSDT/deploy.mjs new file mode 100644 index 00000000..ead71119 --- /dev/null +++ b/backend/services/blockchain-service/contracts/fUSDT/deploy.mjs @@ -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); diff --git a/backend/services/blockchain-service/contracts/fUSDT/deployment.json b/backend/services/blockchain-service/contracts/fUSDT/deployment.json new file mode 100644 index 00000000..1ae8c632 --- /dev/null +++ b/backend/services/blockchain-service/contracts/fUSDT/deployment.json @@ -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" + } +} \ No newline at end of file diff --git a/backend/services/blockchain-service/contracts/fUSDT/package-lock.json b/backend/services/blockchain-service/contracts/fUSDT/package-lock.json new file mode 100644 index 00000000..6dcae991 --- /dev/null +++ b/backend/services/blockchain-service/contracts/fUSDT/package-lock.json @@ -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 + } + } + } + } +} diff --git a/backend/services/blockchain-service/contracts/fUSDT/package.json b/backend/services/blockchain-service/contracts/fUSDT/package.json new file mode 100644 index 00000000..db440ba4 --- /dev/null +++ b/backend/services/blockchain-service/contracts/fUSDT/package.json @@ -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" + } +} diff --git a/contracts/README.md b/contracts/README.md new file mode 100644 index 00000000..78f91878 --- /dev/null +++ b/contracts/README.md @@ -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` | 签名验证工具 |