feat(contracts): add DurianUSDT ERC-20 token contract
Add fixed-supply ERC-20 token contract for Durian USDT (dUSDT): - Total supply: 1 trillion tokens with 6 decimals - No minting capability - all tokens minted at deployment - Includes compile and deploy scripts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
582e80b750
commit
2e7de8a1ef
|
|
@ -0,0 +1 @@
|
||||||
|
node_modules/
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity 0.8.19;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title DurianUSDT
|
||||||
|
* @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 DurianUSDT {
|
||||||
|
string public constant name = "Durian USDT";
|
||||||
|
string public constant symbol = "dUSDT";
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,229 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "constructor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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": "account",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "balanceOf",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "decimals",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint8",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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": "totalSupply",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "transfer",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bool",
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "from",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "transferFrom",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bool",
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
608060405234801561001057600080fd5b5033600081815260208181526040808320670de0b6b3a76400009081905590519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36106fb8061006d6000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce5671461012b57806370a082311461014557806395d89b411461016e578063a9059cbb14610192578063dd62ed3e146101a557600080fd5b806306fdde0314610098578063095ea7b3146100d857806318160ddd146100fb57806323b872dd14610118575b600080fd5b6100c26040518060400160405280600b81526020016a111d5c9a585b881554d11560aa1b81525081565b6040516100cf91906105a0565b60405180910390f35b6100eb6100e636600461060a565b6101de565b60405190151581526020016100cf565b61010a670de0b6b3a764000081565b6040519081526020016100cf565b6100eb610126366004610634565b6102a0565b610133600681565b60405160ff90911681526020016100cf565b61010a610153366004610670565b6001600160a01b031660009081526020819052604090205490565b6100c260405180604001604052806005815260200164191554d11560da1b81525081565b6100eb6101a036600461060a565b61049a565b61010a6101b3366004610692565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60006001600160a01b03831661023b5760405162461bcd60e51b815260206004820152601760248201527f417070726f766520746f207a65726f206164647265737300000000000000000060448201526064015b60405180910390fd5b3360008181526001602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a350600192915050565b60006001600160a01b0384166102f85760405162461bcd60e51b815260206004820152601a60248201527f5472616e736665722066726f6d207a65726f20616464726573730000000000006044820152606401610232565b6001600160a01b0383166103495760405162461bcd60e51b81526020600482015260186024820152775472616e7366657220746f207a65726f206164647265737360401b6044820152606401610232565b6001600160a01b0384166000908152602081905260409020548211156103a85760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610232565b6001600160a01b03841660009081526001602090815260408083203384529091529020548211156104145760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e7420616c6c6f77616e636560501b6044820152606401610232565b6001600160a01b03848116600081815260208181526040808320805488900390559387168083528483208054880190558383526001825284832033845282529184902080548790039055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35060019392505050565b60006001600160a01b0383166104ed5760405162461bcd60e51b81526020600482015260186024820152775472616e7366657220746f207a65726f206164647265737360401b6044820152606401610232565b336000908152602081905260409020548211156105435760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610232565b33600081815260208181526040808320805487900390556001600160a01b03871680845292819020805487019055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910161028f565b600060208083528351808285015260005b818110156105cd578581018301518582016040015282016105b1565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461060557600080fd5b919050565b6000806040838503121561061d57600080fd5b610626836105ee565b946020939093013593505050565b60008060006060848603121561064957600080fd5b610652846105ee565b9250610660602085016105ee565b9150604084013590509250925092565b60006020828403121561068257600080fd5b61068b826105ee565b9392505050565b600080604083850312156106a557600080fd5b6106ae836105ee565b91506106bc602084016105ee565b9050925092905056fea264697066735822122028c97073f6e7db0ad943d101cb6873b31c3eb19bcea3eda83148447ab676a5ee64736f6c63430008130033
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"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"},{"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"},{"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"},{"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":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"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":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
6080604052348015600e575f5ffd5b50335f81815260208181526040808320670de0b6b3a76400009081905590519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36106ca806100685f395ff3fe608060405234801561000f575f5ffd5b5060043610610090575f3560e01c8063313ce56711610063578063313ce5671461012757806370a082311461014157806395d89b4114610169578063a9059cbb1461018d578063dd62ed3e146101a0575f5ffd5b806306fdde0314610094578063095ea7b3146100d457806318160ddd146100f757806323b872dd14610114575b5f5ffd5b6100be6040518060400160405280600b81526020016a111d5c9a585b881554d11560aa1b81525081565b6040516100cb9190610591565b60405180910390f35b6100e76100e23660046105e1565b6101d8565b60405190151581526020016100cb565b610106670de0b6b3a764000081565b6040519081526020016100cb565b6100e7610122366004610609565b610298565b61012f600681565b60405160ff90911681526020016100cb565b61010661014f366004610643565b6001600160a01b03165f9081526020819052604090205490565b6100be60405180604001604052806005815260200164191554d11560da1b81525081565b6100e761019b3660046105e1565b61048e565b6101066101ae366004610663565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b5f6001600160a01b0383166102345760405162461bcd60e51b815260206004820152601760248201527f417070726f766520746f207a65726f206164647265737300000000000000000060448201526064015b60405180910390fd5b335f8181526001602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a350600192915050565b5f6001600160a01b0384166102ef5760405162461bcd60e51b815260206004820152601a60248201527f5472616e736665722066726f6d207a65726f2061646472657373000000000000604482015260640161022b565b6001600160a01b0383166103405760405162461bcd60e51b81526020600482015260186024820152775472616e7366657220746f207a65726f206164647265737360401b604482015260640161022b565b6001600160a01b0384165f9081526020819052604090205482111561039e5760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b604482015260640161022b565b6001600160a01b0384165f9081526001602090815260408083203384529091529020548211156104095760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e7420616c6c6f77616e636560501b604482015260640161022b565b6001600160a01b038481165f81815260208181526040808320805488900390559387168083528483208054880190558383526001825284832033845282529184902080548790039055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35060019392505050565b5f6001600160a01b0383166104e05760405162461bcd60e51b81526020600482015260186024820152775472616e7366657220746f207a65726f206164647265737360401b604482015260640161022b565b335f908152602081905260409020548211156105355760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b604482015260640161022b565b335f81815260208181526040808320805487900390556001600160a01b03871680845292819020805487019055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610287565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b03811681146105dc575f5ffd5b919050565b5f5f604083850312156105f2575f5ffd5b6105fb836105c6565b946020939093013593505050565b5f5f5f6060848603121561061b575f5ffd5b610624846105c6565b9250610632602085016105c6565b929592945050506040919091013590565b5f60208284031215610653575f5ffd5b61065c826105c6565b9392505050565b5f5f60408385031215610674575f5ffd5b61067d836105c6565b915061068b602084016105c6565b9050925092905056fea2646970667358221220401cdf325cd267d7b8721fd26fa71e8965baaf38de318523730aa20166b0c98664736f6c63430008210033
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
import solc from 'solc';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
const source = fs.readFileSync('DurianUSDT.sol', 'utf8');
|
||||||
|
|
||||||
|
const input = {
|
||||||
|
language: 'Solidity',
|
||||||
|
sources: {
|
||||||
|
'DurianUSDT.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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const contract = output.contracts['DurianUSDT.sol']['DurianUSDT'];
|
||||||
|
const bytecode = contract.evm.bytecode.object;
|
||||||
|
const abi = contract.abi;
|
||||||
|
|
||||||
|
fs.mkdirSync('build', { recursive: true });
|
||||||
|
fs.writeFileSync('build/DurianUSDT.bin', bytecode);
|
||||||
|
fs.writeFileSync('build/DurianUSDT.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(', '));
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { ethers } from 'ethers';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
const PRIVATE_KEY = '0x886ea4cffe76c386fecf3ff321ac9ae913737c46c17bc6ce2413752144668a2a';
|
||||||
|
const RPC_URL = 'https://evm.kava.io';
|
||||||
|
|
||||||
|
// Contract bytecode
|
||||||
|
const BYTECODE = '0x' + fs.readFileSync('build/DurianUSDT.bin', 'utf8');
|
||||||
|
const ABI = JSON.parse(fs.readFileSync('build/DurianUSDT.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');
|
||||||
|
|
||||||
|
// 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 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), 'dUSDT');
|
||||||
|
console.log('Owner balance:', ethers.formatUnits(ownerBalance, 6), 'dUSDT');
|
||||||
|
|
||||||
|
console.log('\n=== DEPLOYMENT COMPLETE ===');
|
||||||
|
console.log('Contract Address:', contractAddress);
|
||||||
|
console.log('Explorer:', `https://kavascan.com/address/${contractAddress}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy().catch(console.error);
|
||||||
|
|
@ -0,0 +1,165 @@
|
||||||
|
import { keccak_256 } from '@noble/hashes/sha3.js';
|
||||||
|
import { secp256k1 } from '@noble/curves/secp256k1.js';
|
||||||
|
import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js';
|
||||||
|
|
||||||
|
const PRIVATE_KEY = '886ea4cffe76c386fecf3ff321ac9ae913737c46c17bc6ce2413752144668a2a';
|
||||||
|
const RPC_URL = 'https://evm.kava.io';
|
||||||
|
const CHAIN_ID = 2222;
|
||||||
|
|
||||||
|
// Contract bytecode (compiled with paris EVM, no PUSH0)
|
||||||
|
const BYTECODE = '0x608060405234801561001057600080fd5b5033600081815260208181526040808320670de0b6b3a76400009081905590519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36106fb8061006d6000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce5671461012b57806370a082311461014557806395d89b411461016e578063a9059cbb14610192578063dd62ed3e146101a557600080fd5b806306fdde0314610098578063095ea7b3146100d857806318160ddd146100fb57806323b872dd14610118575b600080fd5b6100c26040518060400160405280600b81526020016a111d5c9a585b881554d11560aa1b81525081565b6040516100cf91906105a0565b60405180910390f35b6100eb6100e636600461060a565b6101de565b60405190151581526020016100cf565b61010a670de0b6b3a764000081565b6040519081526020016100cf565b6100eb610126366004610634565b6102a0565b610133600681565b60405160ff90911681526020016100cf565b61010a610153366004610670565b6001600160a01b031660009081526020819052604090205490565b6100c260405180604001604052806005815260200164191554d11560da1b81525081565b6100eb6101a036600461060a565b61049a565b61010a6101b3366004610692565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60006001600160a01b03831661023b5760405162461bcd60e51b815260206004820152601760248201527f417070726f766520746f207a65726f206164647265737300000000000000000060448201526064015b60405180910390fd5b3360008181526001602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a350600192915050565b60006001600160a01b0384166102f85760405162461bcd60e51b815260206004820152601a60248201527f5472616e736665722066726f6d207a65726f20616464726573730000000000006044820152606401610232565b6001600160a01b0383166103495760405162461bcd60e51b81526020600482015260186024820152775472616e7366657220746f207a65726f206164647265737360401b6044820152606401610232565b6001600160a01b0384166000908152602081905260409020548211156103a85760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610232565b6001600160a01b03841660009081526001602090815260408083203384529091529020548211156104145760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e7420616c6c6f77616e636560501b6044820152606401610232565b6001600160a01b03848116600081815260208181526040808320805488900390559387168083528483208054880190558383526001825284832033845282529184902080548790039055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35060019392505050565b60006001600160a01b0383166104ed5760405162461bcd60e51b81526020600482015260186024820152775472616e7366657220746f207a65726f206164647265737360401b6044820152606401610232565b336000908152602081905260409020548211156105435760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610232565b33600081815260208181526040808320805487900390556001600160a01b03871680845292819020805487019055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910161028f565b600060208083528351808285015260005b818110156105cd578581018301518582016040015282016105b1565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461060557600080fd5b919050565b6000806040838503121561061d57600080fd5b610626836105ee565b946020939093013593505050565b60008060006060848603121561064957600080fd5b610652846105ee565b9250610660602085016105ee565b9150604084013590509250925092565b60006020828403121561068257600080fd5b61068b826105ee565b9392505050565b600080604083850312156106a557600080fd5b6106ae836105ee565b91506106bc602084016105ee565b9050925092905056fea264697066735822122028c97073f6e7db0ad943d101cb6873b31c3eb19bcea3eda83148447ab676a5ee64736f6c63430008130033';
|
||||||
|
|
||||||
|
// RLP encode helper
|
||||||
|
function rlpEncodeLength(len, offset) {
|
||||||
|
if (len < 56) {
|
||||||
|
return Buffer.from([len + offset]);
|
||||||
|
}
|
||||||
|
const hexLen = len.toString(16);
|
||||||
|
const lenBytes = Buffer.from(hexLen.length % 2 ? '0' + hexLen : hexLen, 'hex');
|
||||||
|
return Buffer.concat([Buffer.from([offset + 55 + lenBytes.length]), lenBytes]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rlpEncodeItem(data) {
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
data = data.startsWith('0x') ? data.slice(2) : data;
|
||||||
|
if (data.length === 0) return Buffer.from([0x80]);
|
||||||
|
const bytes = Buffer.from(data, 'hex');
|
||||||
|
if (bytes.length === 1 && bytes[0] < 0x80) return bytes;
|
||||||
|
return Buffer.concat([rlpEncodeLength(bytes.length, 0x80), bytes]);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rlpEncodeList(items) {
|
||||||
|
const encodedItems = items.map(rlpEncodeItem);
|
||||||
|
const totalLen = encodedItems.reduce((sum, b) => sum + b.length, 0);
|
||||||
|
return Buffer.concat([rlpEncodeLength(totalLen, 0xc0), ...encodedItems]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function rpcCall(method, params) {
|
||||||
|
const response = await fetch(RPC_URL, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ jsonrpc: '2.0', method, params, id: 1 })
|
||||||
|
});
|
||||||
|
const json = await response.json();
|
||||||
|
if (json.error) throw new Error(json.error.message);
|
||||||
|
return json.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deploy() {
|
||||||
|
const address = '0x4F7E78d6B7C5FC502Ec7039848690f08c8970F1E';
|
||||||
|
|
||||||
|
// Get nonce
|
||||||
|
const nonceHex = await rpcCall('eth_getTransactionCount', [address, 'latest']);
|
||||||
|
const nonce = parseInt(nonceHex, 16);
|
||||||
|
console.log('Nonce:', nonce);
|
||||||
|
|
||||||
|
// Estimate gas
|
||||||
|
const gasEstimate = await rpcCall('eth_estimateGas', [{
|
||||||
|
from: address,
|
||||||
|
data: BYTECODE
|
||||||
|
}]);
|
||||||
|
console.log('Gas estimate:', parseInt(gasEstimate, 16));
|
||||||
|
|
||||||
|
// Get gas price
|
||||||
|
const gasPrice = await rpcCall('eth_gasPrice', []);
|
||||||
|
console.log('Gas price:', parseInt(gasPrice, 16));
|
||||||
|
|
||||||
|
// Use slightly higher gas for safety
|
||||||
|
const gas = Math.ceil(parseInt(gasEstimate, 16) * 1.2);
|
||||||
|
const gasPriceValue = parseInt(gasPrice, 16);
|
||||||
|
|
||||||
|
// Build EIP-155 transaction
|
||||||
|
const txFields = [
|
||||||
|
nonce === 0 ? '' : nonce.toString(16), // nonce
|
||||||
|
gasPriceValue.toString(16), // gasPrice
|
||||||
|
gas.toString(16), // gasLimit
|
||||||
|
'', // to (empty for contract creation)
|
||||||
|
'', // value (0)
|
||||||
|
BYTECODE.slice(2), // data (without 0x)
|
||||||
|
CHAIN_ID.toString(16), // chainId (2222 = 0x8ae)
|
||||||
|
'', // empty for EIP-155
|
||||||
|
'' // empty for EIP-155
|
||||||
|
];
|
||||||
|
|
||||||
|
// RLP encode for signing
|
||||||
|
const rlpEncoded = rlpEncodeList(txFields);
|
||||||
|
const msgHash = keccak_256(rlpEncoded);
|
||||||
|
|
||||||
|
console.log('Signing transaction...');
|
||||||
|
|
||||||
|
// Sign
|
||||||
|
const privateKeyBytes = hexToBytes(PRIVATE_KEY);
|
||||||
|
const sigBytes = secp256k1.sign(msgHash, privateKeyBytes, { lowS: true });
|
||||||
|
|
||||||
|
// Get signature components (64-byte compact signature)
|
||||||
|
const r = bytesToHex(sigBytes.slice(0, 32));
|
||||||
|
const s = bytesToHex(sigBytes.slice(32, 64));
|
||||||
|
|
||||||
|
// Get public key for recovery check
|
||||||
|
const expectedPubKey = secp256k1.getPublicKey(privateKeyBytes, true);
|
||||||
|
|
||||||
|
// Try both recovery values to find the correct one
|
||||||
|
let recovery = 0;
|
||||||
|
for (let rec = 0; rec <= 1; rec++) {
|
||||||
|
try {
|
||||||
|
// Build 65-byte signature with recovery id
|
||||||
|
const sigWithRec = new Uint8Array(65);
|
||||||
|
sigWithRec.set(sigBytes, 0);
|
||||||
|
sigWithRec[64] = rec;
|
||||||
|
|
||||||
|
const recovered = secp256k1.recoverPublicKey(msgHash, sigWithRec, rec);
|
||||||
|
if (bytesToHex(recovered) === bytesToHex(expectedPubKey)) {
|
||||||
|
recovery = rec;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Continue trying
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('Recovery:', recovery);
|
||||||
|
|
||||||
|
const v = CHAIN_ID * 2 + 35 + recovery;
|
||||||
|
|
||||||
|
// Build signed transaction
|
||||||
|
const signedTxFields = [
|
||||||
|
nonce === 0 ? '' : nonce.toString(16),
|
||||||
|
gasPriceValue.toString(16),
|
||||||
|
gas.toString(16),
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
BYTECODE.slice(2),
|
||||||
|
v.toString(16),
|
||||||
|
r,
|
||||||
|
s
|
||||||
|
];
|
||||||
|
|
||||||
|
const signedTx = '0x' + rlpEncodeList(signedTxFields).toString('hex');
|
||||||
|
console.log('Signed tx length:', signedTx.length);
|
||||||
|
|
||||||
|
// Send transaction
|
||||||
|
console.log('Sending transaction...');
|
||||||
|
const txHash = await rpcCall('eth_sendRawTransaction', [signedTx]);
|
||||||
|
console.log('Transaction hash:', txHash);
|
||||||
|
|
||||||
|
// Wait for receipt
|
||||||
|
console.log('Waiting for confirmation...');
|
||||||
|
let receipt = null;
|
||||||
|
for (let i = 0; i < 60; i++) {
|
||||||
|
await new Promise(r => setTimeout(r, 2000));
|
||||||
|
receipt = await rpcCall('eth_getTransactionReceipt', [txHash]);
|
||||||
|
if (receipt) break;
|
||||||
|
process.stdout.write('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (receipt) {
|
||||||
|
console.log('\nContract deployed!');
|
||||||
|
console.log('Contract address:', receipt.contractAddress);
|
||||||
|
console.log('Block number:', parseInt(receipt.blockNumber, 16));
|
||||||
|
console.log('Gas used:', parseInt(receipt.gasUsed, 16));
|
||||||
|
console.log('Status:', receipt.status === '0x1' ? 'Success' : 'Failed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy().catch(console.error);
|
||||||
|
|
@ -0,0 +1,252 @@
|
||||||
|
{
|
||||||
|
"name": "contracts",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "contracts",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@noble/curves": "^2.0.1",
|
||||||
|
"@noble/hashes": "^2.0.1",
|
||||||
|
"ethers": "^6.16.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": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@noble/hashes": "2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 20.19.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@noble/hashes": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 20.19.0"
|
||||||
|
},
|
||||||
|
"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/ethers/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/ethers/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/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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "contracts",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"@noble/curves": "^2.0.1",
|
||||||
|
"@noble/hashes": "^2.0.1",
|
||||||
|
"ethers": "^6.16.0",
|
||||||
|
"solc": "^0.8.19"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { ethers } from 'ethers';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
const PRIVATE_KEY = '0x886ea4cffe76c386fecf3ff321ac9ae913737c46c17bc6ce2413752144668a2a';
|
||||||
|
const RPC_URL = 'https://evm.kava.io';
|
||||||
|
|
||||||
|
// dUSDT Contract
|
||||||
|
const CONTRACT_ADDRESS = '0xA9F3A35dBa8699c8C681D8db03F0c1A8CEB9D7c3';
|
||||||
|
const ABI = JSON.parse(fs.readFileSync('build/DurianUSDT.abi', 'utf8'));
|
||||||
|
|
||||||
|
// Transfer destination
|
||||||
|
const TO_ADDRESS = '0xdd919d51ec09c0830fd000a0ff6f0e1859b48db2';
|
||||||
|
|
||||||
|
async function transferAll() {
|
||||||
|
// Connect to Kava mainnet
|
||||||
|
const provider = new ethers.JsonRpcProvider(RPC_URL);
|
||||||
|
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
|
||||||
|
|
||||||
|
console.log('From address:', wallet.address);
|
||||||
|
console.log('To address:', TO_ADDRESS);
|
||||||
|
|
||||||
|
// Connect to contract
|
||||||
|
const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, wallet);
|
||||||
|
|
||||||
|
// Get current balance
|
||||||
|
const balance = await contract.balanceOf(wallet.address);
|
||||||
|
console.log('Current balance:', ethers.formatUnits(balance, 6), 'dUSDT');
|
||||||
|
|
||||||
|
if (balance === 0n) {
|
||||||
|
console.log('No balance to transfer');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer all tokens
|
||||||
|
console.log('\nTransferring all tokens...');
|
||||||
|
const tx = await contract.transfer(TO_ADDRESS, balance);
|
||||||
|
console.log('Transaction hash:', tx.hash);
|
||||||
|
|
||||||
|
// Wait for confirmation
|
||||||
|
console.log('Waiting for confirmation...');
|
||||||
|
const receipt = await tx.wait();
|
||||||
|
console.log('Confirmed in block:', receipt.blockNumber);
|
||||||
|
console.log('Gas used:', receipt.gasUsed.toString());
|
||||||
|
|
||||||
|
// Verify balances
|
||||||
|
console.log('\n=== Transfer Complete ===');
|
||||||
|
const newFromBalance = await contract.balanceOf(wallet.address);
|
||||||
|
const newToBalance = await contract.balanceOf(TO_ADDRESS);
|
||||||
|
console.log('From balance:', ethers.formatUnits(newFromBalance, 6), 'dUSDT');
|
||||||
|
console.log('To balance:', ethers.formatUnits(newToBalance, 6), 'dUSDT');
|
||||||
|
|
||||||
|
console.log('\nExplorer link:');
|
||||||
|
console.log(`https://kavascan.com/tx/${tx.hash}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
transferAll().catch(console.error);
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
import { keccak_256 } from '@noble/hashes/sha3.js';
|
||||||
|
import { secp256k1 } from '@noble/curves/secp256k1.js';
|
||||||
|
import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js';
|
||||||
|
|
||||||
|
const PRIVATE_KEY = '886ea4cffe76c386fecf3ff321ac9ae913737c46c17bc6ce2413752144668a2a';
|
||||||
|
const CHAIN_ID = 2222;
|
||||||
|
|
||||||
|
const BYTECODE = '0x608060405234801561001057600080fd5b5033600081815260208181526040808320670de0b6b3a76400009081905590519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36106fb8061006d6000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce5671461012b57806370a082311461014557806395d89b411461016e578063a9059cbb14610192578063dd62ed3e146101a557600080fd5b806306fdde0314610098578063095ea7b3146100d857806318160ddd146100fb57806323b872dd14610118575b600080fd5b6100c26040518060400160405280600b81526020016a111d5c9a585b881554d11560aa1b81525081565b6040516100cf91906105a0565b60405180910390f35b6100eb6100e636600461060a565b6101de565b60405190151581526020016100cf565b61010a670de0b6b3a764000081565b6040519081526020016100cf565b6100eb610126366004610634565b6102a0565b610133600681565b60405160ff90911681526020016100cf565b61010a610153366004610670565b6001600160a01b031660009081526020819052604090205490565b6100c260405180604001604052806005815260200164191554d11560da1b81525081565b6100eb6101a036600461060a565b61049a565b61010a6101b3366004610692565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60006001600160a01b03831661023b5760405162461bcd60e51b815260206004820152601760248201527f417070726f766520746f207a65726f206164647265737300000000000000000060448201526064015b60405180910390fd5b3360008181526001602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a350600192915050565b60006001600160a01b0384166102f85760405162461bcd60e51b815260206004820152601a60248201527f5472616e736665722066726f6d207a65726f20616464726573730000000000006044820152606401610232565b6001600160a01b0383166103495760405162461bcd60e51b81526020600482015260186024820152775472616e7366657220746f207a65726f206164647265737360401b6044820152606401610232565b6001600160a01b0384166000908152602081905260409020548211156103a85760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610232565b6001600160a01b03841660009081526001602090815260408083203384529091529020548211156104145760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e7420616c6c6f77616e636560501b6044820152606401610232565b6001600160a01b03848116600081815260208181526040808320805488900390559387168083528483208054880190558383526001825284832033845282529184902080548790039055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35060019392505050565b60006001600160a01b0383166104ed5760405162461bcd60e51b81526020600482015260186024820152775472616e7366657220746f207a65726f206164647265737360401b6044820152606401610232565b336000908152602081905260409020548211156105435760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610232565b33600081815260208181526040808320805487900390556001600160a01b03871680845292819020805487019055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910161028f565b600060208083528351808285015260005b818110156105cd578581018301518582016040015282016105b1565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461060557600080fd5b919050565b6000806040838503121561061d57600080fd5b610626836105ee565b946020939093013593505050565b60008060006060848603121561064957600080fd5b610652846105ee565b9250610660602085016105ee565b9150604084013590509250925092565b60006020828403121561068257600080fd5b61068b826105ee565b9392505050565b600080604083850312156106a557600080fd5b6106ae836105ee565b91506106bc602084016105ee565b9050925092905056fea264697066735822122028c97073f6e7db0ad943d101cb6873b31c3eb19bcea3eda83148447ab676a5ee64736f6c63430008130033';
|
||||||
|
|
||||||
|
// RLP encode helper
|
||||||
|
function rlpEncodeLength(len, offset) {
|
||||||
|
if (len < 56) {
|
||||||
|
return Buffer.from([len + offset]);
|
||||||
|
}
|
||||||
|
const hexLen = len.toString(16);
|
||||||
|
const lenBytes = Buffer.from(hexLen.length % 2 ? '0' + hexLen : hexLen, 'hex');
|
||||||
|
return Buffer.concat([Buffer.from([offset + 55 + lenBytes.length]), lenBytes]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rlpEncodeItem(data) {
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
data = data.startsWith('0x') ? data.slice(2) : data;
|
||||||
|
if (data.length === 0) return Buffer.from([0x80]);
|
||||||
|
const bytes = Buffer.from(data, 'hex');
|
||||||
|
if (bytes.length === 1 && bytes[0] < 0x80) return bytes;
|
||||||
|
return Buffer.concat([rlpEncodeLength(bytes.length, 0x80), bytes]);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rlpEncodeList(items) {
|
||||||
|
const encodedItems = items.map(rlpEncodeItem);
|
||||||
|
const totalLen = encodedItems.reduce((sum, b) => sum + b.length, 0);
|
||||||
|
return Buffer.concat([rlpEncodeLength(totalLen, 0xc0), ...encodedItems]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expected address
|
||||||
|
const privateKeyBytes = hexToBytes(PRIVATE_KEY);
|
||||||
|
const publicKey = secp256k1.getPublicKey(privateKeyBytes, false);
|
||||||
|
const pubKeyNoPrefix = publicKey.slice(1);
|
||||||
|
const hashPubKey = keccak_256(pubKeyNoPrefix);
|
||||||
|
const expectedAddress = '0x' + bytesToHex(hashPubKey.slice(-20));
|
||||||
|
console.log('Expected address:', expectedAddress);
|
||||||
|
|
||||||
|
// Build transaction
|
||||||
|
const nonce = 0;
|
||||||
|
const gasPrice = 1000000000;
|
||||||
|
const gas = 557117;
|
||||||
|
|
||||||
|
const txFields = [
|
||||||
|
'', // nonce = 0
|
||||||
|
gasPrice.toString(16),
|
||||||
|
gas.toString(16),
|
||||||
|
'', // to (empty for contract creation)
|
||||||
|
'', // value (0)
|
||||||
|
BYTECODE.slice(2),
|
||||||
|
CHAIN_ID.toString(16),
|
||||||
|
'',
|
||||||
|
''
|
||||||
|
];
|
||||||
|
|
||||||
|
console.log('Transaction fields:');
|
||||||
|
console.log(' nonce:', txFields[0] || '(empty = 0)');
|
||||||
|
console.log(' gasPrice:', txFields[1]);
|
||||||
|
console.log(' gas:', txFields[2]);
|
||||||
|
console.log(' to:', txFields[3] || '(empty = contract creation)');
|
||||||
|
console.log(' value:', txFields[4] || '(empty = 0)');
|
||||||
|
console.log(' data length:', txFields[5].length);
|
||||||
|
console.log(' chainId:', txFields[6]);
|
||||||
|
|
||||||
|
const rlpEncoded = rlpEncodeList(txFields);
|
||||||
|
const msgHash = keccak_256(rlpEncoded);
|
||||||
|
console.log('\nMessage hash:', bytesToHex(msgHash));
|
||||||
|
|
||||||
|
// Sign
|
||||||
|
const sigBytes = secp256k1.sign(msgHash, privateKeyBytes, { lowS: true });
|
||||||
|
const r = bytesToHex(sigBytes.slice(0, 32));
|
||||||
|
const s = bytesToHex(sigBytes.slice(32, 64));
|
||||||
|
console.log('Signature r:', r);
|
||||||
|
console.log('Signature s:', s);
|
||||||
|
|
||||||
|
// Now try to recover address from signature
|
||||||
|
// We need to try both recovery values
|
||||||
|
const sig = secp256k1.Signature.fromHex(r + s);
|
||||||
|
|
||||||
|
for (let rec = 0; rec <= 1; rec++) {
|
||||||
|
try {
|
||||||
|
const sigWithRec = sig.addRecoveryBit(rec);
|
||||||
|
const recoveredPoint = sigWithRec.recoverPublicKey(msgHash);
|
||||||
|
// Get uncompressed public key bytes
|
||||||
|
const recoveredPubHex = recoveredPoint.toHex ? recoveredPoint.toHex(false) : null;
|
||||||
|
if (recoveredPubHex) {
|
||||||
|
const recoveredPubBytes = hexToBytes(recoveredPubHex);
|
||||||
|
const recoveredPubNoPrefix = recoveredPubBytes.slice(1);
|
||||||
|
const recoveredHash = keccak_256(recoveredPubNoPrefix);
|
||||||
|
const recoveredAddress = '0x' + bytesToHex(recoveredHash.slice(-20));
|
||||||
|
console.log(`\nRecovery ${rec}:`);
|
||||||
|
console.log(' Recovered address:', recoveredAddress);
|
||||||
|
if (recoveredAddress.toLowerCase() === expectedAddress.toLowerCase()) {
|
||||||
|
console.log(' *** MATCH! Use recovery =', rec);
|
||||||
|
console.log(' v =', CHAIN_ID * 2 + 35 + rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`Recovery ${rec} failed:`, e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue