From 36fc728dd551855c7c93918b9d4d4f32004ada81 Mon Sep 17 00:00:00 2001 From: kyzooghost <73516204+kyzooghost@users.noreply.github.com> Date: Thu, 24 Apr 2025 18:01:27 +1000 Subject: [PATCH] [Feat] Postman Sponsorship manual test script (#899) * postman test script * logString fixes * Revert "logString fixes" This reverts commit 66e15176d553abb741194be8446bf63e4defe114. --- postman/scripts/helpers.ts | 2 +- postman/scripts/manualTestSendMessages.ts | 194 ++++++++++++++++++++++ postman/scripts/sendMessageOnL1.ts | 2 +- 3 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 postman/scripts/manualTestSendMessages.ts diff --git a/postman/scripts/helpers.ts b/postman/scripts/helpers.ts index fcbf9335..b6e94129 100644 --- a/postman/scripts/helpers.ts +++ b/postman/scripts/helpers.ts @@ -1,6 +1,6 @@ import { ethers } from "ethers"; -export async function encodeSendMessage( +export function encodeSendMessage( sender: string, receiver: string, fee: bigint, diff --git a/postman/scripts/manualTestSendMessages.ts b/postman/scripts/manualTestSendMessages.ts new file mode 100644 index 00000000..86ed7ce3 --- /dev/null +++ b/postman/scripts/manualTestSendMessages.ts @@ -0,0 +1,194 @@ +// Manual script to run on devnet & Sepolia deployments to test various scenarios + +/** USAGE + +npx ts-node postman/scripts/manualTestSendMessages.ts \ + --rpc-url= \ + --priv-key= \ + --deployment-env= + + */ + +/** + * Test Scenarios + * -------------- + * + * (Below MAX_POSTMAN_SPONSOR_GAS_LIMIT or 250_000 gas used): + * + * 1. Fee = 0 + * Should be auto-claimed on L2 + * + * 2. Fee = Underpriced + * Should be auto-claimed on L2 + * + * 3. Fee = correctly priced + * Should be auto-claimed on L2 + * + * (Above MAX_POSTMAN_SPONSOR_GAS_LIMIT or 250_000 gas used): + * + * 4. Fee = 0 + * Should not be auto-claimed on L2, and log 'Found message with zero fee' + * + * 5. Fee = Underpriced + * Should not be auto-claimed on L2, and log 'Fee underpriced found in this message' + * + * 6. Fee = correctly priced + * Should be auto-claimed on L2 + */ + +import { config } from "dotenv"; +import yargs from "yargs"; +import { hideBin } from "yargs/helpers"; +import { sanitizePrivKey } from "./cli"; +import { ContractTransactionReceipt, Wallet, JsonRpcProvider } from "ethers"; +import { LineaRollup, LineaRollup__factory } from "@consensys/linea-sdk"; +import { SendMessageArgs } from "./types"; +import { encodeSendMessage } from "./helpers"; + +// CONFIG INPUT +config(); +const argv = yargs(hideBin(process.argv)) + .option("rpc-url", { + describe: "Sepolia URL", + type: "string", + demandOption: true, + }) + .option("priv-key", { + describe: "Signer private key on Sepolia", + type: "string", + demandOption: true, + coerce: sanitizePrivKey("priv-key"), + }) + .option("deployment-env", { + describe: "Deployment environment", + type: "string", + choices: ["devnet", "sepolia"], + demandOption: true, + }) + .parseSync(); + +// TYPES +type TestScenario = { + logString: string; + fee: bigint; + calldata: string; +}; + +type DeploymentEnv = "devnet" | "sepolia"; + +// VARIABLES +const ZERO_FEE = 0n; +const UNDERPRICED_FEE = 1n; +const CORRECTLY_PRICED_FEE = 10000000000000000n; // 0.01 ETH, conservatively high estimate +const NO_CALLDATA = "0x"; +const SPAM_CALLDATA = "0xdead".padEnd(40964, "dead"); + +const L1_MESSAGE_SERVICE_ADDRESS: Record = { + devnet: "0x2A5CDCfc38856e2590E9Bd32F54Fa348e5De5f48", + sepolia: "0xB218f8A4Bc926cF1cA7b3423c154a0D627Bdb7E5", +}; + +const testScenarios: TestScenario[] = [ + // Below 250,000 gas used + { + logString: "Case 1: <250_000 gas, 0 fee => Should be auto-claimed on L2", + fee: ZERO_FEE, + calldata: NO_CALLDATA, + }, + { + logString: "Case 2: <250_000 gas, underpriced fee => Should be auto-claimed on L2", + fee: UNDERPRICED_FEE, + calldata: NO_CALLDATA, + }, + { + logString: "Case 3: <250_000 gas, correct fee => Should be auto-claimed on L2", + fee: CORRECTLY_PRICED_FEE, + calldata: NO_CALLDATA, + }, + + // Above 250,000 gas used + { + logString: + "Case 4: >250_000 gas, 0 fee => Should NOT be auto-claimed, and should find Postman log 'Found message with zero fee'", + fee: ZERO_FEE, + calldata: SPAM_CALLDATA, + }, + { + logString: + "Case 5: >250_000 gas, underpriced fee => Should NOT be auto-claimed, and should find Postman log 'Fee underpriced found in this message'", + fee: UNDERPRICED_FEE, + calldata: SPAM_CALLDATA, + }, + { + logString: "Case 6: >250_000 gas, correct fee => Should be auto-claimed on L2", + fee: CORRECTLY_PRICED_FEE, + calldata: SPAM_CALLDATA, + }, +]; + +// LOCAL FUNCTIONS +const sendMessage = async ( + deploymentEnv: DeploymentEnv, + sender: Wallet, + args: SendMessageArgs, + messageNonce: bigint, + senderNonce: number, + logString: string, +): Promise => { + const lineaRollup = LineaRollup__factory.connect(L1_MESSAGE_SERVICE_ADDRESS[deploymentEnv], sender) as LineaRollup; + const tx = await lineaRollup.sendMessage(args.to, args.fee, args.calldata, { value: args.fee, nonce: senderNonce }); + const messageHash = encodeSendMessage( + sender.address, + args.to, + BigInt(args.fee.toString()), + 0n, + BigInt(messageNonce), + String(args.calldata), + ); + + console.log(`Sent message with messageHash=${messageHash}. ${logString}`); + return await tx.wait(); +}; + +const sendMessages = async (deploymentEnv: DeploymentEnv, sender: Wallet, testScenarios: TestScenario[]) => { + const nextSenderNonce = await sender.getNonce(); + const nextMessageCounter = await getMessageCounter(deploymentEnv, sender); + + const sendMessagePromises: Promise[] = testScenarios.map((s, i) => { + const functionArgs: SendMessageArgs = { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + to: sender.address, + fee: s.fee, + calldata: s.calldata, + }; + return sendMessage( + deploymentEnv, + sender, + functionArgs, + nextMessageCounter + BigInt(i), + nextSenderNonce + i, + s.logString, + ); + }); + await Promise.all(sendMessagePromises); +}; + +const getMessageCounter = async (deploymentEnv: DeploymentEnv, signer: Wallet) => { + const lineaRollup = LineaRollup__factory.connect(L1_MESSAGE_SERVICE_ADDRESS[deploymentEnv], signer) as LineaRollup; + return lineaRollup.nextMessageNumber(); +}; + +// MAIN SCRIPT + +const main = async (args: typeof argv) => { + const l1Provider = new JsonRpcProvider(args.rpcUrl); + const l1Signer = new Wallet(args.privKey, l1Provider); + await sendMessages(args.deploymentEnv as DeploymentEnv, l1Signer, testScenarios); +}; + +main(argv) + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/postman/scripts/sendMessageOnL1.ts b/postman/scripts/sendMessageOnL1.ts index 1f198642..4fb0d775 100644 --- a/postman/scripts/sendMessageOnL1.ts +++ b/postman/scripts/sendMessageOnL1.ts @@ -165,7 +165,7 @@ const main = async (args: typeof argv) => { const messageHashesToAnchor: string[] = []; for (let i = startCounter; i < nextMessageCounter; i++) { - const messageHash = await encodeSendMessage( + const messageHash = encodeSendMessage( l1Signer.address, args.to, BigInt(args.fee.toString()),