diff --git a/.env.example b/.env.example index ebfca42..9927aed 100644 --- a/.env.example +++ b/.env.example @@ -39,6 +39,7 @@ BLAST_RPC= MODE_RPC= MANTLE_RPC= MEGAETH_RPC= +RISE_RPC= GNOSIS_RPC= SONIC_RPC= UNICHAIN_RPC= @@ -81,6 +82,7 @@ WORLDCHAIN_ETHERSCAN_KEY= SEI_ETHERSCAN_KEY= SONEIUM_ETHERSCAN_KEY= MEGAETH_ETHERSCAN_KEY= +RISE_ETHERSCAN_KEY= # optional; RISE Blockscout does not require a key PLUME_ETHERSCAN_KEY= ETHEREAL_ETHERSCAN_KEY= KATANA_ETHERSCAN_KEY= diff --git a/deployments.csv b/deployments.csv index f131bce..2f6f57c 100644 --- a/deployments.csv +++ b/deployments.csv @@ -11,6 +11,7 @@ chainId,variant,allowanceHolderAddress,allowanceHolderSalt,allowanceHolderSaltTe 999,cancun,0x50c4E75a512F2A14A7b304787Adf79C4531A5909,0xa450483209637d11f92238066a6b1f405ae093536f02dda3b90a36d36f180570,AllowanceHolder50c4e7:5981577,0xe0afa70daed24ec949499638683365cbe4cbf097a1c8417a730e4b497cfb4610,0x0be5794255d21df0f4a10a516428f8d06805779d69b1714297bebcc18971e0b4,0x50cFe7c1938dB66A1a6D2e86D36F39FBef3d5c4a,0x4c57cf418d2865efb93a3c31021f230798eaca0458d188fbb593e329718139ab,OpenRouter50cfe7:4030514,0x0e5ff42eb7810767de756c833a042818f95052b885634a3dc3adb679a4652f48,0xd1dbc2c8ca87939cadf58e4eb91832cbe44bd5d12e3a0a0d56c76928a818e26b,0x8A774c1B73998A54ff09341f3cfF8A0010BbA7f1,0xeb8d08957ffb6da6c84ab1f89e95f4e08331fa81834e21d00754af20ec74d453,BungeeReceiver,0x1e4cf28950cc422f6b2112db77b8c0b0025c176291f984166889b8157de9dfe6,0x3e3fdfa261d7f00f53c22b4ba051f0da1903402669591bcef63d51ebe3085108,0xC914815120FA5A7e05748398C9fDf1d1b2729008,0x7c3bbaa3e26afa737955bd8665389dae8745dd537430122c9545abb09f85e34b,CalldataExecutor,0x2ac2791e955dbd2e9787486e2a4a9ba669d27cb1b642ade54a1221a5ccd53b64,0x037de760dbd500210ed5c68706a16171ec415563c6136e52d6a9930a5f53e32a 1329,cancun,0x50c4E75a512F2A14A7b304787Adf79C4531A5909,0xa450483209637d11f92238066a6b1f405ae093536f02dda3b90a36d36f180570,AllowanceHolder50c4e7:5981577,0xe0afa70daed24ec949499638683365cbe4cbf097a1c8417a730e4b497cfb4610,0x0be5794255d21df0f4a10a516428f8d06805779d69b1714297bebcc18971e0b4,0x50cFe7c1938dB66A1a6D2e86D36F39FBef3d5c4a,0x4c57cf418d2865efb93a3c31021f230798eaca0458d188fbb593e329718139ab,OpenRouter50cfe7:4030514,0x0e5ff42eb7810767de756c833a042818f95052b885634a3dc3adb679a4652f48,0xd1dbc2c8ca87939cadf58e4eb91832cbe44bd5d12e3a0a0d56c76928a818e26b,0x8A774c1B73998A54ff09341f3cfF8A0010BbA7f1,0xeb8d08957ffb6da6c84ab1f89e95f4e08331fa81834e21d00754af20ec74d453,BungeeReceiver,0x1e4cf28950cc422f6b2112db77b8c0b0025c176291f984166889b8157de9dfe6,0x3e3fdfa261d7f00f53c22b4ba051f0da1903402669591bcef63d51ebe3085108,0xC914815120FA5A7e05748398C9fDf1d1b2729008,0x7c3bbaa3e26afa737955bd8665389dae8745dd537430122c9545abb09f85e34b,CalldataExecutor,0x2ac2791e955dbd2e9787486e2a4a9ba669d27cb1b642ade54a1221a5ccd53b64,0x037de760dbd500210ed5c68706a16171ec415563c6136e52d6a9930a5f53e32a 1868,cancun,0x50c4E75a512F2A14A7b304787Adf79C4531A5909,0xa450483209637d11f92238066a6b1f405ae093536f02dda3b90a36d36f180570,AllowanceHolder50c4e7:5981577,0xe0afa70daed24ec949499638683365cbe4cbf097a1c8417a730e4b497cfb4610,0x0be5794255d21df0f4a10a516428f8d06805779d69b1714297bebcc18971e0b4,0x50cFe7c1938dB66A1a6D2e86D36F39FBef3d5c4a,0x4c57cf418d2865efb93a3c31021f230798eaca0458d188fbb593e329718139ab,OpenRouter50cfe7:4030514,0x0e5ff42eb7810767de756c833a042818f95052b885634a3dc3adb679a4652f48,0xd1dbc2c8ca87939cadf58e4eb91832cbe44bd5d12e3a0a0d56c76928a818e26b,0x8A774c1B73998A54ff09341f3cfF8A0010BbA7f1,0xeb8d08957ffb6da6c84ab1f89e95f4e08331fa81834e21d00754af20ec74d453,BungeeReceiver,0x1e4cf28950cc422f6b2112db77b8c0b0025c176291f984166889b8157de9dfe6,0x3e3fdfa261d7f00f53c22b4ba051f0da1903402669591bcef63d51ebe3085108,0xC914815120FA5A7e05748398C9fDf1d1b2729008,0x7c3bbaa3e26afa737955bd8665389dae8745dd537430122c9545abb09f85e34b,CalldataExecutor,0x2ac2791e955dbd2e9787486e2a4a9ba669d27cb1b642ade54a1221a5ccd53b64,0x037de760dbd500210ed5c68706a16171ec415563c6136e52d6a9930a5f53e32a +4153,cancun,0x50c4E75a512F2A14A7b304787Adf79C4531A5909,0xa450483209637d11f92238066a6b1f405ae093536f02dda3b90a36d36f180570,AllowanceHolder50c4e7:5981577,0x7b4c1230f4398f130d0763a180f21f0dbcae086cbd4a52746c4374a8d5620165,0x1919e6d868d2cc2e7de33d97a656149d47f37b87d0eea3f07a6a404663746d4f,0x50cFe7c1938dB66A1a6D2e86D36F39FBef3d5c4a,0x4c57cf418d2865efb93a3c31021f230798eaca0458d188fbb593e329718139ab,OpenRouter50cfe7:4030514,0x0e5ff42eb7810767de756c833a042818f95052b885634a3dc3adb679a4652f48,0xd1dbc2c8ca87939cadf58e4eb91832cbe44bd5d12e3a0a0d56c76928a818e26b,0x8A774c1B73998A54ff09341f3cfF8A0010BbA7f1,0xeb8d08957ffb6da6c84ab1f89e95f4e08331fa81834e21d00754af20ec74d453,BungeeReceiver,0x8c61bf68799b5897057a153c134492e43faa90a4caa0d9ce5d1016e4dec6ae5e,0x3e3fdfa261d7f00f53c22b4ba051f0da1903402669591bcef63d51ebe3085108,0xC914815120FA5A7e05748398C9fDf1d1b2729008,0x7c3bbaa3e26afa737955bd8665389dae8745dd537430122c9545abb09f85e34b,CalldataExecutor,0x2ac2791e955dbd2e9787486e2a4a9ba669d27cb1b642ade54a1221a5ccd53b64,0x037de760dbd500210ed5c68706a16171ec415563c6136e52d6a9930a5f53e32a 4217,cancun,0x50c4E75a512F2A14A7b304787Adf79C4531A5909,0xa450483209637d11f92238066a6b1f405ae093536f02dda3b90a36d36f180570,AllowanceHolder50c4e7:5981577,0xe0afa70daed24ec949499638683365cbe4cbf097a1c8417a730e4b497cfb4610,0x0be5794255d21df0f4a10a516428f8d06805779d69b1714297bebcc18971e0b4,,,,,,,,,,,,,,, 4326,cancun,0x50c4E75a512F2A14A7b304787Adf79C4531A5909,0xa450483209637d11f92238066a6b1f405ae093536f02dda3b90a36d36f180570,AllowanceHolder50c4e7:5981577,0xe0afa70daed24ec949499638683365cbe4cbf097a1c8417a730e4b497cfb4610,0x0be5794255d21df0f4a10a516428f8d06805779d69b1714297bebcc18971e0b4,0x50cFe7c1938dB66A1a6D2e86D36F39FBef3d5c4a,0x4c57cf418d2865efb93a3c31021f230798eaca0458d188fbb593e329718139ab,OpenRouter50cfe7:4030514,0x0e5ff42eb7810767de756c833a042818f95052b885634a3dc3adb679a4652f48,0xd1dbc2c8ca87939cadf58e4eb91832cbe44bd5d12e3a0a0d56c76928a818e26b,0x8A774c1B73998A54ff09341f3cfF8A0010BbA7f1,0xeb8d08957ffb6da6c84ab1f89e95f4e08331fa81834e21d00754af20ec74d453,BungeeReceiver,0x1e4cf28950cc422f6b2112db77b8c0b0025c176291f984166889b8157de9dfe6,0x3e3fdfa261d7f00f53c22b4ba051f0da1903402669591bcef63d51ebe3085108,0xC914815120FA5A7e05748398C9fDf1d1b2729008,0x7c3bbaa3e26afa737955bd8665389dae8745dd537430122c9545abb09f85e34b,CalldataExecutor,0x2ac2791e955dbd2e9787486e2a4a9ba669d27cb1b642ade54a1221a5ccd53b64,0x037de760dbd500210ed5c68706a16171ec415563c6136e52d6a9930a5f53e32a 4663,cancun,0x50c4E75a512F2A14A7b304787Adf79C4531A5909,0xa450483209637d11f92238066a6b1f405ae093536f02dda3b90a36d36f180570,AllowanceHolder50c4e7:5981577,0xe0afa70daed24ec949499638683365cbe4cbf097a1c8417a730e4b497cfb4610,0x0be5794255d21df0f4a10a516428f8d06805779d69b1714297bebcc18971e0b4,0x50cFe7c1938dB66A1a6D2e86D36F39FBef3d5c4a,0x4c57cf418d2865efb93a3c31021f230798eaca0458d188fbb593e329718139ab,OpenRouter50cfe7:4030514,0x0e5ff42eb7810767de756c833a042818f95052b885634a3dc3adb679a4652f48,0xd1dbc2c8ca87939cadf58e4eb91832cbe44bd5d12e3a0a0d56c76928a818e26b,0x8A774c1B73998A54ff09341f3cfF8A0010BbA7f1,0xeb8d08957ffb6da6c84ab1f89e95f4e08331fa81834e21d00754af20ec74d453,BungeeReceiver,0x1e4cf28950cc422f6b2112db77b8c0b0025c176291f984166889b8157de9dfe6,0x3e3fdfa261d7f00f53c22b4ba051f0da1903402669591bcef63d51ebe3085108,0xC914815120FA5A7e05748398C9fDf1d1b2729008,0x7c3bbaa3e26afa737955bd8665389dae8745dd537430122c9545abb09f85e34b,CalldataExecutor,0x2ac2791e955dbd2e9787486e2a4a9ba669d27cb1b642ade54a1221a5ccd53b64,0x037de760dbd500210ed5c68706a16171ec415563c6136e52d6a9930a5f53e32a diff --git a/deployments/prod/addresses/rise.json b/deployments/prod/addresses/rise.json new file mode 100644 index 0000000..68c28d7 --- /dev/null +++ b/deployments/prod/addresses/rise.json @@ -0,0 +1,5 @@ +{ + "RFQVaultExecutor": "0x97caca78ac2a94c67643d07843f85afaa44a3ea5", + "AcrossERC20AmountManipulator": "0x05481b7163c376ab4cb0ebc7d17f2cf7651042ee", + "MathManipulator": "0x3c3d4F3D636C06bcEb3bCc71EafE36486Ef40581" +} diff --git a/hardhat.config.ts b/hardhat.config.ts index 40cbbb8..61f2ed8 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -146,6 +146,11 @@ const config: HardhatUserConfig = { chainId: 4326, accounts, }, + rise: { + url: process.env.RISE_RPC ?? 'https://rpc.risechain.com/', + chainId: 4153, + accounts, + }, robinhood: { url: process.env.ROBINHOOD_RPC ?? '', chainId: 4663, @@ -267,6 +272,7 @@ const config: HardhatUserConfig = { sei: explorerApiKey(process.env.SEI_ETHERSCAN_KEY), soneium: explorerApiKey(process.env.SONEIUM_ETHERSCAN_KEY), megaeth: explorerApiKey(process.env.MEGAETH_ETHERSCAN_KEY), + rise: process.env.RISE_ETHERSCAN_KEY ?? 'blockscout', robinhood: explorerApiKey(process.env.ROBINHOOD_ETHERSCAN_KEY), plume: explorerApiKey(process.env.PLUME_ETHERSCAN_KEY), ethereal: explorerApiKey(process.env.ETHEREAL_ETHERSCAN_KEY), @@ -453,6 +459,14 @@ const config: HardhatUserConfig = { browserURL: 'https://mega.etherscan.io', }, }, + { + network: 'rise', + chainId: 4153, + urls: { + apiURL: 'https://explorer.risechain.com/api', + browserURL: 'https://explorer.risechain.com', + }, + }, { network: 'robinhood', chainId: 4663, diff --git a/package.json b/package.json index a1e258b..4f8f1f9 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "deploy:allowance-holder": "hardhat run scripts/deploy/deployAllowanceHolder.ts --network", "deploy:receiver-executor": "hardhat run scripts/deploy/deployReceiverAllChains.ts", "deploy:across-manipulator": "hardhat run scripts/deploy/deployAcrossERC20AmountManipulator.ts --network", + "deploy:math-manipulator": "hardhat run scripts/deploy/deployMathManipulator.ts --network", "deploy:cctp-claim-executor:all": "ts-node scripts/deploy/deployCctpClaimExecutorAllChains.ts", "deploy:rfq-vault-executor:all": "ts-node scripts/deploy/deployRFQVaultExecutorAllChains.ts", "deploy:rfq-vault-executor": "hardhat run scripts/deploy/deployRFQVaultExecutor.ts --network", diff --git a/scripts/deploy/create3.ts b/scripts/deploy/create3.ts index 01046d9..bb50426 100644 --- a/scripts/deploy/create3.ts +++ b/scripts/deploy/create3.ts @@ -55,6 +55,14 @@ export const ACROSS_MANIPULATOR_CREATE3_SALT = keccak256( toUtf8Bytes(ACROSS_MANIPULATOR_CREATE3_SALT_TEXT), ); +/** CREATE3 salt label used by `deployMathManipulator.ts`. */ +export const MATH_MANIPULATOR_CREATE3_SALT_TEXT = 'MathManipulator'; + +/** Keccak256 salt for deterministic MathManipulator CREATE3 deployments. */ +export const MATH_MANIPULATOR_CREATE3_SALT = keccak256( + toUtf8Bytes(MATH_MANIPULATOR_CREATE3_SALT_TEXT), +); + /** CREATE3 salt label used by `deployCelerExecutor.ts`. */ export const CELER_EXECUTOR_CREATE3_SALT_TEXT = 'CelerExecutor'; @@ -112,6 +120,10 @@ export const OPEN_ROUTER_EXPECTED_ADDRESS = export const ACROSS_MANIPULATOR_EXPECTED_ADDRESS = '0x05481b7163c376ab4cb0ebc7d17f2cf7651042ee'; +/** MathManipulator CREATE3 address for salt `MathManipulator` via canonical CreateX. */ +export const MATH_MANIPULATOR_EXPECTED_ADDRESS = + '0x3c3d4F3D636C06bcEb3bCc71EafE36486Ef40581'; + /** * BungeeReceiver CREATE3 address for salt `BungeeReceiver` via canonical CreateX. * Verified with {@link computeFinalAddress} (guarded salt + factory deployer), not diff --git a/scripts/deploy/deployAcrossERC20AmountManipulator.ts b/scripts/deploy/deployAcrossERC20AmountManipulator.ts index 09a5a8b..09dcbaf 100644 --- a/scripts/deploy/deployAcrossERC20AmountManipulator.ts +++ b/scripts/deploy/deployAcrossERC20AmountManipulator.ts @@ -17,7 +17,7 @@ import { decodeCreate3DeploymentFromTxReceipt, getAcrossManipulatorDeploymentStatus, } from './create3'; -import { confirm } from '../utils'; +import { writeManipulatorAddress } from './manipulatorAddresses'; async function main() { const [deployer] = await ethers.getSigners(); @@ -34,6 +34,12 @@ async function main() { console.log( `AcrossERC20AmountManipulator already deployed on ${networkName} at ${existing.address}`, ); + const filePath = await writeManipulatorAddress( + networkName, + 'AcrossERC20AmountManipulator', + existing.address, + ); + console.log('Deployment JSON:', filePath); return; } @@ -74,6 +80,12 @@ async function main() { console.log('\n=== Deployment Summary ==='); console.log(`AcrossERC20AmountManipulator: ${manipulatorAddress}`); + const filePath = await writeManipulatorAddress( + networkName, + 'AcrossERC20AmountManipulator', + manipulatorAddress, + ); + console.log('Deployment JSON:', filePath); const chainId = (await ethers.provider.getNetwork()).chainId; const skipVerify = process.env.SKIP_VERIFY?.trim().toLowerCase() === 'true'; diff --git a/scripts/deploy/deployMathManipulator.ts b/scripts/deploy/deployMathManipulator.ts new file mode 100644 index 0000000..3484c91 --- /dev/null +++ b/scripts/deploy/deployMathManipulator.ts @@ -0,0 +1,114 @@ +/** + * Deployment script for MathManipulator via CreateX CREATE3. + * + * Usage: + * npx hardhat run scripts/deploy/deployMathManipulator.ts --network + * + * Required env vars: + * DEPLOYER_PRIVATE_KEY - deployer wallet private key + */ + +import hre from 'hardhat'; +import { ethers } from 'hardhat'; +import { + CREATE_X_FACTORY, + Create3ABI, + MATH_MANIPULATOR_CREATE3_SALT, + MATH_MANIPULATOR_EXPECTED_ADDRESS, + decodeCreate3DeploymentFromTxReceipt, + hasContractBytecode, +} from './create3'; +import { writeManipulatorAddress } from './manipulatorAddresses'; + +async function persist(network: string): Promise { + const filePath = await writeManipulatorAddress( + network, + 'MathManipulator', + MATH_MANIPULATOR_EXPECTED_ADDRESS, + ); + console.log('Deployment JSON:', filePath); +} + +async function main() { + const [deployer] = await ethers.getSigners(); + const networkName = hre.network.name; + + console.log('Deployer: ', deployer.address); + console.log('Network: ', networkName); + console.log(''); + + const existingBytecode = await ethers.provider.getCode( + MATH_MANIPULATOR_EXPECTED_ADDRESS, + ); + if (hasContractBytecode(existingBytecode)) { + console.log( + `MathManipulator already deployed on ${networkName} at ${MATH_MANIPULATOR_EXPECTED_ADDRESS}`, + ); + await persist(networkName); + return; + } + + const create3Factory = new ethers.Contract( + CREATE_X_FACTORY, + Create3ABI, + deployer, + ); + const factory = await ethers.getContractFactory('MathManipulator'); + const deployTransaction = await factory.getDeployTransaction(); + if (!deployTransaction.data) { + throw new Error('MathManipulator deployment bytecode is empty'); + } + + const deployAddress = await create3Factory.deployCreate3.staticCall( + MATH_MANIPULATOR_CREATE3_SALT, + deployTransaction.data, + ); + if ( + deployAddress.toLowerCase() !== + MATH_MANIPULATOR_EXPECTED_ADDRESS.toLowerCase() + ) { + throw new Error( + `CREATE3 address ${deployAddress} does not match expected ${MATH_MANIPULATOR_EXPECTED_ADDRESS}`, + ); + } + console.log('Contract address will be:', deployAddress); + + const deployment = await create3Factory.deployCreate3( + MATH_MANIPULATOR_CREATE3_SALT, + deployTransaction.data, + ); + console.log('CREATE3 deployment tx:', deployment.hash); + const receipt = await deployment.wait(); + if (!receipt || receipt.status !== 1) { + throw new Error(`MathManipulator deployment failed: ${deployment.hash}`); + } + + const deployedAddress = decodeCreate3DeploymentFromTxReceipt({ receipt }); + if ( + !deployedAddress || + deployedAddress.toLowerCase() !== + MATH_MANIPULATOR_EXPECTED_ADDRESS.toLowerCase() + ) { + throw new Error( + `MathManipulator receipt address ${deployedAddress}, expected ${MATH_MANIPULATOR_EXPECTED_ADDRESS}`, + ); + } + + console.log('MathManipulator deployed to:', deployedAddress); + await persist(networkName); + + const skipVerify = process.env.SKIP_VERIFY?.trim().toLowerCase() === 'true'; + const chainId = (await ethers.provider.getNetwork()).chainId; + if (chainId !== 31337n && !skipVerify) { + await new Promise((resolve) => setTimeout(resolve, 5000)); + await hre.run('verify:verify', { + address: deployedAddress, + constructorArguments: [], + }); + } +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/scripts/deploy/manipulatorAddresses.ts b/scripts/deploy/manipulatorAddresses.ts new file mode 100644 index 0000000..e1aa758 --- /dev/null +++ b/scripts/deploy/manipulatorAddresses.ts @@ -0,0 +1,42 @@ +import { mkdir, readFile, writeFile } from 'fs/promises'; +import { dirname, resolve } from 'path'; + +export type ManipulatorContractName = + | 'AcrossERC20AmountManipulator' + | 'MathManipulator'; + +export async function writeManipulatorAddress( + network: string, + contractName: ManipulatorContractName, + address: string, + stage = 'prod', +): Promise { + const filePath = resolve( + process.cwd(), + 'deployments', + stage, + 'addresses', + `${network}.json`, + ); + let deployments: Record = {}; + + try { + deployments = JSON.parse(await readFile(filePath, 'utf8')) as Record< + string, + string + >; + } catch (err) { + if ((err as NodeJS.ErrnoException).code !== 'ENOENT') { + throw err; + } + } + + deployments[contractName] = address; + await mkdir(dirname(filePath), { recursive: true }); + await writeFile( + filePath, + `${JSON.stringify(deployments, null, 2)}\n`, + 'utf8', + ); + return filePath; +} diff --git a/scripts/deploy/networks.ts b/scripts/deploy/networks.ts index f89cbda..ac79c00 100644 --- a/scripts/deploy/networks.ts +++ b/scripts/deploy/networks.ts @@ -35,6 +35,7 @@ export const RECEIVER_DEPLOY_NETWORKS: readonly ReceiverDeployNetwork[] = [ { name: 'katana', chainId: CHAIN_IDS.KATANA, rpcEnvKey: 'KATANA_RPC', rpcFallback: 'https://rpc.katana.network' }, { name: 'mode', chainId: CHAIN_IDS.MODE, rpcEnvKey: 'MODE_RPC', rpcFallback: 'https://1rpc.io/mode' }, { name: 'megaeth', chainId: CHAIN_IDS.MEGAETH, rpcEnvKey: 'MEGAETH_RPC', rpcFallback: 'https://rpc.megaeth.xyz' }, + { name: 'rise', chainId: CHAIN_IDS.RISE, rpcEnvKey: 'RISE_RPC', rpcFallback: 'https://rpc.risechain.com/' }, { name: 'robinhood', chainId: CHAIN_IDS.ROBINHOOD, rpcEnvKey: 'ROBINHOOD_RPC', rpcFallback: '' }, { name: 'plume', chainId: CHAIN_IDS.PLUME, rpcEnvKey: 'PLUME_RPC', rpcFallback: 'https://rpc.plume.org' }, { name: 'blast', chainId: CHAIN_IDS.BLAST, rpcEnvKey: 'BLAST_RPC', rpcFallback: 'https://blastl2-mainnet.public.blastapi.io' }, @@ -71,6 +72,7 @@ const RPC_ENV_ALIASES: Partial> = { PLASMA_RPC: ['PLASMA_RPC_URL'], MONAD_RPC: ['MONAD_RPC_URL'], MEGAETH_RPC: ['MEGAETH_RPC_URL'], + RISE_RPC: ['RISE_RPC_URL'], ROBINHOOD_RPC: ['ROBINHOOD_RPC_URL'], }; diff --git a/scripts/deploy/openRouterBuild.ts b/scripts/deploy/openRouterBuild.ts index 5348cec..15609dc 100644 --- a/scripts/deploy/openRouterBuild.ts +++ b/scripts/deploy/openRouterBuild.ts @@ -43,6 +43,7 @@ export const OPENROUTER_NETWORK_CHAIN_IDS: Record = { arc: CHAIN_IDS.ARC, plasma: CHAIN_IDS.PLASMA, tempo: CHAIN_IDS.TEMPO, + rise: CHAIN_IDS.RISE, monad: CHAIN_IDS.MONAD, linea: CHAIN_IDS.LINEA, mantle: CHAIN_IDS.MANTLE, @@ -83,6 +84,7 @@ export const OPENROUTER_DEPLOY_NETWORKS = [ 'katana', 'mode', 'megaeth', + 'rise', 'robinhood', 'plume', 'blast', diff --git a/scripts/deploy/verifyAllowanceHolderBatch.ts b/scripts/deploy/verifyAllowanceHolderBatch.ts index a44587a..d3b019a 100644 --- a/scripts/deploy/verifyAllowanceHolderBatch.ts +++ b/scripts/deploy/verifyAllowanceHolderBatch.ts @@ -25,7 +25,7 @@ interface AllowanceHolderDeploymentRecord { type ExplorerConfig = | { verifier: 'etherscan'; chainArg: string } - | { verifier: 'custom'; chainArg: string; verifierUrl: string } + | { verifier: 'custom'; chainArg: string; verifierUrl: string; apiKeyOptional?: boolean } | { verifier: 'sourcify'; chainArg: string }; const ADDR_HEX_RE = /^0x[a-fA-F0-9]{40}$/; @@ -63,6 +63,7 @@ const EXPLORERS_BY_CHAIN_ID = new Map([ [9745, { verifier: 'custom', chainArg: '1', verifierUrl: 'https://api.etherscan.io/v2/api?chainid=9745' }], [98866, { verifier: 'sourcify', chainArg: '98866' }], [4217, { verifier: 'sourcify', chainArg: '4217' }], + [4153, { verifier: 'custom', chainArg: '1', verifierUrl: 'https://explorer.risechain.com/api', apiKeyOptional: true }], ]); function readDeploymentRecords(): AllowanceHolderDeploymentRecord[] { @@ -134,12 +135,18 @@ function verifierArgs( } if (config.verifier === 'custom') { - args.push('--verifier-url', config.verifierUrl, '--verifier-api-key', apiKey); + args.push('--verifier-url', config.verifierUrl); + if (apiKey) { + args.push('--verifier-api-key', apiKey); + } } else if (config.verifier === 'etherscan') { args.push('--etherscan-api-key', apiKey); } - if (config.verifier === 'custom' && config.chainArg === '1') { + if ( + config.verifier === 'custom' && + (config.chainArg === '1' || config.apiKeyOptional) + ) { args.push('--skip-is-verified-check'); } @@ -179,7 +186,11 @@ function main() { ); continue; } - if (explorer.verifier !== 'sourcify' && !apiKey) { + if ( + explorer.verifier !== 'sourcify' && + !apiKey && + !(explorer.verifier === 'custom' && explorer.apiKeyOptional) + ) { throw new Error('ETHERSCAN_API_KEY is required for non-Sourcify verification'); } diff --git a/scripts/e2e/config.ts b/scripts/e2e/config.ts index 709f9ba..483bbe4 100644 --- a/scripts/e2e/config.ts +++ b/scripts/e2e/config.ts @@ -27,6 +27,8 @@ export const CHAIN_IDS = { ARC: 5042, /** Tempo mainnet — AllowanceHolder only; OpenRouter not deployed (deposit-only chain). */ TEMPO: 4217, + /** RISE mainnet. */ + RISE: 4153, /** Robinhood mainnet. */ ROBINHOOD: 4663, /** MegaETH mainnet — Relay USDM → Base USDC e2e. */ @@ -68,6 +70,7 @@ export const BLOCK_EXPLORER_TX_PREFIX: Record = { [CHAIN_IDS.TEMPO]: 'https://explore.mainnet.tempo.xyz/tx/', [CHAIN_IDS.ROBINHOOD]: 'https://robinhoodchain.blockscout.com/tx/', [CHAIN_IDS.MEGAETH]: 'https://mega.etherscan.io/tx/', + [CHAIN_IDS.RISE]: 'https://explorer.risechain.com/tx/', [CHAIN_IDS.ARBITRUM]: 'https://arbiscan.io/tx/', [CHAIN_IDS.LINEA]: 'https://lineascan.build/tx/', [CHAIN_IDS.INK]: 'https://explorer.inkonchain.com/tx/', @@ -166,6 +169,7 @@ export const OPEN_ROUTER_CHAIN_IDS: readonly number[] = [ CHAIN_IDS.KATANA, CHAIN_IDS.MODE, CHAIN_IDS.MEGAETH, + CHAIN_IDS.RISE, CHAIN_IDS.ROBINHOOD, CHAIN_IDS.PLUME, CHAIN_IDS.BLAST,