Skip to content

Commit 2277ebc

Browse files
authored
synd-cli: checkRetryable & undo-alias commands (#917)
1 parent 12cc72e commit 2277ebc

File tree

12 files changed

+417
-131
lines changed

12 files changed

+417
-131
lines changed

synd-cli/biome.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@
2626
}
2727
},
2828
"files": {
29-
"ignore": ["node_modules", "dist", ".gitignore", ".next"]
29+
"ignore": ["node_modules", "dist", ".gitignore", ".next", "src/dev"]
3030
}
3131
}

synd-cli/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
"format": "biome format --write .",
88
"lint": "biome lint --write .",
99
"typecheck": "tsc --noEmit",
10-
"biome:check": "biome check .",
11-
"biome:check-write": "biome check --write ."
10+
"check": "biome check .",
11+
"check-write": "biome check --write ."
1212
},
1313
"dependencies": {
1414
"@arbitrum/orbit-sdk": "^0.23.3",

synd-cli/src/cli/commands/alias.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { applyL1ToL2Alias } from "@/utils/alias"
1+
import { applyL1ToL2Alias, undoL1ToL2Alias } from "@/utils/alias"
22
import { print } from "@/utils/print"
33
import type { Command } from "@commander-js/extra-typings"
44
import { ethAddressSchema, handleSchemaErrors } from "../schema"
@@ -19,4 +19,20 @@ export function aliasCommand(program: Command) {
1919
}
2020
print(applyL1ToL2Alias(parsedAddress))
2121
})
22+
23+
program
24+
.command("undo-alias")
25+
.description("Calculate the original address from an aliased L2 address")
26+
.argument("<address>", "The aliased address to undo")
27+
.action((address: string) => {
28+
const {
29+
success,
30+
data: parsedAddress,
31+
error
32+
} = ethAddressSchema.safeParse(address)
33+
if (!success) {
34+
return handleSchemaErrors(error)
35+
}
36+
print(undoL1ToL2Alias(parsedAddress))
37+
})
2238
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import type { CheckRetryable } from "@/types"
2+
import {
3+
publicClientToProvider,
4+
registerNetworkInArbSDK
5+
} from "@/utils/arbitrumSDKHelpers"
6+
import { print } from "@/utils/print"
7+
import {
8+
ParentToChildMessageStatus,
9+
ParentTransactionReceipt
10+
} from "@arbitrum/sdk"
11+
import type { JsonRpcProvider } from "@ethersproject/providers"
12+
13+
export async function checkRetryable({
14+
hash,
15+
settlementPublicClient,
16+
appchainPublicClient,
17+
rollup
18+
}: CheckRetryable) {
19+
const settlementChainProvider: JsonRpcProvider = publicClientToProvider(
20+
settlementPublicClient
21+
)
22+
const appchainProvider: JsonRpcProvider =
23+
publicClientToProvider(appchainPublicClient)
24+
25+
await registerNetworkInArbSDK(
26+
settlementChainProvider,
27+
appchainProvider,
28+
rollup,
29+
appchainPublicClient.chain.testnet ?? false
30+
)
31+
32+
print(`Checking retryable tickets for settlement chain tx: ${hash}`)
33+
34+
const parentReceipt =
35+
await settlementChainProvider.getTransactionReceipt(hash)
36+
if (!parentReceipt) {
37+
throw new Error(`Transaction receipt not found for hash: ${hash}`)
38+
}
39+
40+
print(`Settlement chain tx found in block ${parentReceipt.blockNumber}`)
41+
42+
const parentTxReceipt = new ParentTransactionReceipt(parentReceipt)
43+
44+
const parentToChildMessages =
45+
await parentTxReceipt.getParentToChildMessages(appchainProvider)
46+
47+
print(`Found ${parentToChildMessages.length} retryable ticket(s)`)
48+
49+
if (parentToChildMessages.length === 0) {
50+
print("No retryable tickets found in this transaction")
51+
return
52+
}
53+
54+
for (let i = 0; i < parentToChildMessages.length; i++) {
55+
const message = parentToChildMessages[i]
56+
print(`\n=== Retryable Ticket ${i + 1}/${parentToChildMessages.length} ===`)
57+
print(`Retryable creation ID: ${message.retryableCreationId}`)
58+
59+
const status = await message.status()
60+
print(`Status: ${ParentToChildMessageStatus[status]}`)
61+
62+
if (status === ParentToChildMessageStatus.REDEEMED) {
63+
const result = await message.waitForStatus()
64+
if ("childTxReceipt" in result) {
65+
print(`Appchain tx hash: ${result.childTxReceipt.transactionHash}`)
66+
print(`Appchain block: ${result.childTxReceipt.blockNumber}`)
67+
}
68+
}
69+
}
70+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { appchainCheckRetryableOptionsSchema } from "@/cli/schema"
2+
import { addInitSubcommand } from "@/utils/addInitCommand"
3+
import {
4+
getAppchainClients,
5+
getSupportedChainPublicClient
6+
} from "@/utils/clients"
7+
import { parseConfigAndOptions } from "@/utils/config"
8+
import type { Command } from "@commander-js/extra-typings"
9+
import { checkRetryable } from "./checkRetryable"
10+
11+
export function checkRetryableCommand(program: Command) {
12+
const checkCmd = program
13+
.command("check-retryable")
14+
.description(
15+
"Check retryable ticket status from a settlement chain transaction"
16+
)
17+
18+
addInitSubcommand(
19+
checkCmd,
20+
"check-retryable",
21+
appchainCheckRetryableOptionsSchema
22+
)
23+
24+
checkCmd
25+
.option("--config <path>", "Path to JSON config file")
26+
.option("--settlement-rpc <url>", "RPC URL for the settlement chain")
27+
.option("--appchain-rpc <url>", "RPC URL for the appchain")
28+
.option("--rollup <address>", "Address of the rollup contract")
29+
.option("--hash <hash>", "Settlement chain transaction hash to check")
30+
.action(async (options: Record<string, unknown>) => {
31+
const validatedOptions = parseConfigAndOptions(
32+
options,
33+
appchainCheckRetryableOptionsSchema
34+
)
35+
36+
const { settlementRpc, appchainRpc, rollup, hash } = validatedOptions
37+
38+
const settlementPublicClient =
39+
await getSupportedChainPublicClient(settlementRpc)
40+
const [appchainPublicClient] = await getAppchainClients(appchainRpc)
41+
42+
await checkRetryable({
43+
hash,
44+
settlementPublicClient,
45+
appchainPublicClient,
46+
rollup
47+
})
48+
})
49+
}
Lines changed: 6 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
import type { CheckTokenBridge, PublicClientWithChain } from "@/types"
1+
import type { CheckTokenBridge } from "@/types"
2+
import {
3+
publicClientToProvider,
4+
registerNetworkInArbSDK
5+
} from "@/utils/arbitrumSDKHelpers"
26
import { getTokenBridgeContracts } from "@/utils/getTokenBridgeContracts"
37
import { print } from "@/utils/print"
48
import { createTokenBridgePrepareTransactionReceipt } from "@arbitrum/orbit-sdk"
5-
import {
6-
type ArbitrumNetwork,
7-
getArbitrumNetworkInformationFromRollup,
8-
registerCustomArbitrumNetwork
9-
} from "@arbitrum/sdk"
10-
import type { JsonRpcProvider } from "@ethersproject/providers"
11-
import { providers } from "ethers"
129
import { stringify } from "viem"
1310

1411
export async function checkTokenBridge({
@@ -17,7 +14,7 @@ export async function checkTokenBridge({
1714
settlementPublicClient,
1815
createdAtHash
1916
}: CheckTokenBridge) {
20-
registerNewNetwork(
17+
registerNetworkInArbSDK(
2118
publicClientToProvider(settlementPublicClient),
2219
publicClientToProvider(appchainPublicClient),
2320
rollup,
@@ -63,45 +60,3 @@ export async function checkTokenBridge({
6360
print("TokenBridge contracts fetched")
6461
print(stringify(tokenBridgeContracts, null, 2))
6562
}
66-
67-
export const registerNewNetwork = async (
68-
parentProvider: JsonRpcProvider,
69-
childProvider: JsonRpcProvider,
70-
rollupAddress: string,
71-
isTestnet: boolean
72-
): Promise<ArbitrumNetwork> => {
73-
const chainId = (await childProvider.getNetwork()).chainId
74-
const { parentChainId, ethBridge, confirmPeriodBlocks } =
75-
await getArbitrumNetworkInformationFromRollup(rollupAddress, parentProvider)
76-
77-
const arbitrumNetwork: ArbitrumNetwork = {
78-
name: String(`${chainId}-arbitrum-network`),
79-
chainId,
80-
parentChainId,
81-
confirmPeriodBlocks,
82-
ethBridge,
83-
isCustom: true,
84-
isTestnet
85-
}
86-
87-
return registerCustomArbitrumNetwork(arbitrumNetwork)
88-
}
89-
90-
export function publicClientToProvider(publicClient: PublicClientWithChain) {
91-
const { chain } = publicClient
92-
93-
if (typeof chain === "undefined") {
94-
throw new Error(`[publicClientToProvider] "chain" is undefined`)
95-
}
96-
97-
const network = {
98-
chainId: chain.id,
99-
name: chain.name,
100-
ensAddress: chain.contracts?.ensRegistry?.address
101-
}
102-
103-
const transportUrl = publicClient.transport.url as string | undefined
104-
const url = transportUrl ?? chain.rpcUrls.default.http[0]
105-
106-
return new providers.StaticJsonRpcProvider(url, network)
107-
}

0 commit comments

Comments
 (0)