ox 1.0.0-beta.13 → 1.0.0-beta.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/tempo/Channel.d.ts +8 -14
  2. package/dist/tempo/Channel.d.ts.map +1 -1
  3. package/dist/tempo/Channel.js +4 -8
  4. package/dist/tempo/Channel.js.map +1 -1
  5. package/dist/tempo/PoolId.d.ts +7 -7
  6. package/dist/tempo/PoolId.d.ts.map +1 -1
  7. package/dist/tempo/PoolId.js +9 -6
  8. package/dist/tempo/PoolId.js.map +1 -1
  9. package/dist/tempo/TransactionRequest.d.ts +15 -2
  10. package/dist/tempo/TransactionRequest.d.ts.map +1 -1
  11. package/dist/tempo/TransactionRequest.js +65 -29
  12. package/dist/tempo/TransactionRequest.js.map +1 -1
  13. package/dist/tempo/TxEnvelopeTempo.d.ts +2 -3
  14. package/dist/tempo/TxEnvelopeTempo.d.ts.map +1 -1
  15. package/dist/tempo/TxEnvelopeTempo.js +5 -6
  16. package/dist/tempo/TxEnvelopeTempo.js.map +1 -1
  17. package/dist/tempo/index.d.ts +3 -24
  18. package/dist/tempo/index.d.ts.map +1 -1
  19. package/dist/tempo/index.js +3 -24
  20. package/dist/tempo/index.js.map +1 -1
  21. package/dist/zod/tempo/RpcSchemaTempo.d.ts +46 -2
  22. package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
  23. package/dist/zod/tempo/TransactionRequest.d.ts +81 -4
  24. package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
  25. package/dist/zod/tempo/TransactionRequest.js +81 -18
  26. package/dist/zod/tempo/TransactionRequest.js.map +1 -1
  27. package/dist/zod/tempo/TxEnvelopeTempo.d.ts +3 -3
  28. package/dist/zod/tempo/TxEnvelopeTempo.js +1 -1
  29. package/dist/zod/tempo/TxEnvelopeTempo.js.map +1 -1
  30. package/dist/zod/tempo/z.d.ts +0 -1
  31. package/dist/zod/tempo/z.d.ts.map +1 -1
  32. package/dist/zod/tempo/z.js +0 -1
  33. package/dist/zod/tempo/z.js.map +1 -1
  34. package/package.json +1 -11
  35. package/src/tempo/Channel.test.ts +2 -23
  36. package/src/tempo/Channel.ts +10 -22
  37. package/src/tempo/PoolId.test.ts +7 -41
  38. package/src/tempo/PoolId.ts +14 -10
  39. package/src/tempo/TransactionRequest.test.ts +174 -1
  40. package/src/tempo/TransactionRequest.ts +84 -32
  41. package/src/tempo/TxEnvelopeTempo.test.ts +2 -2
  42. package/src/tempo/TxEnvelopeTempo.ts +7 -7
  43. package/src/tempo/index.ts +3 -24
  44. package/src/version.ts +1 -1
  45. package/src/zod/tempo/TransactionRequest.ts +86 -20
  46. package/src/zod/tempo/TxEnvelopeTempo.ts +1 -1
  47. package/src/zod/tempo/_test/TransactionRequest.test.ts +44 -0
  48. package/src/zod/tempo/z.ts +0 -1
  49. package/dist/tempo/TokenId.d.ts +0 -87
  50. package/dist/tempo/TokenId.d.ts.map +0 -1
  51. package/dist/tempo/TokenId.js +0 -123
  52. package/dist/tempo/TokenId.js.map +0 -1
  53. package/dist/zod/tempo/TokenId.d.ts +0 -6
  54. package/dist/zod/tempo/TokenId.d.ts.map +0 -1
  55. package/dist/zod/tempo/TokenId.js +0 -14
  56. package/dist/zod/tempo/TokenId.js.map +0 -1
  57. package/src/tempo/TokenId.bench.ts +0 -36
  58. package/src/tempo/TokenId.test.ts +0 -79
  59. package/src/tempo/TokenId.ts +0 -141
  60. package/src/zod/tempo/TokenId.ts +0 -15
  61. package/src/zod/tempo/_test/TokenId.test-d.ts +0 -17
  62. package/src/zod/tempo/_test/TokenId.test.ts +0 -21
@@ -14,7 +14,6 @@ import * as z from 'zod/mini'
14
14
  import * as z_AuthorizationTempo from './AuthorizationTempo.js'
15
15
  import * as z_KeyAuthorization from './KeyAuthorization.js'
16
16
  import * as z_SignatureEnvelope from './SignatureEnvelope.js'
