Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@
"node": ">=22.0.0"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
"workspaces": [
"packages/*"
],
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"@requestnetwork/smart-contracts/@openzeppelin/**"
]
},
"repository": {
"type": "git",
"url": "git+https://github.com/RequestNetwork/requestNetwork.git"
Expand Down
12 changes: 9 additions & 3 deletions packages/smart-contracts/deployments/tron/mainnet.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
{
"network": "mainnet",
"chainId": "1",
"timestamp": "2024-01-01T00:00:00.000Z",
"deployer": "TO_BE_FILLED_ON_DEPLOYMENT",
"note": "Existing deployment from handover document",
"timestamp": "2026-05-26T17:02:20.157Z",
"deployer": "TR7EydtGnsxriSieLfEuspTAqhQRmoscWC",
"deploymentDuration": "3.244s",
"note": "Deployment of ERC20BatchPayments",
"contracts": {
"ERC20FeeProxy": {
"address": "TCUDPYnS9dH3WvFEaE7wN7vnDa51J4R4fd",
"hexAddress": "411b6ca35d39842cf8fbe49000653a1505412da659",
"creationBlockNumber": 79216121
},
"ERC20BatchPayments": {
"address": "TUdcGd29QpV65MkbqgBLWJKbTG3UL7PuQB",
"hexAddress": "41ccb57e7bbb729b1c8c94294a61b658a6f2304281",
"creationBlockNumber": 83048743
}
}
}
5 changes: 5 additions & 0 deletions packages/smart-contracts/deployments/tron/nile.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
"address": "THK5rNmrvCujhmrXa5DB1dASepwXTr9cJs",
"hexAddress": "41508b3b4059c40bb3aac5da5ac006ccdd9c4dc957",
"creationBlockNumber": 63208782
},
"ERC20BatchPayments": {
"address": "TDnU5eY8Et3QdZRWMSTvoXQnxQeMxF7CE4",
"hexAddress": "4129d883d52bf19f97ef0a0c2edb99a679b0d5e12e",
"creationBlockNumber": 67775288
}
}
}
122 changes: 94 additions & 28 deletions packages/smart-contracts/scripts/tron/deploy-mainnet.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/**
* Tron Mainnet Deployment Script
*
* This script deploys the ERC20FeeProxy to Tron mainnet.
* This script deploys the ERC20FeeProxy and ERC20BatchPayments to Tron mainnet.
*
* ⚠️ WARNING: This deploys to MAINNET with real TRX!
*
Expand All @@ -28,6 +28,18 @@ const PRIVATE_KEY = process.env.TRON_PRIVATE_KEY;
// Safety check
const CONFIRM_MAINNET = process.env.CONFIRM_MAINNET_DEPLOY === 'true';

const MAINNET_DEPLOYMENT_PATH = path.join(__dirname, '../../deployments/tron/mainnet.json');

/**
* Contracts to deploy
*
* Comment out the contracts you don't want to deploy.
*/
const CONTRACTS_TO_DEPLOY = [
//'ERC20FeeProxy',
'ERC20BatchPayments',
];

