Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/clean-zones-withdraw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'ox': patch
---

Added `WithdrawalSenderTag` utilities for deriving nonce-bound Tempo Zone withdrawal sender tags.
14 changes: 14 additions & 0 deletions src/tempo/WithdrawalSenderTag.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Hex } from 'ox'
import { WithdrawalSenderTag } from 'ox/tempo'
import { expectTypeOf, test } from 'vitest'

test('from', () => {
expectTypeOf(
WithdrawalSenderTag.from({
fallbackNonce: 19n,
sender: '0x1234567890abcdef1234567890abcdef12345678',
transactionHash:
'0xabababababababababababababababababababababababababababababababab',
}),
).toEqualTypeOf<Hex.Hex>()
})
30 changes: 30 additions & 0 deletions src/tempo/WithdrawalSenderTag.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, expect, test } from 'vitest'
import * as WithdrawalSenderTag from './WithdrawalSenderTag.js'

describe('from', () => {
test('derives the production sender tag', () => {
expect(
WithdrawalSenderTag.from({
fallbackNonce: 19n,
sender: '0x0F0896dbf0465E5c07963301dcFEA1101Fa91EaC',
transactionHash:
'0xae628bdc4bd24a9f9a917825a208baa16c384ab8a96a40cd5146bd20d9b3f6d9',
}),
).toMatchInlineSnapshot(
`"0xf1acbae45cd689281144042331e3379cf631a8d2db83057ccf38754a0b0108f2"`,
)
})

test('derives the canonical internal deposit bounce-back tag', () => {
expect(
WithdrawalSenderTag.from({
fallbackNonce: 0n,
sender: '0x0000000000000000000000000000000000000000',
transactionHash:
'0x0000000000000000000000000000000000000000000000000000000000000000',
}),
).toMatchInlineSnapshot(
`"0xa86d54e9aab41ae5e520ff0062ff1b4cbd0b2192bb01080a058bb170d84e6457"`,
)
})
})
66 changes: 66 additions & 0 deletions src/tempo/WithdrawalSenderTag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import * as AbiParameters from '../core/AbiParameters.js'
import type * as Address from '../core/Address.js'
import * as Hash from '../core/Hash.js'
import type * as Hex from '../core/Hex.js'

/**
* Derives the sender tag that identifies the indexed parent-chain
* `WithdrawalProcessed` event for a Zone withdrawal.
*
* The `transactionHash` is the Zone transaction containing the
* `ZoneOutbox.requestWithdrawal` call. The protocol defines a user withdrawal
* sender tag as
* `keccak256(abi.encodePacked(sender, transactionHash, fallbackNonce))`.
* Internal deposit bounce-backs use the canonical zero-sender tag derived from
* `address(0)` and `bytes32(0)` without a fallback nonce.
*
* [Authenticated Withdrawals Specification](https://github.com/tempoxyz/zones/blob/main/specs/spec.md#authenticated-withdrawals)
*
* @example
* ```ts twoslash
* import { WithdrawalSenderTag } from 'ox/tempo'
*
* const senderTag = WithdrawalSenderTag.from({
* fallbackNonce: 19n,
* sender: '0x1234567890abcdef1234567890abcdef12345678',
* transactionHash:
* '0xabababababababababababababababababababababababababababababababab'
* })
* ```
*
* @param value - Withdrawal sender, Zone transaction hash, and fallback nonce.
* @returns The sender tag.
*/
export function from(value: from.Value): Hex.Hex {
const { fallbackNonce, sender, transactionHash } = value
if (
sender === '0x0000000000000000000000000000000000000000' &&
fallbackNonce === 0n
)
return Hash.keccak256(
AbiParameters.encodePacked(
['address', 'bytes32'],
[
sender,
'0x0000000000000000000000000000000000000000000000000000000000000000',
],
),
)
return Hash.keccak256(
AbiParameters.encodePacked(
['address', 'bytes32', 'uint64'],
[sender, transactionHash, fallbackNonce],
),
)
}

export declare namespace from {
export type Value = {
/** Public nonce assigned to the withdrawal's private fallback recipient. */
fallbackNonce: bigint
/** Address that requested the withdrawal. */
sender: Address.Address
/** Hash of the Zone transaction containing `ZoneOutbox.requestWithdrawal`. */
transactionHash: Hex.Hex
}
}
24 changes: 24 additions & 0 deletions src/tempo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,30 @@ export * as VirtualAddress from './VirtualAddress.js'
* @category Reference
*/
export * as VirtualMaster from './VirtualMaster.js'
/**
* Utilities for deriving the sender tag that correlates a Zone withdrawal with
* its indexed parent-chain `WithdrawalProcessed` event.
*
* The sender tag commits to the withdrawal sender, the Zone transaction hash
* containing the `ZoneOutbox.requestWithdrawal` call, and its fallback nonce.
*
* [Authenticated Withdrawals Specification](https://github.com/tempoxyz/zones/blob/main/specs/spec.md#authenticated-withdrawals)
*
* @example
* ```ts twoslash
* import { WithdrawalSenderTag } from 'ox/tempo'
*
* const senderTag = WithdrawalSenderTag.from({
* fallbackNonce: 19n,
* sender: '0x1234567890abcdef1234567890abcdef12345678',
* transactionHash:
* '0xabababababababababababababababababababababababababababababababab'
* })
* ```
*
* @category Reference
*/
export * as WithdrawalSenderTag from './WithdrawalSenderTag.js'

/**
* Zone ID utilities for converting between zone IDs and zone chain IDs.
Expand Down
Loading