17
- import * as z_TokenId from './TokenId.js'
18
17
 
19
18
  const fromRpcType = { '0x76': 'tempo' } as const
20
19
  const toRpcType = { tempo: '0x76' } as const
@@ -57,6 +56,16 @@ const CallToRpc = z.object({
57
56
  value: z.optional(uintBigintNumberish()),
58
57
  })
59
58
 
59
+ const Capabilities = z.record(z.string(), z.unknown())
60
+
61
+ const MultisigInit = z.object({
62
+ salt: z_Hex.Hex,
63
+ threshold: z.number(),
64
+ owners: z.readonly(
65
+ z.array(z.object({ owner: z_Address.Address, weight: z.number() })),
66
+ ),
67
+ })
68
+
60
69
  /** RPC tempo transaction request schema. */
61
70
  export const Rpc = z.object({
62
71
  accessList: z.optional(z_AccessList.AccessList),
@@ -64,6 +73,7 @@ export const Rpc = z.object({
64
73
  blobVersionedHashes: z.optional(z.readonly(z.array(z_Hex.Hex))),
65
74
  blobs: z.optional(z.readonly(z.array(z_Hex.Hex))),
66
75
  calls: z.optional(z.readonly(z.array(CallRpc))),
76
+ capabilities: z.optional(Capabilities),
67
77
  chainId: z.optional(z_Hex.Hex),
68
78
  data: z.optional(z_Hex.Hex),
69
79
  feePayer: z.optional(z.boolean()),
@@ -75,10 +85,13 @@ export const Rpc = z.object({
75
85
  input: z.optional(z_Hex.Hex),
76
86
  keyAuthorization: z.optional(z_KeyAuthorization.Rpc),
77
87
  keyData: z.optional(z_Hex.Hex),
88
+ keyId: z.optional(z_Address.Address),
78
89
  keyType: z.optional(KeyType),
79
90
  maxFeePerBlobGas: z.optional(z_Hex.Hex),
80
91
  maxFeePerGas: z.optional(z_Hex.Hex),
81
92
  maxPriorityFeePerGas: z.optional(z_Hex.Hex),
93
+ multisigInit: z.optional(MultisigInit),
94
+ multisigSignatureCount: z.optional(z.number()),
82
95
  nonce: z.optional(z_Hex.Hex),
83
96
  nonceKey: z.optional(z_Hex.Hex),
84
97
  r: z.optional(z_Hex.Hex),
@@ -114,21 +127,25 @@ export const Domain = z.object({
114
127
  blobVersionedHashes: z.optional(z.readonly(z.array(z_Hex.Hex))),
115
128
  blobs: z.optional(z.readonly(z.array(z_Hex.Hex))),
116
129
  calls: z.optional(z.readonly(z.array(Call))),
130
+ capabilities: z.optional(Capabilities),
117
131
  chainId: z.optional(z.number()),
118
132
  data: z.optional(z_Hex.Hex),
119
133
  feePayer: z.optional(z.boolean()),
120
134
  feePayerSignature: z.optional(z.union([SignatureDecoded, z.null()])),
121
- feeToken: z.optional(z.union([z_Address.Address, z.bigint()])),
135
+ feeToken: z.optional(z_Address.Address),
122
136
  from: z.optional(z_Address.Address),
123
137
  gas: z.optional(z.bigint()),
124
138
  gasPrice: z.optional(z.bigint()),
125
139
  input: z.optional(z_Hex.Hex),
126
140
  keyAuthorization: z.optional(z_KeyAuthorization.Domain),
127
141
  keyData: z.optional(z_Hex.Hex),
142
+ keyId: z.optional(z_Address.Address),
128
143
  keyType: z.optional(KeyType),
129
144
  maxFeePerBlobGas: z.optional(z.bigint()),
130
145
  maxFeePerGas: z.optional(z.bigint()),
131
146
  maxPriorityFeePerGas: z.optional(z.bigint()),
147
+ multisigInit: z.optional(MultisigInit),
148
+ multisigSignatureCount: z.optional(z.number()),
132
149
  nonce: z.optional(z.bigint()),
133
150
  nonceKey: z.optional(z.union([z.bigint(), z.literal('random')])),
134
151
  r: z.optional(z_Hex.Hex),
@@ -150,21 +167,25 @@ export const DomainToRpc = z.object({
150
167
  blobVersionedHashes: z.optional(z.readonly(z.array(z_Hex.Hex))),
151
168
  blobs: z.optional(z.readonly(z.array(z_Hex.Hex))),
152
169
  calls: z.optional(z.readonly(z.array(CallToRpc))),
170
+ capabilities: z.optional(Capabilities),
153
171
  chainId: z.optional(uintNumberNumberish()),
154
172
  data: z.optional(z_Hex.Hex),
155
173
  feePayer: z.optional(z.boolean()),
156
174
  feePayerSignature: z.optional(z.union([SignatureDecoded, z.null()])),
157
- feeToken: z.optional(z.union([z_Address.Address, z.bigint()])),
175
+ feeToken: z.optional(z_Address.Address),
158
176
  from: z.optional(z_Address.Address),
159
177
  gas: z.optional(uintBigintNumberish()),
160
178
  gasPrice: z.optional(uintBigintNumberish()),
161
179
  input: z.optional(z_Hex.Hex),
162
180
  keyAuthorization: z.optional(z_KeyAuthorization.DomainToRpc),
163
181
  keyData: z.optional(z_Hex.Hex),
182
+ keyId: z.optional(z_Address.Address),
164
183
  keyType: z.optional(KeyType),
165
184
  maxFeePerBlobGas: z.optional(uintBigintNumberish()),
166
185
  maxFeePerGas: z.optional(uintBigintNumberish()),
167
186
  maxPriorityFeePerGas: z.optional(uintBigintNumberish()),
187
+ multisigInit: z.optional(MultisigInit),
188
+ multisigSignatureCount: z.optional(z.number()),
168
189
  nonce: z.optional(uintBigintNumberish()),
169
190
  nonceKey: z.optional(z.union([uintBigintNumberish(), z.literal('random')])),
170
191
  r: z.optional(z_Hex.Hex),
@@ -232,6 +253,17 @@ function fromRpc(
232
253
  z_KeyAuthorization.KeyAuthorization,
233
254
  request.keyAuthorization as never,
234
255
  ) as never
256
+ if (typeof request.capabilities !== 'undefined')
257
+ request_.capabilities = request.capabilities
258
+ if (typeof request.feePayer !== 'undefined')
259
+ request_.feePayer = request.feePayer
260
+ if (typeof request.keyData !== 'undefined') request_.keyData = request.keyData
261
+ if (typeof request.keyId !== 'undefined') request_.keyId = request.keyId
262
+ if (typeof request.keyType !== 'undefined') request_.keyType = request.keyType
263
+ if (typeof request.multisigInit !== 'undefined')
264
+ request_.multisigInit = request.multisigInit
265
+ if (typeof request.multisigSignatureCount !== 'undefined')
266
+ request_.multisigSignatureCount = request.multisigSignatureCount
235
267
  if (typeof request.validBefore !== 'undefined')
236
268
  request_.validBefore = core_Hex.toNumber(request.validBefore)
237
269
  if (typeof request.validAfter !== 'undefined')
@@ -251,6 +283,22 @@ function toRpc(
251
283
  authorizationList: undefined,
252
284
  } as never) as core_TransactionRequest.Rpc
253
285
 
286
+ const tempo =
287
+ typeof request.calls !== 'undefined' ||
288
+ typeof request.capabilities !== 'undefined' ||
289
+ typeof request.feePayer !== 'undefined' ||
290
+ typeof request.feeToken !== 'undefined' ||
291
+ typeof request.keyAuthorization !== 'undefined' ||
292
+ typeof request.keyData !== 'undefined' ||
293
+ typeof request.keyId !== 'undefined' ||
294
+ typeof request.keyType !== 'undefined' ||
295
+ typeof request.multisigInit !== 'undefined' ||
296
+ typeof request.multisigSignatureCount !== 'undefined' ||
297
+ typeof request.nonceKey !== 'undefined' ||
298
+ typeof request.validBefore !== 'undefined' ||
299
+ typeof request.validAfter !== 'undefined' ||
300
+ request.type === 'tempo'
301
+
254
302
  if (request.authorizationList)
255
303
  request_rpc.authorizationList = z.encode(
256
304
  z_AuthorizationTempo.ListSignedToRpc,
@@ -269,24 +317,41 @@ function toRpc(
269
317
  value: call.value ? encodeNumberish(call.value) : '0x',
270
318
  data: call.data ?? '0x',
271
319
  }))
272
- else if (request.to || request.data || request.value)
320
+ else if (request.to || request.data || request.value || tempo)
273
321
  request_rpc.calls = [
274
322
  {
275
- to: request.to ?? undefined,
323
+ to:
324
+ request.to ||
325
+ (tempo && (!request.data || request.data === '0x')
326
+ ? '0x0000000000000000000000000000000000000000'
327
+ : undefined),
276
328
  value: request.value ? encodeNumberish(request.value) : '0x',
277
329
  data: request.data ?? '0x',
278
330
  },
279
331
  ]
280
- if (typeof request.feeToken !== 'undefined')
281
- request_rpc.feeToken =
282
- typeof request.feeToken === 'bigint'
283
- ? z.encode(z_TokenId.address, request.feeToken)
284
- : request.feeToken
332
+ if (
333
+ typeof request.feeToken !== 'undefined' &&
334
+ !(request.feePayer === true && !request.feePayerSignature)
335
+ )
336
+ request_rpc.feeToken = request.feeToken
285
337
  if (request.keyAuthorization)
286
338
  request_rpc.keyAuthorization = z.encode(
287
339
  z_KeyAuthorization.KeyAuthorizationToRpc,
288
340
  request.keyAuthorization as never,
289
341
  ) as never
342
+ if (typeof request.capabilities !== 'undefined')
343
+ request_rpc.capabilities = request.capabilities
344
+ if (typeof request.feePayer !== 'undefined')
345
+ request_rpc.feePayer = request.feePayer
346
+ if (typeof request.keyData !== 'undefined')
347
+ request_rpc.keyData = shimKeyData(request.keyData)
348
+ if (typeof request.keyId !== 'undefined') request_rpc.keyId = request.keyId
349
+ if (typeof request.keyType !== 'undefined')
350
+ request_rpc.keyType = request.keyType
351
+ if (typeof request.multisigInit !== 'undefined')
352
+ request_rpc.multisigInit = request.multisigInit
353
+ if (typeof request.multisigSignatureCount !== 'undefined')
354
+ request_rpc.multisigSignatureCount = request.multisigSignatureCount
290
355
  if (typeof request.validBefore !== 'undefined')
291
356
  request_rpc.validBefore = encodeNumberish(request.validBefore)
292
357
  if (typeof request.validAfter !== 'undefined')
@@ -300,16 +365,7 @@ function toRpc(
300
365
  })()
301
366
  if (nonceKey) request_rpc.nonceKey = nonceKey
302
367
 
303
- if (
304
- typeof request.calls !== 'undefined' ||
305
- typeof request.feePayer !== 'undefined' ||
306
- typeof request.feeToken !== 'undefined' ||
307
- typeof request.keyAuthorization !== 'undefined' ||
308
- typeof request.nonceKey !== 'undefined' ||
309
- typeof request.validBefore !== 'undefined' ||
310
- typeof request.validAfter !== 'undefined' ||
311
- request.type === 'tempo'
312
- ) {
368
+ if (tempo) {
313
369
  request_rpc.type = toRpcType.tempo
314
370
  delete request_rpc.data
315
371
  delete request_rpc.input
@@ -320,6 +376,16 @@ function toRpc(
320
376
  return request_rpc
321
377
  }
322
378
 
379
+ /**
380
+ * Shims key data longer than 4 bytes into a 2-byte big-endian length hint
381
+ * (the node's gas estimator only accepts 1, 2, or 4-byte key data).
382
+ */
383
+ function shimKeyData(data: core_Hex.Hex): core_Hex.Hex {
384
+ const byteLength = core_Hex.size(data)
385
+ if (byteLength <= 4) return data
386
+ return core_Hex.fromNumber(byteLength, { size: 2 })
387
+ }
388
+
323
389
  /** Decodes an RPC signature into a recovered signature. */
324
390
  function signatureFromRpc(signature: {
325
391
  r: core_Hex.Hex
@@ -31,7 +31,7 @@ const baseFields = {
31
31
  calls: z.readonly(z.array(Call)),
32
32
  chainId: z.number(),
33
33
  feePayerSignature: z.optional(z.union([FeePayerSignature, z.null()])),
34
- feeToken: z.optional(z.union([z_Address.Address, z.bigint()])),
34
+ feeToken: z.optional(z_Address.Address),
35
35
  from: z.optional(z_Address.Address),
36
36
  gas: z.optional(z.bigint()),
37
37
  keyAuthorization: z.optional(z_KeyAuthorization.Domain),
@@ -44,6 +44,50 @@ describe('TransactionRequest', () => {
44
44
  )
45
45
  })
46
46
 
47
+ test('gas-model hints and capabilities round-trip', () => {
48
+ const hints = {
49
+ capabilities: { balanceDiffs: true },
50
+ keyData: '0x0578',
51
+ keyId: '0xcccccccccccccccccccccccccccccccccccccccc',
52
+ keyType: 'webAuthn',
53
+ multisigInit: {
54
+ salt: '0x0000000000000000000000000000000000000000000000000000000000000000',
55
+ threshold: 2,
56
+ owners: [
57
+ {
58
+ owner: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
59
+ weight: 1,
60
+ },
61
+ {
62
+ owner: '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
63
+ weight: 1,
64
+ },
65
+ ],
66
+ },
67
+ multisigSignatureCount: 2,
68
+ } as const
69
+
70
+ const decoded = z.decode(z_TransactionRequest.TransactionRequest, {
71
+ ...rpc,
72
+ ...hints,
73
+ })
74
+ expect(decoded).toMatchObject(hints)
75
+
76
+ const encoded = z.encode(z_TransactionRequest.TransactionRequest, decoded)
77
+ expect(encoded).toMatchObject(hints)
78
+ expect(encoded).toEqual(core_TransactionRequest.toRpc(decoded))
79
+ })
80
+
81
+ test('feeToken is withheld until the fee payer signs (TIP-76)', () => {
82
+ const decoded = z.decode(z_TransactionRequest.TransactionRequest, rpc)
83
+ const pending = z.encode(z_TransactionRequest.TransactionRequest, {
84
+ ...decoded,
85
+ feePayer: true,
86
+ })
87
+ expect(pending.feeToken).toBeUndefined()
88
+ expect(pending.feePayer).toBe(true)
89
+ })
90
+
47
91
  test('rejects an invalid request', () => {
48
92
  expect(
49
93
  z.safeDecode(z_TransactionRequest.TransactionRequest, {
@@ -6,7 +6,6 @@ export * as PoolId from './PoolId.js'
6
6
  export * as RpcSchemaTempo from './RpcSchemaTempo.js'
7
7
  export * as SignatureEnvelope from './SignatureEnvelope.js'
8
8
  export * as Tick from './Tick.js'
9
- export * as TokenId from './TokenId.js'
10
9
  export * as TokenRole from './TokenRole.js'
11
10
  export * as Transaction from './Transaction.js'
12
11
  export * as TransactionReceipt from './TransactionReceipt.js'
@@ -1,87 +0,0 @@
1
- import * as Address from '../core/Address.js';
2
- import * as Hex from '../core/Hex.js';
3
- export type TokenId = bigint;
4
- export type TokenIdOrAddress = TokenId | Address.Address;
5
- /**
6
- * Converts a token ID or address to a token ID.
7
- *
8
- * TIP-20 is Tempo's native token standard for stablecoins with deterministic addresses
9
- * derived from sequential token IDs (prefix `0x20c0`).
10
- *
11
- * [TIP-20 Token Standard](https://docs.tempo.xyz/protocol/tip20/overview)
12
- *
13
- * @example
14
- * ```ts twoslash
15
- * import { TokenId } from 'ox/tempo'
16
- *
17
- * const tokenId = TokenId.from(1n)
18
- * ```
19
- *
20
- * @param tokenIdOrAddress - The token ID or address.
21
- * @returns The token ID.
22
- */
23
- export declare function from(tokenIdOrAddress: TokenIdOrAddress | number): TokenId;
24
- /**
25
- * Converts a TIP-20 token address to a token ID.
26
- *
27
- * [TIP-20 Token Standard](https://docs.tempo.xyz/protocol/tip20/overview)
28
- *
29
- * @example
30
- * ```ts twoslash
31
- * import { TokenId } from 'ox/tempo'
32
- *
33
- * const tokenId = TokenId.fromAddress(
34
- * '0x20c0000000000000000000000000000000000001'
35
- * )
36
- * ```
37
- *
38
- * @param address - The token address.
39
- * @returns The token ID.
40
- */
41
- export declare function fromAddress(address: Address.Address): TokenId;
42
- /**
43
- * Converts a TIP-20 token ID to an address.
44
- *
45
- * [TIP-20 Token Standard](https://docs.tempo.xyz/protocol/tip20/overview)
46
- *
47
- * @example
48
- * ```ts twoslash
49
- * import { TokenId } from 'ox/tempo'
50
- *
51
- * const address = TokenId.toAddress(1n)
52
- * ```
53
- *
54
- * @param tokenId - The token ID.
55
- * @returns The address.
56
- */
57
- export declare function toAddress(tokenId: TokenIdOrAddress): Address.Address;
58
- /**
59
- * Computes a deterministic TIP-20 token address from a sender address and salt.
60
- *
61
- * The address is computed as: `TIP20_PREFIX (12 bytes) || keccak256(abi.encode(sender, salt))[:8]`
62
- *
63
- * [TIP-20 Token Standard](https://docs.tempo.xyz/protocol/tip20/overview)
64
- *
65
- * @example
66
- * ```ts twoslash
67
- * import { TokenId } from 'ox/tempo'
68
- *
69
- * const id = TokenId.compute({
70
- * sender: '0x1234567890123456789012345678901234567890',
71
- * salt: '0x0000000000000000000000000000000000000000000000000000000000000001'
72
- * })
73
- * ```
74
- *
75
- * @param value - The sender address and salt.
76
- * @returns The computed TIP-20 token id.
77
- */
78
- export declare function compute(value: compute.Value): bigint;
79
- export declare namespace compute {
80
- type Value = {
81
- /** The salt (32 bytes). */
82
- salt: Hex.Hex;
83
- /** The sender address. */
84
- sender: Address.Address;
85
- };
86
- }
87
- //# sourceMappingURL=TokenId.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TokenId.d.ts","sourceRoot":"","sources":["../../src/tempo/TokenId.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAA;AAE7C,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAA;AAIrC,MAAM,MAAM,OAAO,GAAG,MAAM,CAAA;AAC5B,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAA;AAExD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,MAAM,GAAG,OAAO,CAOzE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAiB7D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAQpE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,MAAM,CAapD;AAED,MAAM,CAAC,OAAO,WAAW,OAAO,CAAC;IAC/B,KAAY,KAAK,GAAG;QAClB,2BAA2B;QAC3B,IAAI,EAAE,GAAG,CAAC,GAAG,CAAA;QACb,0BAA0B;QAC1B,MAAM,EAAE,OAAO,CAAC,OAAO,CAAA;KACxB,CAAA;CACF"}
@@ -1,123 +0,0 @@
1
- import { keccak_256 } from '@noble/hashes/sha3.js';
2
- import * as Address from '../core/Address.js';
3
- import * as Bytes from '../core/Bytes.js';
4
- import * as Hex from '../core/Hex.js';
5
- const tip20Prefix = '0x20c0';
6
- /**
7
- * Converts a token ID or address to a token ID.
8
- *
9
- * TIP-20 is Tempo's native token standard for stablecoins with deterministic addresses
10
- * derived from sequential token IDs (prefix `0x20c0`).
11
- *
12
- * [TIP-20 Token Standard](https://docs.tempo.xyz/protocol/tip20/overview)
13
- *
14
- * @example
15
- * ```ts twoslash
16
- * import { TokenId } from 'ox/tempo'
17
- *
18
- * const tokenId = TokenId.from(1n)
19
- * ```
20
- *
21
- * @param tokenIdOrAddress - The token ID or address.
22
- * @returns The token ID.
23
- */
24
- export function from(tokenIdOrAddress) {
25
- if (typeof tokenIdOrAddress === 'bigint' ||
26
- typeof tokenIdOrAddress === 'number')
27
- return BigInt(tokenIdOrAddress);
28
- return fromAddress(tokenIdOrAddress);
29
- }
30
- /**
31
- * Converts a TIP-20 token address to a token ID.
32
- *
33
- * [TIP-20 Token Standard](https://docs.tempo.xyz/protocol/tip20/overview)
34
- *
35
- * @example
36
- * ```ts twoslash
37
- * import { TokenId } from 'ox/tempo'
38
- *
39
- * const tokenId = TokenId.fromAddress(
40
- * '0x20c0000000000000000000000000000000000001'
41
- * )
42
- * ```
43
- *
44
- * @param address - The token address.
45
- * @returns The token ID.
46
- */
47
- export function fromAddress(address) {
48
- const resolved = address;
49
- // The TIP-20 prefix check is case-insensitive, but most inputs are already
50
- // lowercase, so peek the prefix bytes before falling back to a full
51
- // `.toLowerCase()`.
52
- const c2 = resolved.charCodeAt(2);
53
- const c3 = resolved.charCodeAt(3);
54
- const c4 = resolved.charCodeAt(4);
55
- const c5 = resolved.charCodeAt(5);
56
- const isPrefix = c2 === 50 /* '2' */ &&
57
- c3 === 48 /* '0' */ &&
58
- (c4 === 99 || c4 === 67) /* 'c' or 'C' */ &&
59
- c5 === 48; /* '0' */
60
- if (!isPrefix)
61
- throw new Error('invalid tip20 address.');
62
- // The trailing 36 hex characters encode the token id big-endian.
63
- return BigInt(`0x${resolved.slice(tip20Prefix.length)}`);
64
- }
65
- /**
66
- * Converts a TIP-20 token ID to an address.
67
- *
68
- * [TIP-20 Token Standard](https://docs.tempo.xyz/protocol/tip20/overview)
69
- *
70
- * @example
71
- * ```ts twoslash
72
- * import { TokenId } from 'ox/tempo'
73
- *
74
- * const address = TokenId.toAddress(1n)
75
- * ```
76
- *
77
- * @param tokenId - The token ID.
78
- * @returns The address.
79
- */
80
- export function toAddress(tokenId) {
81
- if (typeof tokenId === 'string') {
82
- Address.assert(tokenId);
83
- return tokenId;
84
- }
85
- const tokenIdHex = Hex.fromNumber(tokenId, { size: 18 });
86
- return Hex.concat(tip20Prefix, tokenIdHex);
87
- }
88
- /**
89
- * Computes a deterministic TIP-20 token address from a sender address and salt.
90
- *
91
- * The address is computed as: `TIP20_PREFIX (12 bytes) || keccak256(abi.encode(sender, salt))[:8]`
92
- *
93
- * [TIP-20 Token Standard](https://docs.tempo.xyz/protocol/tip20/overview)
94
- *
95
- * @example
96
- * ```ts twoslash
97
- * import { TokenId } from 'ox/tempo'
98
- *
99
- * const id = TokenId.compute({
100
- * sender: '0x1234567890123456789012345678901234567890',
101
- * salt: '0x0000000000000000000000000000000000000000000000000000000000000001'
102
- * })
103
- * ```
104
- *
105
- * @param value - The sender address and salt.
106
- * @returns The computed TIP-20 token id.
107
- */
108
- export function compute(value) {
109
- // ABI encoding of (address, bytes32) is the 32-byte left-padded address
110
- // followed by the 32-byte salt. Build that 64-byte buffer directly and hash
111
- // it, instead of round-tripping through `AbiParameters.encode`.
112
- const buffer = new Uint8Array(64);
113
- const addressBytes = Bytes.fromHex(value.sender);
114
- buffer.set(addressBytes, 12);
115
- buffer.set(Bytes.fromHex(value.salt, { size: 32 }), 32);
116
- const hash = keccak_256(buffer);
117
- // First 8 bytes of the digest, big-endian.
118
- let id = 0n;
119
- for (let i = 0; i < 8; i++)
120
- id = (id << 8n) | BigInt(hash[i]);
121
- return id;
122
- }
123
- //# sourceMappingURL=TokenId.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TokenId.js","sourceRoot":"","sources":["../../src/tempo/TokenId.ts"],"names":[],"mappings":"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"}
@@ -1,6 +0,0 @@
1
- import * as z from 'zod/mini';
2
- /** TIP-20 token id schema (non-negative bigint). */
3
- export declare const TokenId: z.ZodMiniBigInt<bigint>;
4
- /** Codec decoding a TIP-20 token address into a token id. */
5
- export declare const address: z.ZodMiniCodec<z.ZodMiniTemplateLiteral<`0x${string}`>, z.ZodMiniBigInt<bigint>>;
6
- //# sourceMappingURL=TokenId.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TokenId.d.ts","sourceRoot":"","sources":["../../../src/zod/tempo/TokenId.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAE7B,oDAAoD;AACpD,eAAO,MAAM,OAAO,yBAE2C,CAAA;AAE/D,6DAA6D;AAC7D,eAAO,MAAM,OAAO,kFAGlB,CAAA"}
@@ -1,14 +0,0 @@
1
- /* eslint-disable jsdoc-js/require-jsdoc, jsdoc-js/require-description, jsdoc-js/require-example */
2
- import * as core_TokenId from '../../tempo/TokenId.js';
3
- import * as z_Address from '../Address.js';
4
- import * as z from 'zod/mini';
5
- /** TIP-20 token id schema (non-negative bigint). */
6
- export const TokenId = z
7
- .bigint()
8
- .check(z.refine((value) => value >= 0n, 'expected token id'));
9
- /** Codec decoding a TIP-20 token address into a token id. */
10
- export const address = z.codec(z_Address.Address, TokenId, {
11
- decode: (value) => core_TokenId.fromAddress(value),
12
- encode: (value) => core_TokenId.toAddress(value),
13
- });
14
- //# sourceMappingURL=TokenId.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TokenId.js","sourceRoot":"","sources":["../../../src/zod/tempo/TokenId.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,OAAO,KAAK,YAAY,MAAM,wBAAwB,CAAA;AACtD,OAAO,KAAK,SAAS,MAAM,eAAe,CAAA;AAC1C,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAE7B,oDAAoD;AACpD,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC;KACrB,MAAM,EAAE;KACR,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAA;AAE/D,6DAA6D;AAC7D,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE;IACzD,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,CAAC;IAClD,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC;CACjD,CAAC,CAAA"}
@@ -1,36 +0,0 @@
1
- import { bench, describe } from 'vp/test'
2
- import * as TokenId from './TokenId.js'
3
-
4
- const sender = '0x1234567890123456789012345678901234567890' as const
5
- const salt =
6
- '0x0000000000000000000000000000000000000000000000000000000000000001' as const
7
-
8
- const tokenIdAddress = '0x20c0000000000000000000000000000000000001' as const
9
- const tokenIdBigInt = 1n
10
- const tokenIdLargeBigInt = 0xdeadbeefcafebabe1234n
11
-
12
- describe('TokenId.compute', () => {
13
- bench('hex sender', () => {
14
- TokenId.compute({ sender, salt })
15
- })
16
- })
17
-
18
- describe('TokenId.fromAddress', () => {
19
- bench('hex address', () => {
20
- TokenId.fromAddress(tokenIdAddress)
21
- })
22
- })
23
-
24
- describe('TokenId.toAddress', () => {
25
- bench('small bigint', () => {
26
- TokenId.toAddress(tokenIdBigInt)
27
- })
28
-
29
- bench('large bigint', () => {
30
- TokenId.toAddress(tokenIdLargeBigInt)
31
- })
32
-
33
- bench('hex address passthrough', () => {
34
- TokenId.toAddress(tokenIdAddress)
35
- })
36
- })
@@ -1,79 +0,0 @@
1
- import { Hex } from 'ox'
2
- import { TokenId } from 'ox/tempo'
3
- import { expect, test } from 'vp/test'
4
-
5
- test('from', () => {
6
- expect(TokenId.from(0n)).toBe(0n)
7
- expect(TokenId.from(0x1)).toBe(1n)
8
- expect(TokenId.from(0xdef)).toBe(0xdefn)
9
- expect(TokenId.from('0x20c0000000000000000000000000000000000000')).toBe(0n)
10
- expect(TokenId.from('0x20c0000000000000000000000000000000000001')).toBe(1n)
11
- expect(TokenId.from('0x20c0000000000000000000000000000000000def')).toBe(
12
- 0xdefn,
13
- )
14
- })
15
-
16
- test('fromAddress', () => {
17
- expect(
18
- TokenId.fromAddress('0x20c0000000000000000000000000000000000000'),
19
- ).toBe(0n)
20
- expect(
21
- TokenId.fromAddress('0x20c0000000000000000000000000000000000001'),
22
- ).toBe(1n)
23
- expect(
24
- TokenId.fromAddress('0x20c0000000000000000000000000000000000def'),
25
- ).toBe(0xdefn)
26
- })
27
-
28
- test('toAddress', () => {
29
- expect(TokenId.toAddress(0n)).toBe(
30
- '0x20c0000000000000000000000000000000000000',
31
- )
32
- expect(TokenId.toAddress('0x20c0000000000000000000000000000000000000')).toBe(
33
- '0x20c0000000000000000000000000000000000000',
34
- )
35
- expect(TokenId.toAddress(1n)).toBe(
36
- '0x20c0000000000000000000000000000000000001',
37
- )
38
- expect(TokenId.toAddress(0xdefn)).toBe(
39
- '0x20c0000000000000000000000000000000000def',
40
- )
41
- })
42
-
43
- test('compute', () => {
44
- const sender = '0x1234567890123456789012345678901234567890'
45
- const salt1 =
46
- '0x0000000000000000000000000000000000000000000000000000000000000001'
47
- const salt2 =
48
- '0x0000000000000000000000000000000000000000000000000000000000000002'
49
-
50
- const id1 = TokenId.compute({ sender, salt: salt1 })
51
- const id2 = TokenId.compute({ sender, salt: salt2 })
52
- const address1 = TokenId.toAddress(id1)
53
- const address2 = TokenId.toAddress(id2)
54
-
55
- // deterministic: same inputs produce same output
56
- expect(TokenId.compute({ sender, salt: salt1 })).toBe(id1)
57
-
58
- // different salts produce different addresses
59
- expect(address1).not.toBe(address2)
60
-
61
- // address suffix matches id
62
- expect(Hex.slice(address1, 12)).toBe(Hex.fromNumber(id1, { size: 8 }))
63
-
64
- // addresses have TIP-20 prefix (0x20c0 followed by zeroes for 12 bytes total)
65
- expect(address1.toLowerCase().startsWith('0x20c000000000000000000000')).toBe(
66
- true,
67
- )
68
- expect(address2.toLowerCase().startsWith('0x20c000000000000000000000')).toBe(
69
- true,
70
- )
71
-
72
- // addresses are 20 bytes (40 hex chars + 0x prefix)
73
- expect(address1.length).toBe(42)
74
-
75
- // different senders produce different addresses
76
- const otherSender = '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd'
77
- const address3 = TokenId.compute({ sender: otherSender, salt: salt1 })
78
- expect(address3).not.toBe(address1)
79
- })