if (!PRIVATE_KEY) {
console.error('Error: TRON_PRIVATE_KEY environment variable is required');
process.exit(1);
Expand All @@ -49,6 +61,13 @@ async function loadArtifact(contractName) {
return JSON.parse(fs.readFileSync(artifactPath, 'utf8'));
}

function loadExistingMainnetDeployment() {
if (!fs.existsSync(MAINNET_DEPLOYMENT_PATH)) {
return null;
}
return JSON.parse(fs.readFileSync(MAINNET_DEPLOYMENT_PATH, 'utf8'));
}

async function confirmDeployment() {
if (CONFIRM_MAINNET) {
return true;
Expand Down Expand Up @@ -92,6 +111,24 @@ async function deployContract(contractName, constructorArgs = []) {
};
}

async function deployContractWrapper({
contractName,
deployments,
blockNumbers,
constructorArgs = [],
}) {
const contract = await deployContract(contractName, constructorArgs);
deployments[contractName] = {
address: contract.address,
hexAddress: contract.hexAddress,
};

// Get block number
const block = await tronWeb.trx.getCurrentBlock();
const blockNumber = block.block_header.raw_data.number;
blockNumbers[contractName] = blockNumber;
}

async function main() {
console.log('╔══════════════════════════════════════════════════════════╗');
console.log('║ TRON MAINNET DEPLOYMENT ║');
Expand Down Expand Up @@ -123,59 +160,88 @@ async function main() {
console.log('\n🚀 Starting mainnet deployment...\n');

const deployments = {};
const blockNumbers = {};
const startTime = Date.now();

try {
// Deploy ERC20FeeProxy only (no test tokens on mainnet)
const erc20FeeProxy = await deployContract('ERC20FeeProxy');
deployments.ERC20FeeProxy = {
address: erc20FeeProxy.address,
hexAddress: erc20FeeProxy.hexAddress,
};
const existingDeployment = loadExistingMainnetDeployment();

// Deploy ERC20FeeProxy
if (CONTRACTS_TO_DEPLOY.includes('ERC20FeeProxy')) {
await deployContractWrapper({ contractName: 'ERC20FeeProxy', deployments, blockNumbers });
await new Promise((resolve) => setTimeout(resolve, 5000));
}

// Deploy ERC20BatchPayments
if (CONTRACTS_TO_DEPLOY.includes('ERC20BatchPayments')) {
const erc20FeeProxyAddress = deployments.ERC20FeeProxy
? deployments.ERC20FeeProxy.address
: existingDeployment.contracts.ERC20FeeProxy.address;

// Get block number
const block = await tronWeb.trx.getCurrentBlock();
const blockNumber = block.block_header.raw_data.number;
if (!erc20FeeProxyAddress) {
console.error(
'ERC20FeeProxy address not found in deployments/tron/mainnet.json; cannot deploy ERC20BatchPayments',
);
process.exit(1);
}

console.log('Using ERC20FeeProxy at:', erc20FeeProxyAddress);
await deployContractWrapper({
contractName: 'ERC20BatchPayments',
deployments,
blockNumbers,
constructorArgs: [erc20FeeProxyAddress],
});
}

// Print summary
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ MAINNET DEPLOYMENT SUMMARY ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');

console.log('ERC20FeeProxy:');
console.log(` Address: ${deployments.ERC20FeeProxy.address}`);
console.log(` Block: ${blockNumber}`);
console.log(
` Tronscan: https://tronscan.org/#/contract/${deployments.ERC20FeeProxy.address}`,
);
for (const contractName of Object.keys(deployments)) {
console.log(`${contractName}:`);
console.log(` Address: ${deployments[contractName].address}`);
console.log(` Block: ${blockNumbers[contractName]}`);
console.log(
` Tronscan: https://tronscan.org/#/contract/${deployments[contractName].address}`,
);
}

const newContracts = Object.entries(deployments).reduce((acc, [contractName, contract]) => {
acc[contractName] = {
...contract,
creationBlockNumber: blockNumbers[contractName],
};
return acc;
}, {});

const contracts = {
...(existingDeployment.contracts || {}),
...newContracts,
};

// Save deployment info
// Save deployment info (merge with existing mainnet.json)
const deploymentInfo = {
network: 'mainnet',
chainId: '1',
timestamp: new Date().toISOString(),
deployer: deployerAddress,
deploymentDuration: `${(Date.now() - startTime) / 1000}s`,
contracts: {
ERC20FeeProxy: {
...deployments.ERC20FeeProxy,
creationBlockNumber: blockNumber,
},
},
contracts,
};

const outputPath = path.join(__dirname, '../../deployments/tron/mainnet.json');
fs.writeFileSync(outputPath, JSON.stringify(deploymentInfo, null, 2));
console.log(`\nDeployment info saved to: ${outputPath}`);
fs.mkdirSync(path.dirname(MAINNET_DEPLOYMENT_PATH), { recursive: true });
fs.writeFileSync(MAINNET_DEPLOYMENT_PATH, JSON.stringify(deploymentInfo, null, 2));
console.log(`\nDeployment info saved to: ${MAINNET_DEPLOYMENT_PATH}`);

// Next steps
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ NEXT STEPS ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
console.log('1. Verify contract on Tronscan');
console.log('2. Run verification script: yarn tron:verify:mainnet');
console.log('3. Update artifact registry in:');
console.log(' packages/smart-contracts/src/lib/artifacts/ERC20FeeProxy/index.ts');
console.log('3. Update artifact registry with new deployment addresses');
console.log('4. Test with a real TRC20 token payment');
} catch (error) {
console.error('\n❌ Deployment failed:', error.message);
Expand Down
12 changes: 12 additions & 0 deletions packages/smart-contracts/scripts/tron/deploy-nile.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ async function main() {
hexAddress: erc20FeeProxy.address,
};

// 2. Deploy ERC20BatchPayments
const erc20BatchPayments = await deployContract('ERC20BatchPayments', [
deployments.ERC20FeeProxy.address,
]);
deployments.ERC20BatchPayments = {
address: tronWeb.address.fromHex(erc20BatchPayments.address),
hexAddress: erc20BatchPayments.address,
};

// 2. Deploy TestTRC20 for testing
const testToken = await deployContract('TestTRC20', [
'1000000000000000000000000000', // 1 billion tokens
Expand Down Expand Up @@ -141,6 +150,9 @@ async function main() {
console.log('╚══════════════════════════════════════════════════════════╝\n');
console.log('1. Verify contracts on Nile Tronscan:');
console.log(' https://nile.tronscan.org/#/contract/' + deployments.ERC20FeeProxy.address);
console.log(
' https://nile.tronscan.org/#/contract/' + deployments.ERC20BatchPayments.address,
);
console.log('\n2. Run tests against deployed contracts:');
console.log(' TRON_PRIVATE_KEY=... yarn tron:test:nile');
console.log('\n3. Update artifact registry with deployment addresses');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
{
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "_paymentErc20FeeProxy",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "address",
"name": "_erc20Address",
"type": "address"
}
],
"name": "approvePaymentProxyToSpend",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "_tokenAddresses",
"type": "address[]"
},
{
"internalType": "address[]",
"name": "_recipients",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "_amounts",
"type": "uint256[]"
},
{
"internalType": "bytes[]",
"name": "_paymentReferences",
"type": "bytes[]"
},
{
"internalType": "uint256[]",
"name": "_feeAmounts",
"type": "uint256[]"
},
{
"internalType": "address",
"name": "_feeAddress",
"type": "address"
}
],
"name": "batchERC20PaymentsMultiTokensWithReference",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_tokenAddress",
"type": "address"
},
{
"internalType": "address[]",
"name": "_recipients",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "_amounts",
"type": "uint256[]"
},
{
"internalType": "bytes[]",
"name": "_paymentReferences",
"type": "bytes[]"
},
{
"internalType": "uint256[]",
"name": "_feeAmounts",
"type": "uint256[]"
},
{
"internalType": "address",
"name": "_feeAddress",
"type": "address"
}
],
"name": "batchERC20PaymentsWithReference",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "paymentErc20FeeProxy",
"outputs": [
{
"internalType": "contract IERC20FeeProxy",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
}
]
}
Loading
Loading