-
Notifications
You must be signed in to change notification settings - Fork 0
feat: rise deployment #16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "RFQVaultExecutor": "0x97caca78ac2a94c67643d07843f85afaa44a3ea5", | ||
| "AcrossERC20AmountManipulator": "0x05481b7163c376ab4cb0ebc7d17f2cf7651042ee", | ||
| "MathManipulator": "0x3c3d4F3D636C06bcEb3bCc71EafE36486Ef40581" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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), | ||
| ); | ||
|
Comment on lines
+58
to
+64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🌐 Web query:
💡 Result: To enable permissioned deploy protection while using CreateX's deployCreate3, you must encode msg.sender into the first 20 bytes of the salt [1][2][3]. Because CreateX uses these bytes to verify that the transaction initiator matches the address embedded in the salt, this ensures that only the specified address can perform the deployment [3]. Regarding the preservation of cross-chain deterministic addresses, you must decide whether to enable or disable cross-chain redeploy protection using the 21st byte of the salt [2][4]: 1. To preserve the same address across all chains (disable cross-chain redeploy protection), set the 21st byte (index 20) to 0x00 [3]. 2. To use different addresses per chain (enable cross-chain redeploy protection), set the 21st byte to 0x01 [2][4]. Any value greater than 0x01 in the 21st byte will cause the transaction to revert, as CreateX enforces developer explicitness regarding these protection mechanisms [2][4]. The remaining 11 bytes (indices 21–31) are available for arbitrary entropy, such as a unique identifier, to distinguish deployments while maintaining the desired protection levels [3]. Summary of salt structure: - Bytes 0-19: msg.sender (Permissioned Deploy Protection) [3] - Byte 20: 0x00 (Same address on all chains) or 0x01 (Different address per chain) [2][3][4] - Bytes 21-31: Entropy [3] Citations:
🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- tracked candidate files ---'
git ls-files \
'scripts/deploy/create3.ts' \
'scripts/deploy/deployMathManipulator.ts' \
'*create*x*' \
'*MathManipulator*' \
'*addresses*' | sed -n '1,160p'
printf '%s\n' '--- create3.ts ---'
cat -n scripts/deploy/create3.ts | sed -n '1,140p'
printf '%s\n' '--- deployMathManipulator.ts ---'
cat -n scripts/deploy/deployMathManipulator.ts | sed -n '1,150p'
printf '%s\n' '--- CREATE3 and expected-address references ---'
rg -n -S 'MATH_MANIPULATOR_(CREATE3_SALT|EXPECTED_ADDRESS)|deployCreate3|create3Factory|hasContractBytecode|persist\(' \
scripts test tests contracts config deployments 2>/dev/null | sed -n '1,260p'Repository: SocketDotTech/openrouter Length of output: 20806 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- create3 helpers and ABI ---'
cat -n scripts/deploy/create3.ts | sed -n '140,370p'
printf '%s\n' '--- comparable deployment flows ---'
for f in \
scripts/deploy/deployCctpClaimExecutor.ts \
scripts/deploy/deployRFQVaultExecutor.ts \
scripts/deploy/deployEtherealExecutor.ts \
scripts/deploy/deployCelerExecutor.ts \
scripts/deploy/deployHypercoreExecutor.ts \
scripts/deploy/deployAcrossERC20AmountManipulator.ts \
scripts/deploy/deployOpenRouter.ts
do
if [ -f "$f" ]; then
printf '\n### %s\n' "$f"
rg -n -A18 -B8 'existingBytecode|deployCreate3|computeFinalAddress|persist\(' "$f" | sed -n '1,180p'
fi
done
printf '%s\n' '--- tests and documentation mentioning MathManipulator/CreateX salts ---'
rg -n -S 'MathManipulator|CREATE3_SALT|CreateX|permissioned|salt' \
test tests scripts README.md docs 2>/dev/null | sed -n '1,260p'Repository: SocketDotTech/openrouter Length of output: 39974 🌐 Web query:
💡 Result: The CreateX Citations:
🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from urllib.request import urlopen
urls = [
"https://raw.githubusercontent.com/pcaversaccio/createx/main/src/CreateX.sol",
"https://raw.githubusercontent.com/pcaversaccio/createx/main/README.md",
]
for url in urls:
print(f"--- {url} ---")
try:
text = urlopen(url, timeout=10).read().decode()
except Exception as exc:
print(type(exc).__name__, exc)
continue
lines = text.splitlines()
needles = ("function _guard", "deployCreate3", "permissioned", "cross-chain", "salt")
for i, line in enumerate(lines):
if any(n.lower() in line.lower() for n in needles):
lo, hi = max(0, i-5), min(len(lines), i+15)
print("\n".join(f"{j+1}:{lines[j]}" for j in range(lo, hi)))
print()
PYRepository: SocketDotTech/openrouter Length of output: 612 🏁 Script executed: #!/bin/bash
set -eu
for url in \
https://raw.githubusercontent.com/pcaversaccio/createx/main/src/CreateX.sol \
https://raw.githubusercontent.com/pcaversaccio/createx/main/README.md
do
printf '%s\n' "--- $url ---"
curl -ksSfL "$url" | tr -d '\r' | \
rg -n -A24 -B12 '_guard|deployCreate3|permissioned|cross.?chain|InvalidSalt|salt' | sed -n '1,320p'
doneRepository: SocketDotTech/openrouter Length of output: 36777 🏁 Script executed: #!/bin/bash
set -eu
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
curl -ksSfL https://raw.githubusercontent.com/pcaversaccio/createx/main/src/CreateX.sol > "$tmp"
printf '%s\n' '--- relevant CreateX source locations ---'
rg -n '_guard|deployCreate3|computeCreate3Address|SenderBytes|RedeployProtectionFlag' "$tmp"
printf '%s\n' '--- guard implementation and CREATE3 implementation ---'
line=$(rg -n '^ function _guard' "$tmp" | head -1 | cut -d: -f1)
if [ -n "${line:-}" ]; then
start=$((line-12)); end=$((line+80))
sed -n "${start},${end}p" "$tmp"
fi
line=$(rg -n 'function deployCreate3\(bytes32' "$tmp" | head -1 | cut -d: -f1)
if [ -n "${line:-}" ]; then
start=$((line-12)); end=$((line+70))
sed -n "${start},${end}p" "$tmp"
fi
printf '%s\n' '--- README special-feature section ---'
line=$(rg -n 'Permissioned Deploy Protection and Cross-Chain Redeploy Protection' README.tmp "$tmp" 2>/dev/null | head -1 | cut -d: -f1 || true)
rg -n -A100 -B8 'Permissioned Deploy Protection and Cross-Chain Redeploy Protection' "$tmp" | sed -n '1,180p'Repository: SocketDotTech/openrouter Length of output: 16099 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- MathManipulator implementation and address persistence ---'
cat -n src/manipulators/MathManipulator.sol | sed -n '1,240p'
cat -n scripts/deploy/manipulatorAddresses.ts | sed -n '1,220p'
printf '%s\n' '--- MathManipulator consumers and persisted entries ---'
rg -n -S 'MathManipulator|mathManipulator|manipulator' \
src scripts deployments config test tests 2>/dev/null | sed -n '1,300p'
printf '%s\n' '--- deployment address records containing MathManipulator ---'
rg -n -S 'MathManipulator' deployments *.json 2>/dev/null | sed -n '1,180p'Repository: SocketDotTech/openrouter Length of output: 7180 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
try:
from Crypto.Hash import keccak
except Exception as exc:
print("PyCryptodome unavailable:", exc)
raise SystemExit(0)
def k256(data: bytes) -> bytes:
h = keccak.new(digest_bits=256)
h.update(data)
return h.digest()
def abi_encode_bytes32(value: bytes) -> bytes:
assert len(value) == 32
return value
def rlp_string(value: bytes) -> bytes:
if len(value) == 1 and value[0] < 0x80:
return value
if len(value) <= 55:
return bytes([0x80 + len(value)]) + value
n = len(value).to_bytes((len(value).bit_length() + 7) // 8, "big")
return bytes([0xb7 + len(n)]) + n + value
def rlp_list(items: list[bytes]) -> bytes:
payload = b"".join(items)
if len(payload) <= 55:
return bytes([0xc0 + len(payload)]) + payload
n = len(payload).to_bytes((len(payload).bit_length() + 7) // 8, "big")
return bytes([0xf7 + len(n)]) + n + payload
def address_from_create3(guarded_salt: bytes) -> str:
factory = bytes.fromhex("ba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed"[2:] if False else "ba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed")
proxy_init_hash = bytes.fromhex("".join(re.findall(
r"CREATE3_PROXY_INIT_CODE_HASH = keccak256\(\s*'0x([0-9a-f]+)'",
Path("scripts/deploy/create3.ts").read_text(),
)))
proxy = k256(b"\xff" + factory + guarded_salt + proxy_init_hash)[12:]
return "0x" + k256(rlp_list([rlp_string(proxy), rlp_string(b"\x01")]))[12:].hex()
salt_text = b"MathManipulator"
raw = k256(salt_text)
guarded = k256(abi_encode_bytes32(raw))
expected = "0x3c3d4F3D636C06bcEb3bCc71EafE36486Ef40581"
print("raw salt:", raw.hex())
print("raw first 20 bytes:", "0x" + raw[:20].hex())
print("raw byte 20:", f"0x{raw[20]:02x}")
print("guarded salt for CreateX Random path:", guarded.hex())
print("computed final address:", address_from_create3(guarded))
print("matches repository expected:", address_from_create3(guarded).lower() == expected.lower())
print("raw salt is permissioned for arbitrary deployer:", raw[:20] == b"\x00" * 20)
print("raw salt uses an explicit valid flag:", raw[20] in (0, 1))
PYRepository: SocketDotTech/openrouter Length of output: 213 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
# Minimal read-only Keccak-256 implementation for deterministic address checks.
RC = [
1, 0x8082, 0x800000000000808A, 0x8000000080008000,
0x808B, 0x80000001, 0x8000000080008081, 0x8000000000008009,
0x8A, 0x88, 0x80008009, 0x8000000A,
0x8000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003,
0x8000000000008002, 0x8000000000000080, 0x800A, 0x800000008000000A,
0x8000000080008081, 0x8000000000008080, 0x80000001, 0x8000000080008008,
]
ROT = [
[0, 36, 3, 41, 18],
[1, 44, 10, 45, 2],
[62, 6, 43, 15, 61],
[28, 55, 25, 21, 56],
[27, 20, 39, 8, 14],
]
MASK = (1 << 64) - 1
def rol(x, n):
return ((x << n) | (x >> (64 - n))) & MASK if n else x
def keccak_f(a):
for rc in RC:
c = [a[x] ^ a[x+5] ^ a[x+10] ^ a[x+15] ^ a[x+20] for x in range(5)]
d = [c[(x-1) % 5] ^ rol(c[(x+1) % 5], 1) for x in range(5)]
for x in range(5):
for y in range(5):
a[x + 5*y] ^= d[x]
b = [0] * 25
for x in range(5):
for y in range(5):
b[y + 5*((2*x + 3*y) % 5)] = rol(a[x + 5*y], ROT[x][y])
for x in range(5):
for y in range(5):
a[x + 5*y] = b[x + 5*y] ^ ((~b[(x+1) % 5 + 5*y]) & b[(x+2) % 5 + 5*y])
a[0] ^= rc
return a
def k256(data):
rate = 136
padded = bytearray(data)
padded.append(0x01)
padded.extend(b"\x00" * ((rate - (len(padded) % rate) - 1) % rate))
padded.append(0x80)
state = [0] * 25
for off in range(0, len(padded), rate):
block = padded[off:off+rate]
for i in range(rate // 8):
state[i] ^= int.from_bytes(block[i*8:i*8+8], "little")
keccak_f(state)
out = b"".join(x.to_bytes(8, "little") for x in state)
return out[:32]
assert k256(b"") .hex() == "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
assert k256(b"MathManipulator").hex() == "TODO".replace("TODO", k256(b"MathManipulator").hex())
def rlp_string(value):
if len(value) == 1 and value[0] < 0x80:
return value
return bytes([0x80 + len(value)]) + value
def rlp_list(items):
payload = b"".join(items)
return bytes([0xc0 + len(payload)]) + payload
raw = k256(b"MathManipulator")
guarded = k256(raw)
factory = bytes.fromhex("ba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed")
init_hash_hex = re.search(
r"CREATE3_PROXY_INIT_CODE_HASH = keccak256\(\s*'0x([0-9a-f]+)'",
Path("scripts/deploy/create3.ts").read_text(),
).group(1)
proxy_init_hash = k256(bytes.fromhex(init_hash_hex))
proxy = k256(b"\xff" + factory + guarded + proxy_init_hash)[12:]
final = k256(rlp_list([rlp_string(proxy), rlp_string(b"\x01")]))[12:]
print("raw salt:", raw.hex())
print("raw first 20 bytes:", "0x" + raw[:20].hex())
print("raw byte 20:", f"0x{raw[20]:02x}")
print("guarded salt:", guarded.hex())
print("proxy init hash:", proxy_init_hash.hex())
print("computed final address:", "0x" + final.hex())
print("repository expected address:", "0x3c3d4F3D636C06bcEb3bCc71EafE36486Ef40581")
print("matches repository expected:", final.hex().lower() == "3c3d4f3d636c06bceb3bcc71eafe36486ef40581")
print("raw salt is permissioned for arbitrary deployer:", raw[:20] == b"\x00" * 20)
print("raw salt uses an explicit valid flag:", raw[20] in (0, 1))
PYRepository: SocketDotTech/openrouter Length of output: 751 Protect the MathManipulator CREATE3 salt and validate existing code.
📍 Affects 2 files
🤖 Prompt for AI AgentsSource: Path instructions |
||
|
|
||
| /** 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 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| /** | ||
| * Deployment script for MathManipulator via CreateX CREATE3. | ||
| * | ||
| * Usage: | ||
| * npx hardhat run scripts/deploy/deployMathManipulator.ts --network <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<void> { | ||
| 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); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<string> { | ||
| const filePath = resolve( | ||
| process.cwd(), | ||
| 'deployments', | ||
| stage, | ||
| 'addresses', | ||
| `${network}.json`, | ||
| ); | ||
| let deployments: Record<string, string> = {}; | ||
|
|
||
| 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', | ||
| ); | ||
|
Comment on lines
+23
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
file=$(git ls-files | rg '^scripts/deploy/manipulatorAddresses\.ts$')
printf '%s\n' "$file"
ast-grep outline "$file" --lang typescript
printf '\n--- file ---\n'
cat -n "$file"
printf '\n--- helper usages ---\n'
rg -n -C 3 'writeManipulatorAddress|manipulatorAddresses' scripts
printf '\n--- deployment-related files ---\n'
git ls-files scripts/deploy | sortRepository: SocketDotTech/openrouter Length of output: 6463 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- deployMathManipulator.ts ---'
cat -n scripts/deploy/deployMathManipulator.ts
printf '%s\n' '--- deployAcrossERC20AmountManipulator.ts ---'
cat -n scripts/deploy/deployAcrossERC20AmountManipulator.ts
printf '%s\n' '--- package scripts and deployment references ---'
rg -n -C 2 'deploy(Math|AcrossERC20AmountManipulator)|deployAcrossERC20AmountManipulator|deployMathManipulator' package.json .github scripts README.md 2>/dev/null || true
printf '%s\n' '--- existing file-lock or serialization patterns ---'
rg -n -i -C 2 'lockfile|proper-lockfile|mkdir.*lock|flock|rename\(.*tmp|writeFile.*tmp|exclusive.*flag' --glob '*.{ts,js,mjs,cjs,json}' . 2>/dev/null || trueRepository: SocketDotTech/openrouter Length of output: 11562 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- deploymentRegistry lock implementation ---'
cat -n scripts/deploy/deploymentRegistry.ts | sed -n '55,125p'
printf '%s\n' '--- deploymentRegistry write path ---'
cat -n scripts/deploy/deploymentRegistry.ts | sed -n '350,395p'
printf '%s\n' '--- deterministic read-modify-write race probe ---'
python3 - <<'PY'
import json
initial = {}
# Both invocations complete their read before either write.
a = dict(initial)
b = dict(initial)
a["MathManipulator"] = "0xmath"
b["AcrossERC20AmountManipulator"] = "0xacross"
# The second write replaces the complete file, rather than merging with it.
first_write = json.dumps(a, sort_keys=True)
final_write = json.dumps(b, sort_keys=True)
final = json.loads(final_write)
print("first_write:", first_write)
print("final_write:", final_write)
print("lost MathManipulator:", "MathManipulator" not in final)
PYRepository: SocketDotTech/openrouter Length of output: 4336 Serialize updates to each deployment address file. Concurrent runs for the same network can lose one address during the read-modify-write sequence. This should use a per-file cross-process lock around both operations. An atomic rename alone does not prevent the lost update. 🤖 Prompt for AI AgentsSource: Path instructions |
||
| return filePath; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: SocketDotTech/openrouter
Length of output: 2499
🏁 Script executed:
Repository: SocketDotTech/openrouter
Length of output: 30993
🏁 Script executed:
Repository: SocketDotTech/openrouter
Length of output: 908
Treat blank RISE variables as unset.
Use trimmed, non-empty values before applying the fallbacks at
hardhat.config.ts#L149-L153andhardhat.config.ts#L275-L275. Otherwise, a blankRISE_RPCproduces an invalid RPC URL, and a blankRISE_ETHERSCAN_KEYbypasses the intendedblockscoutfallback.📍 Affects 1 file
hardhat.config.ts#L149-L153(this comment)hardhat.config.ts#L275-L275🤖 Prompt for AI Agents
Source: Path instructions