From d43455f2c05f0736b5a38982c059334e254ff525 Mon Sep 17 00:00:00 2001 From: John Guilding Date: Mon, 9 Feb 2026 11:55:36 -0300 Subject: [PATCH 1/7] feat: initial railgun send benchmark --- .env.example | 1 + .github/workflows/test.yml | 38 ++++++++++ .gitignore | 141 ++----------------------------------- .gitmodules | 3 + LICENSE | 21 ------ Makefile | 31 ++++++++ foundry.lock | 8 +++ foundry.toml | 8 +++ lib/forge-std | 1 + test/RailgunTransact.t.sol | 44 ++++++++++++ 10 files changed, 138 insertions(+), 158 deletions(-) create mode 100644 .env.example create mode 100644 .github/workflows/test.yml create mode 100644 .gitmodules delete mode 100644 LICENSE create mode 100644 Makefile create mode 100644 foundry.lock create mode 100644 foundry.toml create mode 160000 lib/forge-std create mode 100644 test/RailgunTransact.t.sol diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..cf65c2b --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +ETH_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..b79c8d4 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,38 @@ +name: CI + +permissions: {} + +on: + push: + pull_request: + workflow_dispatch: + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + name: Foundry project + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v5 + with: + persist-credentials: false + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Show Forge version + run: forge --version + + - name: Run Forge fmt + run: forge fmt --check + + - name: Run Forge build + run: forge build --sizes + + - name: Run Forge tests + run: forge test -vvv diff --git a/.gitignore b/.gitignore index 9a5aced..d594ac5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,139 +1,6 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* +# Foundry +/cache +/out -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files +# Environment .env -.env.* -!.env.example - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# Sveltekit cache directory -.svelte-kit/ - -# vitepress build output -**/.vitepress/dist - -# vitepress cache directory -**/.vitepress/cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# Firebase cache directory -.firebase/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v3 -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions - -# Vite logs files -vite.config.js.timestamp-* -vite.config.ts.timestamp-* diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..888d42d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/forge-std"] + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 11b29f4..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 PSE - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4f14039 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +-include .env + +.PHONY: benchmark snapshot snapshot-check cast-gas install + +TX_HASH := 0x105e408f09685adccb1554a325710e90859efcd488fdb2912c8974e73b803cbd + +## Run the gas benchmark +benchmark: + forge test --match-contract RailgunTransactBenchmark -vv + +## Generate .gas-snapshot +snapshot: + forge snapshot --match-contract RailgunTransactBenchmark + +## Check gas snapshot for regressions +snapshot-check: + forge snapshot --match-contract RailgunTransactBenchmark --check + +## Compare against real tx using cast +cast-gas: + @echo "--- Real transaction ---" + @cast tx $(TX_HASH) --rpc-url $(ETH_RPC_URL) --json \ + | jq '{hash: .hash, gasUsed: .gas, blockNumber: .blockNumber}' + @echo "" + @echo "--- Receipt gas ---" + @cast receipt $(TX_HASH) --rpc-url $(ETH_RPC_URL) --json \ + | jq '{gasUsed: .gasUsed, effectiveGasPrice: .effectiveGasPrice, status: .status}' + +## Install dependencies +install: + forge install diff --git a/foundry.lock b/foundry.lock new file mode 100644 index 0000000..d0c0159 --- /dev/null +++ b/foundry.lock @@ -0,0 +1,8 @@ +{ + "lib/forge-std": { + "tag": { + "name": "v1.14.0", + "rev": "1801b0541f4fda118a10798fd3486bb7051c5dd6" + } + } +} \ No newline at end of file diff --git a/foundry.toml b/foundry.toml new file mode 100644 index 0000000..f7412d2 --- /dev/null +++ b/foundry.toml @@ -0,0 +1,8 @@ +[profile.default] +src = "src" +out = "out" +libs = ["lib"] +solc = "0.8.28" + +[rpc_endpoints] +mainnet = "${ETH_RPC_URL}" diff --git a/lib/forge-std b/lib/forge-std new file mode 160000 index 0000000..1801b05 --- /dev/null +++ b/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 1801b0541f4fda118a10798fd3486bb7051c5dd6 diff --git a/test/RailgunTransact.t.sol b/test/RailgunTransact.t.sol new file mode 100644 index 0000000..5006022 --- /dev/null +++ b/test/RailgunTransact.t.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import {Test, console} from "forge-std/Test.sol"; + +/// @notice Gas benchmark for Railgun transact() by replaying a real mainnet tx. +/// TX: 0x105e408f09685adccb1554a325710e90859efcd488fdb2912c8974e73b803cbd +/// Block: 24419683 | Gas used: 1,158,529 +contract RailgunTransactBenchmark is Test { + address constant RELAY_PROXY = 0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9; + address constant SENDER = 0x0D0Efc24db8fe005e24271c6F823CAC22B0641D8; + uint256 constant FORK_BLOCK = 24_419_682; + uint256 constant REAL_GAS = 1_158_529; + uint256 constant TX_GAS_PRICE = 157_243_696; // wei, from the original tx + + // Calldata from: cast tx 0x105e408f09685adccb1554a325710e90859efcd488fdb2912c8974e73b803cbd input --rpc-url $ETH_RPC_URL + bytes constant TX_CALLDATA = hex"d8ae136a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020015725cd8a15be4bf1f7837e7b8c2025d7ca4dbbbdb2f5fa665114e8c6c4c5a11f6fcfa3b23484c94e39f5b9634f30b442537703120465cbea8b4d4da71586b3022de54da17e30e78420c0cc02b0b38dd955562d36e77bbf80b3f7d945f200620937ada831923756d078a862c16c4b8c177952f4e8a588405f1a8b14f8c6f96f1d796199025622d2b6a16ea9d61db03fbe347c51af8e3d7a5fcb7b10fd713f6a1931d5ef9ae87beec74b1f6e68dc41c274f7074954504e7ae61a6b88327fac1e20bf9f3b7488bca5676eff605108792285b958167f49b2507a5183be926d14f721f070faf2042032eaf837092361dab0ec3da2c12979f05ea3991617c1b326e729cee84a6ded1b1a70e3aecc4c98cc7c409e1fe4ae00546139409b08bb8aaede0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000052ccd390416d0c68a57ebf2b48112f71a8083bdd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076902dd1000000000000000000000000000000000000000000000000000000000000000011859b778ec78a2eb608f2ec51a3c5fe8e9bab7a5f19a21044966227b2de12c6f00000000000000000000000000000000000000000000000000000000000000032ff10322d6b36b7b4f0062515c568c00f919a7fc6fbce0e958ba05fa44c73e802530747fc11a38e51bf951fc9cb6aa2bfd29bd0a9939192a03e1f996520f4b221ae2ff2f4d3e1dcb52b127193bc2806c7bc7c949936867e121557b1ce6eb7584000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000094797ac000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c04f01dc2f8cd4f194d37dc3e81c4c50ed9856e4661d51a8cca19dc1c5f968b559026c971af7058f3ce0d8e5c780738ef9199bd6985a911380ac07f96f8be3c579c05d076bdfb5bd2d9723d9a75ac98032a0587551f91caa2482fc8578260a83235516c564e7f32556ee2fb8bf74d21412cc637f4e1ea34143f29dbf46207c44c53bd01f88b170da516e2797b923d13f809713d79666de845bb22e7275a39c4966ae3daf0c538abb6d93da3f0198b3fb1b5bf29df2911fc5cb2e53b23b29ac375900000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000003e2ba4d2403f37a3c5a029128945391232dc324c89390f1270688961ab6021b8de6fc2435172ba598d13c2eb2dc867f34073ac5d703ced936103f062479267000000000000000000000000000000000000000000000000000000000000000000008739eda54b121b727f3692b482a471bf9b7e8832b9cc4db9f21e8642afe946b49b911f2d28388f225d222d55b7e124d872e9ce22eca707ae07bb863df524f074d1b06bd6aad30e79899071bcd3353065d3fcd14bbcc42313e24a193e2f7fa70894163ca9bff74ce0f3594f7906d0fd181628ca2ea737d2dde24627087a9eee91bd722e2a55d4d9ddc9dd4925f3d1f1664601fabcd2acb94e62e979e6620c2397bd722e2a55d4d9ddc9dd4925f3d1f1664601fabcd2acb94e62e979e6620c239700000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000003e12c1bddb767444fc8a477364ce058394b991f989ca27c6895fd7d7290af50f92f6bb3d5e8c5dbd4e6fdfd50cff17b554670d548f8faa6dfcae95bb212f6100000000000000000000000000000000000000000000000000000000000000000000"; + + function setUp() public { + vm.createSelectFork(vm.envString("ETH_RPC_URL"), FORK_BLOCK); + } + + function test_railgun_transact_gas() public { + assertEq(block.number, FORK_BLOCK, "wrong fork block"); + + vm.txGasPrice(TX_GAS_PRICE); + vm.prank(SENDER); + uint256 gasBefore = gasleft(); + (bool ok,) = RELAY_PROXY.call(TX_CALLDATA); + uint256 gasUsed = gasBefore - gasleft(); + assertTrue(ok, "transact() reverted"); + + console.log("Railgun transact() gas (measured):", gasUsed); + console.log("Railgun transact() gas (real tx): ", REAL_GAS); + console.log("Delta: ", _absDiff(gasUsed, REAL_GAS)); + + // Fork gas may differ slightly from mainnet; allow 5% tolerance + assertApproxEqAbs(gasUsed, REAL_GAS, REAL_GAS * 5 / 100, "gas >5% off from real tx"); + } + + function _absDiff(uint256 a, uint256 b) private pure returns (uint256) { + return a > b ? a - b : b - a; + } +} From ac755d553901a3b1e8d094fa5f9d31cc3bf7f53a Mon Sep 17 00:00:00 2001 From: John Guilding Date: Mon, 9 Feb 2026 16:33:19 -0300 Subject: [PATCH 2/7] feat: construct tx and use snapshot - Pull structs from railgun contracts - Partly construct calldata - Do not compare against real tx in test --- .gitignore | 1 + .gitmodules | 3 + Makefile | 31 ----- README.md | 5 +- foundry.toml | 1 + snapshots/RailgunSendBenchmark.json | 3 + test/RailgunTransact.t.sol | 184 ++++++++++++++++++++++++---- 7 files changed, 170 insertions(+), 58 deletions(-) delete mode 100644 Makefile create mode 100644 snapshots/RailgunSendBenchmark.json diff --git a/.gitignore b/.gitignore index d594ac5..0697f88 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ # Environment .env +.claude \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 888d42d..44b51a4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std +[submodule "lib/contract"] + path = lib/contract + url = https://github.com/Railgun-Privacy/contract diff --git a/Makefile b/Makefile deleted file mode 100644 index 4f14039..0000000 --- a/Makefile +++ /dev/null @@ -1,31 +0,0 @@ --include .env - -.PHONY: benchmark snapshot snapshot-check cast-gas install - -TX_HASH := 0x105e408f09685adccb1554a325710e90859efcd488fdb2912c8974e73b803cbd - -## Run the gas benchmark -benchmark: - forge test --match-contract RailgunTransactBenchmark -vv - -## Generate .gas-snapshot -snapshot: - forge snapshot --match-contract RailgunTransactBenchmark - -## Check gas snapshot for regressions -snapshot-check: - forge snapshot --match-contract RailgunTransactBenchmark --check - -## Compare against real tx using cast -cast-gas: - @echo "--- Real transaction ---" - @cast tx $(TX_HASH) --rpc-url $(ETH_RPC_URL) --json \ - | jq '{hash: .hash, gasUsed: .gas, blockNumber: .blockNumber}' - @echo "" - @echo "--- Receipt gas ---" - @cast receipt $(TX_HASH) --rpc-url $(ETH_RPC_URL) --json \ - | jq '{gasUsed: .gasUsed, effectiveGasPrice: .effectiveGasPrice, status: .status}' - -## Install dependencies -install: - forge install diff --git a/README.md b/README.md index 5dee3df..a9b8707 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # private-transfers-benchmarks -A set of adapters to run structured benchmarks for private transfers protocols + +## Test + +`forge test -vv` diff --git a/foundry.toml b/foundry.toml index f7412d2..e788c9c 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,6 +3,7 @@ src = "src" out = "out" libs = ["lib"] solc = "0.8.28" +remappings = ["@railgun/=lib/contract/contracts/"] [rpc_endpoints] mainnet = "${ETH_RPC_URL}" diff --git a/snapshots/RailgunSendBenchmark.json b/snapshots/RailgunSendBenchmark.json new file mode 100644 index 0000000..c323616 --- /dev/null +++ b/snapshots/RailgunSendBenchmark.json @@ -0,0 +1,3 @@ +{ + "railgun_send": "1132563" +} \ No newline at end of file diff --git a/test/RailgunTransact.t.sol b/test/RailgunTransact.t.sol index 5006022..ff65137 100644 --- a/test/RailgunTransact.t.sol +++ b/test/RailgunTransact.t.sol @@ -2,43 +2,175 @@ pragma solidity ^0.8.28; import {Test, console} from "forge-std/Test.sol"; +import { + Transaction, + SnarkProof, + G1Point, + G2Point, + BoundParams, + CommitmentCiphertext, + CommitmentPreimage, + TokenData, + TokenType, + UnshieldType +} from "@railgun/logic/Globals.sol"; + +interface IRailgunRelay { + function transact(Transaction[] calldata transactions) external; +} + +// Reference tx: 0x105e408f09685adccb1554a325710e90859efcd488fdb2912c8974e73b803cbd +// Gas cost: cast receipt 0x105e408f09685adccb1554a325710e90859efcd488fdb2912c8974e73b803cbd gasUsed --rpc-url $ETH_RPC_URL +contract RailgunSendBenchmark is Test { + IRailgunRelay constant RELAY = + IRailgunRelay(0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9); -/// @notice Gas benchmark for Railgun transact() by replaying a real mainnet tx. -/// TX: 0x105e408f09685adccb1554a325710e90859efcd488fdb2912c8974e73b803cbd -/// Block: 24419683 | Gas used: 1,158,529 -contract RailgunTransactBenchmark is Test { - address constant RELAY_PROXY = 0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9; address constant SENDER = 0x0D0Efc24db8fe005e24271c6F823CAC22B0641D8; + + // TODO: fork at latest once we have proof generation logic. We need + // to fork before the reference tx so nullifiers are unspent uint256 constant FORK_BLOCK = 24_419_682; - uint256 constant REAL_GAS = 1_158_529; - uint256 constant TX_GAS_PRICE = 157_243_696; // wei, from the original tx - // Calldata from: cast tx 0x105e408f09685adccb1554a325710e90859efcd488fdb2912c8974e73b803cbd input --rpc-url $ETH_RPC_URL - bytes constant TX_CALLDATA = hex"d8ae136a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020015725cd8a15be4bf1f7837e7b8c2025d7ca4dbbbdb2f5fa665114e8c6c4c5a11f6fcfa3b23484c94e39f5b9634f30b442537703120465cbea8b4d4da71586b3022de54da17e30e78420c0cc02b0b38dd955562d36e77bbf80b3f7d945f200620937ada831923756d078a862c16c4b8c177952f4e8a588405f1a8b14f8c6f96f1d796199025622d2b6a16ea9d61db03fbe347c51af8e3d7a5fcb7b10fd713f6a1931d5ef9ae87beec74b1f6e68dc41c274f7074954504e7ae61a6b88327fac1e20bf9f3b7488bca5676eff605108792285b958167f49b2507a5183be926d14f721f070faf2042032eaf837092361dab0ec3da2c12979f05ea3991617c1b326e729cee84a6ded1b1a70e3aecc4c98cc7c409e1fe4ae00546139409b08bb8aaede0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000052ccd390416d0c68a57ebf2b48112f71a8083bdd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076902dd1000000000000000000000000000000000000000000000000000000000000000011859b778ec78a2eb608f2ec51a3c5fe8e9bab7a5f19a21044966227b2de12c6f00000000000000000000000000000000000000000000000000000000000000032ff10322d6b36b7b4f0062515c568c00f919a7fc6fbce0e958ba05fa44c73e802530747fc11a38e51bf951fc9cb6aa2bfd29bd0a9939192a03e1f996520f4b221ae2ff2f4d3e1dcb52b127193bc2806c7bc7c949936867e121557b1ce6eb7584000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000094797ac000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c04f01dc2f8cd4f194d37dc3e81c4c50ed9856e4661d51a8cca19dc1c5f968b559026c971af7058f3ce0d8e5c780738ef9199bd6985a911380ac07f96f8be3c579c05d076bdfb5bd2d9723d9a75ac98032a0587551f91caa2482fc8578260a83235516c564e7f32556ee2fb8bf74d21412cc637f4e1ea34143f29dbf46207c44c53bd01f88b170da516e2797b923d13f809713d79666de845bb22e7275a39c4966ae3daf0c538abb6d93da3f0198b3fb1b5bf29df2911fc5cb2e53b23b29ac375900000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000003e2ba4d2403f37a3c5a029128945391232dc324c89390f1270688961ab6021b8de6fc2435172ba598d13c2eb2dc867f34073ac5d703ced936103f062479267000000000000000000000000000000000000000000000000000000000000000000008739eda54b121b727f3692b482a471bf9b7e8832b9cc4db9f21e8642afe946b49b911f2d28388f225d222d55b7e124d872e9ce22eca707ae07bb863df524f074d1b06bd6aad30e79899071bcd3353065d3fcd14bbcc42313e24a193e2f7fa70894163ca9bff74ce0f3594f7906d0fd181628ca2ea737d2dde24627087a9eee91bd722e2a55d4d9ddc9dd4925f3d1f1664601fabcd2acb94e62e979e6620c2397bd722e2a55d4d9ddc9dd4925f3d1f1664601fabcd2acb94e62e979e6620c239700000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000003e12c1bddb767444fc8a477364ce058394b991f989ca27c6895fd7d7290af50f92f6bb3d5e8c5dbd4e6fdfd50cff17b554670d548f8faa6dfcae95bb212f6100000000000000000000000000000000000000000000000000000000000000000000"; + // The reference tx's gas price + uint256 constant TX_GAS_PRICE = 157_243_696; - function setUp() public { + function test_send() public { vm.createSelectFork(vm.envString("ETH_RPC_URL"), FORK_BLOCK); - } + vm.txGasPrice(TX_GAS_PRICE); - function test_railgun_transact_gas() public { - assertEq(block.number, FORK_BLOCK, "wrong fork block"); + Transaction[] memory txs = new Transaction[](1); + txs[0] = _buildTransaction(); - vm.txGasPrice(TX_GAS_PRICE); vm.prank(SENDER); - uint256 gasBefore = gasleft(); - (bool ok,) = RELAY_PROXY.call(TX_CALLDATA); - uint256 gasUsed = gasBefore - gasleft(); - assertTrue(ok, "transact() reverted"); + vm.startSnapshotGas("railgun_send"); + RELAY.transact(txs); + uint256 gasUsed = vm.stopSnapshotGas("railgun_send"); - console.log("Railgun transact() gas (measured):", gasUsed); - console.log("Railgun transact() gas (real tx): ", REAL_GAS); - console.log("Delta: ", _absDiff(gasUsed, REAL_GAS)); - - // Fork gas may differ slightly from mainnet; allow 5% tolerance - assertApproxEqAbs(gasUsed, REAL_GAS, REAL_GAS * 5 / 100, "gas >5% off from real tx"); + console.log("scenario: railgun_send"); + console.log("forkBlock:", block.number); + console.log("gasUsed: ", gasUsed); } - function _absDiff(uint256 a, uint256 b) private pure returns (uint256) { - return a > b ? a - b : b - a; + function _buildTransaction() internal pure returns (Transaction memory) { + SnarkProof memory proof = SnarkProof({ + a: G1Point({ + x: 0x015725cd8a15be4bf1f7837e7b8c2025d7ca4dbbbdb2f5fa665114e8c6c4c5a1, + y: 0x1f6fcfa3b23484c94e39f5b9634f30b442537703120465cbea8b4d4da71586b3 + }), + b: G2Point({ + x: [ + uint256( + 0x022de54da17e30e78420c0cc02b0b38dd955562d36e77bbf80b3f7d945f20062 + ), + uint256( + 0x0937ada831923756d078a862c16c4b8c177952f4e8a588405f1a8b14f8c6f96f + ) + ], + y: [ + uint256( + 0x1d796199025622d2b6a16ea9d61db03fbe347c51af8e3d7a5fcb7b10fd713f6a + ), + uint256( + 0x1931d5ef9ae87beec74b1f6e68dc41c274f7074954504e7ae61a6b88327fac1e + ) + ] + }), + c: G1Point({ + x: 0x20bf9f3b7488bca5676eff605108792285b958167f49b2507a5183be926d14f7, + y: 0x21f070faf2042032eaf837092361dab0ec3da2c12979f05ea3991617c1b326e7 + }) + }); + + bytes32[] memory nullifiers = new bytes32[](1); + nullifiers[ + 0 + ] = 0x1859b778ec78a2eb608f2ec51a3c5fe8e9bab7a5f19a21044966227b2de12c6f; + + bytes32[] memory commitments = new bytes32[](3); + commitments[ + 0 + ] = 0x2ff10322d6b36b7b4f0062515c568c00f919a7fc6fbce0e958ba05fa44c73e80; + commitments[ + 1 + ] = 0x2530747fc11a38e51bf951fc9cb6aa2bfd29bd0a9939192a03e1f996520f4b22; + commitments[ + 2 + ] = 0x1ae2ff2f4d3e1dcb52b127193bc2806c7bc7c949936867e121557b1ce6eb7584; + + CommitmentCiphertext[] memory ciphertexts = new CommitmentCiphertext[]( + 2 + ); + ciphertexts[0] = CommitmentCiphertext({ + ciphertext: [ + bytes32( + 0x4f01dc2f8cd4f194d37dc3e81c4c50ed9856e4661d51a8cca19dc1c5f968b559 + ), + bytes32( + 0x026c971af7058f3ce0d8e5c780738ef9199bd6985a911380ac07f96f8be3c579 + ), + bytes32( + 0xc05d076bdfb5bd2d9723d9a75ac98032a0587551f91caa2482fc8578260a8323 + ), + bytes32( + 0x5516c564e7f32556ee2fb8bf74d21412cc637f4e1ea34143f29dbf46207c44c5 + ) + ], + blindedSenderViewingKey: 0x3bd01f88b170da516e2797b923d13f809713d79666de845bb22e7275a39c4966, + blindedReceiverViewingKey: 0xae3daf0c538abb6d93da3f0198b3fb1b5bf29df2911fc5cb2e53b23b29ac3759, + annotationData: hex"2ba4d2403f37a3c5a029128945391232dc324c89390f1270688961ab6021b8de6fc2435172ba598d13c2eb2dc867f34073ac5d703ced936103f062479267", + memo: hex"" + }); + ciphertexts[1] = CommitmentCiphertext({ + ciphertext: [ + bytes32( + 0x8739eda54b121b727f3692b482a471bf9b7e8832b9cc4db9f21e8642afe946b4 + ), + bytes32( + 0x9b911f2d28388f225d222d55b7e124d872e9ce22eca707ae07bb863df524f074 + ), + bytes32( + 0xd1b06bd6aad30e79899071bcd3353065d3fcd14bbcc42313e24a193e2f7fa708 + ), + bytes32( + 0x94163ca9bff74ce0f3594f7906d0fd181628ca2ea737d2dde24627087a9eee91 + ) + ], + blindedSenderViewingKey: 0xbd722e2a55d4d9ddc9dd4925f3d1f1664601fabcd2acb94e62e979e6620c2397, + blindedReceiverViewingKey: 0xbd722e2a55d4d9ddc9dd4925f3d1f1664601fabcd2acb94e62e979e6620c2397, + annotationData: hex"12c1bddb767444fc8a477364ce058394b991f989ca27c6895fd7d7290af50f92f6bb3d5e8c5dbd4e6fdfd50cff17b554670d548f8faa6dfcae95bb212f61", + memo: hex"" + }); + + BoundParams memory boundParams = BoundParams({ + treeNumber: 2, + minGasPrice: 155_686_828, + unshield: UnshieldType.NORMAL, + chainID: 1, + adaptContract: address(0), + adaptParams: bytes32(0), + commitmentCiphertext: ciphertexts + }); + + CommitmentPreimage memory unshieldPreimage = CommitmentPreimage({ + npk: bytes32( + uint256(uint160(0x52CCD390416d0C68A57EBF2b48112F71A8083bDD)) + ), + token: TokenData({ + tokenType: TokenType.ERC20, + tokenAddress: 0xdAC17F958D2ee523a2206206994597C13D831ec7, + tokenSubID: 0 + }), + value: 31_826_566_416 + }); + + return + Transaction({ + proof: proof, + merkleRoot: 0x29cee84a6ded1b1a70e3aecc4c98cc7c409e1fe4ae00546139409b08bb8aaede, + nullifiers: nullifiers, + commitments: commitments, + boundParams: boundParams, + unshieldPreimage: unshieldPreimage + }); } } From e07a8876f95b7da4a693f4cc7715dbbad6742980 Mon Sep 17 00:00:00 2001 From: John Guilding Date: Mon, 9 Feb 2026 16:46:18 -0300 Subject: [PATCH 3/7] fix: CI - fmt - add CI secret --- .github/workflows/test.yml | 2 + .vscode/settings.json | 7 +++ test/RailgunTransact.t.sol | 101 ++++++++++++------------------------- 3 files changed, 40 insertions(+), 70 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b79c8d4..0b67d49 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,3 +36,5 @@ jobs: - name: Run Forge tests run: forge test -vvv + env: + ETH_RPC_URL: ${{ secrets.ETH_RPC_URL }} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a6deaf9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "[solidity]": { + "editor.defaultFormatter": "JuanBlanco.solidity", + "editor.formatOnSave": true + }, + "solidity.formatter": "forge" +} diff --git a/test/RailgunTransact.t.sol b/test/RailgunTransact.t.sol index ff65137..a8019a1 100644 --- a/test/RailgunTransact.t.sol +++ b/test/RailgunTransact.t.sol @@ -22,8 +22,7 @@ interface IRailgunRelay { // Reference tx: 0x105e408f09685adccb1554a325710e90859efcd488fdb2912c8974e73b803cbd // Gas cost: cast receipt 0x105e408f09685adccb1554a325710e90859efcd488fdb2912c8974e73b803cbd gasUsed --rpc-url $ETH_RPC_URL contract RailgunSendBenchmark is Test { - IRailgunRelay constant RELAY = - IRailgunRelay(0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9); + IRailgunRelay constant RELAY = IRailgunRelay(0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9); address constant SENDER = 0x0D0Efc24db8fe005e24271c6F823CAC22B0641D8; @@ -35,7 +34,8 @@ contract RailgunSendBenchmark is Test { uint256 constant TX_GAS_PRICE = 157_243_696; function test_send() public { - vm.createSelectFork(vm.envString("ETH_RPC_URL"), FORK_BLOCK); + string memory rpcUrl = vm.envOr("ETH_RPC_URL", string("https://eth.llamarpc.com")); + vm.createSelectFork(rpcUrl, FORK_BLOCK); vm.txGasPrice(TX_GAS_PRICE); Transaction[] memory txs = new Transaction[](1); @@ -59,20 +59,12 @@ contract RailgunSendBenchmark is Test { }), b: G2Point({ x: [ - uint256( - 0x022de54da17e30e78420c0cc02b0b38dd955562d36e77bbf80b3f7d945f20062 - ), - uint256( - 0x0937ada831923756d078a862c16c4b8c177952f4e8a588405f1a8b14f8c6f96f - ) + uint256(0x022de54da17e30e78420c0cc02b0b38dd955562d36e77bbf80b3f7d945f20062), + uint256(0x0937ada831923756d078a862c16c4b8c177952f4e8a588405f1a8b14f8c6f96f) ], y: [ - uint256( - 0x1d796199025622d2b6a16ea9d61db03fbe347c51af8e3d7a5fcb7b10fd713f6a - ), - uint256( - 0x1931d5ef9ae87beec74b1f6e68dc41c274f7074954504e7ae61a6b88327fac1e - ) + uint256(0x1d796199025622d2b6a16ea9d61db03fbe347c51af8e3d7a5fcb7b10fd713f6a), + uint256(0x1931d5ef9ae87beec74b1f6e68dc41c274f7074954504e7ae61a6b88327fac1e) ] }), c: G1Point({ @@ -82,38 +74,20 @@ contract RailgunSendBenchmark is Test { }); bytes32[] memory nullifiers = new bytes32[](1); - nullifiers[ - 0 - ] = 0x1859b778ec78a2eb608f2ec51a3c5fe8e9bab7a5f19a21044966227b2de12c6f; + nullifiers[0] = 0x1859b778ec78a2eb608f2ec51a3c5fe8e9bab7a5f19a21044966227b2de12c6f; bytes32[] memory commitments = new bytes32[](3); - commitments[ - 0 - ] = 0x2ff10322d6b36b7b4f0062515c568c00f919a7fc6fbce0e958ba05fa44c73e80; - commitments[ - 1 - ] = 0x2530747fc11a38e51bf951fc9cb6aa2bfd29bd0a9939192a03e1f996520f4b22; - commitments[ - 2 - ] = 0x1ae2ff2f4d3e1dcb52b127193bc2806c7bc7c949936867e121557b1ce6eb7584; - - CommitmentCiphertext[] memory ciphertexts = new CommitmentCiphertext[]( - 2 - ); + commitments[0] = 0x2ff10322d6b36b7b4f0062515c568c00f919a7fc6fbce0e958ba05fa44c73e80; + commitments[1] = 0x2530747fc11a38e51bf951fc9cb6aa2bfd29bd0a9939192a03e1f996520f4b22; + commitments[2] = 0x1ae2ff2f4d3e1dcb52b127193bc2806c7bc7c949936867e121557b1ce6eb7584; + + CommitmentCiphertext[] memory ciphertexts = new CommitmentCiphertext[](2); ciphertexts[0] = CommitmentCiphertext({ ciphertext: [ - bytes32( - 0x4f01dc2f8cd4f194d37dc3e81c4c50ed9856e4661d51a8cca19dc1c5f968b559 - ), - bytes32( - 0x026c971af7058f3ce0d8e5c780738ef9199bd6985a911380ac07f96f8be3c579 - ), - bytes32( - 0xc05d076bdfb5bd2d9723d9a75ac98032a0587551f91caa2482fc8578260a8323 - ), - bytes32( - 0x5516c564e7f32556ee2fb8bf74d21412cc637f4e1ea34143f29dbf46207c44c5 - ) + bytes32(0x4f01dc2f8cd4f194d37dc3e81c4c50ed9856e4661d51a8cca19dc1c5f968b559), + bytes32(0x026c971af7058f3ce0d8e5c780738ef9199bd6985a911380ac07f96f8be3c579), + bytes32(0xc05d076bdfb5bd2d9723d9a75ac98032a0587551f91caa2482fc8578260a8323), + bytes32(0x5516c564e7f32556ee2fb8bf74d21412cc637f4e1ea34143f29dbf46207c44c5) ], blindedSenderViewingKey: 0x3bd01f88b170da516e2797b923d13f809713d79666de845bb22e7275a39c4966, blindedReceiverViewingKey: 0xae3daf0c538abb6d93da3f0198b3fb1b5bf29df2911fc5cb2e53b23b29ac3759, @@ -122,18 +96,10 @@ contract RailgunSendBenchmark is Test { }); ciphertexts[1] = CommitmentCiphertext({ ciphertext: [ - bytes32( - 0x8739eda54b121b727f3692b482a471bf9b7e8832b9cc4db9f21e8642afe946b4 - ), - bytes32( - 0x9b911f2d28388f225d222d55b7e124d872e9ce22eca707ae07bb863df524f074 - ), - bytes32( - 0xd1b06bd6aad30e79899071bcd3353065d3fcd14bbcc42313e24a193e2f7fa708 - ), - bytes32( - 0x94163ca9bff74ce0f3594f7906d0fd181628ca2ea737d2dde24627087a9eee91 - ) + bytes32(0x8739eda54b121b727f3692b482a471bf9b7e8832b9cc4db9f21e8642afe946b4), + bytes32(0x9b911f2d28388f225d222d55b7e124d872e9ce22eca707ae07bb863df524f074), + bytes32(0xd1b06bd6aad30e79899071bcd3353065d3fcd14bbcc42313e24a193e2f7fa708), + bytes32(0x94163ca9bff74ce0f3594f7906d0fd181628ca2ea737d2dde24627087a9eee91) ], blindedSenderViewingKey: 0xbd722e2a55d4d9ddc9dd4925f3d1f1664601fabcd2acb94e62e979e6620c2397, blindedReceiverViewingKey: 0xbd722e2a55d4d9ddc9dd4925f3d1f1664601fabcd2acb94e62e979e6620c2397, @@ -152,25 +118,20 @@ contract RailgunSendBenchmark is Test { }); CommitmentPreimage memory unshieldPreimage = CommitmentPreimage({ - npk: bytes32( - uint256(uint160(0x52CCD390416d0C68A57EBF2b48112F71A8083bDD)) - ), + npk: bytes32(uint256(uint160(0x52CCD390416d0C68A57EBF2b48112F71A8083bDD))), token: TokenData({ - tokenType: TokenType.ERC20, - tokenAddress: 0xdAC17F958D2ee523a2206206994597C13D831ec7, - tokenSubID: 0 + tokenType: TokenType.ERC20, tokenAddress: 0xdAC17F958D2ee523a2206206994597C13D831ec7, tokenSubID: 0 }), value: 31_826_566_416 }); - return - Transaction({ - proof: proof, - merkleRoot: 0x29cee84a6ded1b1a70e3aecc4c98cc7c409e1fe4ae00546139409b08bb8aaede, - nullifiers: nullifiers, - commitments: commitments, - boundParams: boundParams, - unshieldPreimage: unshieldPreimage - }); + return Transaction({ + proof: proof, + merkleRoot: 0x29cee84a6ded1b1a70e3aecc4c98cc7c409e1fe4ae00546139409b08bb8aaede, + nullifiers: nullifiers, + commitments: commitments, + boundParams: boundParams, + unshieldPreimage: unshieldPreimage + }); } } From 33af26bd23c04d451872d4dd369ae543bbfb1b06 Mon Sep 17 00:00:00 2001 From: John Guilding Date: Mon, 9 Feb 2026 16:49:35 -0300 Subject: [PATCH 4/7] fix: correctly add submodule --- lib/contract | 1 + 1 file changed, 1 insertion(+) create mode 160000 lib/contract diff --git a/lib/contract b/lib/contract new file mode 160000 index 0000000..9ec0912 --- /dev/null +++ b/lib/contract @@ -0,0 +1 @@ +Subproject commit 9ec09123eb140fdaaf3a5ff1f29d634c353630cd From 389781c60533d107cb5131ef578810dddb16cee1 Mon Sep 17 00:00:00 2001 From: John Guilding Date: Mon, 9 Feb 2026 19:05:45 -0300 Subject: [PATCH 5/7] feat: use actual private transfer --- snapshots/RailgunSendBenchmark.json | 2 +- test/RailgunTransact.t.sol | 84 ++++++++++++++--------------- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/snapshots/RailgunSendBenchmark.json b/snapshots/RailgunSendBenchmark.json index c323616..202549a 100644 --- a/snapshots/RailgunSendBenchmark.json +++ b/snapshots/RailgunSendBenchmark.json @@ -1,3 +1,3 @@ { - "railgun_send": "1132563" + "railgun_send": "1024078" } \ No newline at end of file diff --git a/test/RailgunTransact.t.sol b/test/RailgunTransact.t.sol index a8019a1..e125647 100644 --- a/test/RailgunTransact.t.sol +++ b/test/RailgunTransact.t.sol @@ -19,19 +19,19 @@ interface IRailgunRelay { function transact(Transaction[] calldata transactions) external; } -// Reference tx: 0x105e408f09685adccb1554a325710e90859efcd488fdb2912c8974e73b803cbd -// Gas cost: cast receipt 0x105e408f09685adccb1554a325710e90859efcd488fdb2912c8974e73b803cbd gasUsed --rpc-url $ETH_RPC_URL +// Reference tx: 0x9691b06aeb81ae709ad478942a5307c5e5cc4597074f5b60e11b2033c1584580 +// Gas cost: cast receipt 0x9691b06aeb81ae709ad478942a5307c5e5cc4597074f5b60e11b2033c1584580 gasUsed --rpc-url $ETH_RPC_URL contract RailgunSendBenchmark is Test { IRailgunRelay constant RELAY = IRailgunRelay(0xFA7093CDD9EE6932B4eb2c9e1cde7CE00B1FA4b9); - address constant SENDER = 0x0D0Efc24db8fe005e24271c6F823CAC22B0641D8; + address constant SENDER = 0x03CbE58799c0EB9AABAB3212886bfcA10A418299; - // TODO: fork at latest once we have proof generation logic. We need - // to fork before the reference tx so nullifiers are unspent - uint256 constant FORK_BLOCK = 24_419_682; + // Fork at block before the reference tx so nullifiers are unspent. + // TODO: fork at latest once we have proof generation logic. + uint256 constant FORK_BLOCK = 24_421_959; // The reference tx's gas price - uint256 constant TX_GAS_PRICE = 157_243_696; + uint256 constant TX_GAS_PRICE = 283_628_746; function test_send() public { string memory rpcUrl = vm.envOr("ETH_RPC_URL", string("https://eth.llamarpc.com")); @@ -54,63 +54,63 @@ contract RailgunSendBenchmark is Test { function _buildTransaction() internal pure returns (Transaction memory) { SnarkProof memory proof = SnarkProof({ a: G1Point({ - x: 0x015725cd8a15be4bf1f7837e7b8c2025d7ca4dbbbdb2f5fa665114e8c6c4c5a1, - y: 0x1f6fcfa3b23484c94e39f5b9634f30b442537703120465cbea8b4d4da71586b3 + x: 0x03d6861e17bf2babb298bb06b69a003f55252b756eab01614acdc89217f5c232, + y: 0x26e0db51c595e77a7041450e8034484976a5ef1509543ba63a3c10f541be3ae0 }), b: G2Point({ x: [ - uint256(0x022de54da17e30e78420c0cc02b0b38dd955562d36e77bbf80b3f7d945f20062), - uint256(0x0937ada831923756d078a862c16c4b8c177952f4e8a588405f1a8b14f8c6f96f) + uint256(0x2b286954d2cc7d4cea7b50450d5c7c072c2a8bd2c76bd8c921ada087d84d26e1), + uint256(0x1091cd885152612e830fb275301648d5f0f0f891a9b0bbd39b3cf390fd907f4c) ], y: [ - uint256(0x1d796199025622d2b6a16ea9d61db03fbe347c51af8e3d7a5fcb7b10fd713f6a), - uint256(0x1931d5ef9ae87beec74b1f6e68dc41c274f7074954504e7ae61a6b88327fac1e) + uint256(0x11dc536a27865e54c3ec085a532814663448a8ff79b20a7824b949574c8bd9fd), + uint256(0x1ac326f30e8798a39f48bc894f1fc94f644ef3b0089bf41eed564ee6e96cff6b) ] }), c: G1Point({ - x: 0x20bf9f3b7488bca5676eff605108792285b958167f49b2507a5183be926d14f7, - y: 0x21f070faf2042032eaf837092361dab0ec3da2c12979f05ea3991617c1b326e7 + x: 0x2fa47504b90d2920e69465871244194d196550355551b9c5b23117e0e31c56b3, + y: 0x1d024b5ac8dd75a6f5f27c34e7c9c4c568bca186ddd6c64c4eeae051a7acf048 }) }); - bytes32[] memory nullifiers = new bytes32[](1); - nullifiers[0] = 0x1859b778ec78a2eb608f2ec51a3c5fe8e9bab7a5f19a21044966227b2de12c6f; + bytes32[] memory nullifiers = new bytes32[](2); + nullifiers[0] = 0x13c9423325c5d638bf183d242aa9f9b864e4b42b749b00a19950d13d10529ef8; + nullifiers[1] = 0x2a7eb0332c12e3fb1920e62ee6bff72c53c9ac036b340f7003ba978a4b497855; - bytes32[] memory commitments = new bytes32[](3); - commitments[0] = 0x2ff10322d6b36b7b4f0062515c568c00f919a7fc6fbce0e958ba05fa44c73e80; - commitments[1] = 0x2530747fc11a38e51bf951fc9cb6aa2bfd29bd0a9939192a03e1f996520f4b22; - commitments[2] = 0x1ae2ff2f4d3e1dcb52b127193bc2806c7bc7c949936867e121557b1ce6eb7584; + bytes32[] memory commitments = new bytes32[](2); + commitments[0] = 0x088699b561e26726c43c482201168a153e623d4dc91c70d5ea15959dbe4aa370; + commitments[1] = 0x06e8dcbb2b237226f4cd2da22acde99d63bd75997a68d89ea660a90ad789d679; CommitmentCiphertext[] memory ciphertexts = new CommitmentCiphertext[](2); ciphertexts[0] = CommitmentCiphertext({ ciphertext: [ - bytes32(0x4f01dc2f8cd4f194d37dc3e81c4c50ed9856e4661d51a8cca19dc1c5f968b559), - bytes32(0x026c971af7058f3ce0d8e5c780738ef9199bd6985a911380ac07f96f8be3c579), - bytes32(0xc05d076bdfb5bd2d9723d9a75ac98032a0587551f91caa2482fc8578260a8323), - bytes32(0x5516c564e7f32556ee2fb8bf74d21412cc637f4e1ea34143f29dbf46207c44c5) + bytes32(0x7d429023249ead0df72b6fbcbc26fa7264033426d5b5934b89ae41e9088def76), + bytes32(0xb4b58e502443c2f79e8891d8c21653dcdc9af33b1af0b2fd662a260450075cbf), + bytes32(0xdc07ad6a7167345f0e798825786d2324f24505cadb6cea1602263dd146febb35), + bytes32(0x83d9085ce23ef4e52372dc68599853274ff383f05d4209cfd62dc10e41192226) ], - blindedSenderViewingKey: 0x3bd01f88b170da516e2797b923d13f809713d79666de845bb22e7275a39c4966, - blindedReceiverViewingKey: 0xae3daf0c538abb6d93da3f0198b3fb1b5bf29df2911fc5cb2e53b23b29ac3759, - annotationData: hex"2ba4d2403f37a3c5a029128945391232dc324c89390f1270688961ab6021b8de6fc2435172ba598d13c2eb2dc867f34073ac5d703ced936103f062479267", + blindedSenderViewingKey: 0x67c7c4f4bf7d695c49508d9341db62f258656cbd3680caa0524f6ceccf8dcfdb, + blindedReceiverViewingKey: 0x70db540142462d9f2e494928c8f473cba28c05a46c279b34c546042ad7e98209, + annotationData: hex"33f172f5005e9a92310ecc740c389523b147fc7e09d0f5df198a7496fae843ad2aaa3dba091c93c8716570c64ce04bcc711cc689c10bec659d28ffb487fa", memo: hex"" }); ciphertexts[1] = CommitmentCiphertext({ ciphertext: [ - bytes32(0x8739eda54b121b727f3692b482a471bf9b7e8832b9cc4db9f21e8642afe946b4), - bytes32(0x9b911f2d28388f225d222d55b7e124d872e9ce22eca707ae07bb863df524f074), - bytes32(0xd1b06bd6aad30e79899071bcd3353065d3fcd14bbcc42313e24a193e2f7fa708), - bytes32(0x94163ca9bff74ce0f3594f7906d0fd181628ca2ea737d2dde24627087a9eee91) + bytes32(0xbbd1240440d6679e22bb11eec05057373e8e1ef31a6ab0a964a4667517ca108e), + bytes32(0x35aaa5137133d43350b5f99a21dc97a793c638f3fc1207c3670cd73712fd6dd5), + bytes32(0x1c81ab00cd19b2d5db398f3140e2d2f2b95f4cf2d0475fc2bedbf3171aaa0654), + bytes32(0x2ac5a7eb3d337aaa488f172eb86c8a5e8eeca5883e38f7824baa9f9d09e39852) ], - blindedSenderViewingKey: 0xbd722e2a55d4d9ddc9dd4925f3d1f1664601fabcd2acb94e62e979e6620c2397, - blindedReceiverViewingKey: 0xbd722e2a55d4d9ddc9dd4925f3d1f1664601fabcd2acb94e62e979e6620c2397, - annotationData: hex"12c1bddb767444fc8a477364ce058394b991f989ca27c6895fd7d7290af50f92f6bb3d5e8c5dbd4e6fdfd50cff17b554670d548f8faa6dfcae95bb212f61", + blindedSenderViewingKey: 0xc422f463519d3ec701d9d763b477d580070f2d5d76feb3a55d6634de3064c8ba, + blindedReceiverViewingKey: 0x94e9d2e6d6507c9446062d750396c37d901f3a7d65517a74f66adecc11514539, + annotationData: hex"a5d946a5411a0f3c697ae08bf3f44f64b27f52be7491faaa7797d0ae9c88e193c5f5f5d180ceb044f9cc62bc9d8c46dc50d803f98237d304c9d3604f47a1", memo: hex"" }); BoundParams memory boundParams = BoundParams({ treeNumber: 2, - minGasPrice: 155_686_828, - unshield: UnshieldType.NORMAL, + minGasPrice: 283_628_746, + unshield: UnshieldType.NONE, chainID: 1, adaptContract: address(0), adaptParams: bytes32(0), @@ -118,16 +118,14 @@ contract RailgunSendBenchmark is Test { }); CommitmentPreimage memory unshieldPreimage = CommitmentPreimage({ - npk: bytes32(uint256(uint160(0x52CCD390416d0C68A57EBF2b48112F71A8083bDD))), - token: TokenData({ - tokenType: TokenType.ERC20, tokenAddress: 0xdAC17F958D2ee523a2206206994597C13D831ec7, tokenSubID: 0 - }), - value: 31_826_566_416 + npk: bytes32(0), + token: TokenData({tokenType: TokenType.ERC20, tokenAddress: address(0), tokenSubID: 0}), + value: 0 }); return Transaction({ proof: proof, - merkleRoot: 0x29cee84a6ded1b1a70e3aecc4c98cc7c409e1fe4ae00546139409b08bb8aaede, + merkleRoot: 0x03309f5fdc4b5c0d38e7c1fbe75be39758dfe5fa63982bf1663ee9ccf3471dc5, nullifiers: nullifiers, commitments: commitments, boundParams: boundParams, From 83f9a5b67ec2c11af2f9ecd9be95d8737275db51 Mon Sep 17 00:00:00 2001 From: John Guilding <54913924+JohnGuilding@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:16:14 +0000 Subject: [PATCH 6/7] fix: run CI on main Co-authored-by: Nico Serrano --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0b67d49..32a5aad 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,6 +4,8 @@ permissions: {} on: push: + push: + branches: [main] pull_request: workflow_dispatch: From 52bc005ff06906737a2d271209cc46724d39726e Mon Sep 17 00:00:00 2001 From: John Guilding Date: Tue, 10 Feb 2026 08:27:13 -0300 Subject: [PATCH 7/7] feat: license & pin deps --- .github/workflows/test.yml | 3 +-- LICENSE | 21 +++++++++++++++++++++ foundry.lock | 3 +++ 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 LICENSE diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 32a5aad..80a8d46 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,8 +4,7 @@ permissions: {} on: push: - push: - branches: [main] + branches: [main] pull_request: workflow_dispatch: diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5f39fac --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 PSE + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/foundry.lock b/foundry.lock index d0c0159..dd24cd5 100644 --- a/foundry.lock +++ b/foundry.lock @@ -1,4 +1,7 @@ { + "lib/contract": { + "rev": "9ec09123eb140fdaaf3a5ff1f29d634c353630cd" + }, "lib/forge-std": { "tag": { "name": "v1.14.0",