ox 0.13.1 → 0.13.2
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.
- package/Base32/package.json +6 -0
- package/CHANGELOG.md +6 -0
- package/CompactSize/package.json +6 -0
- package/_cjs/core/Base32.js +73 -0
- package/_cjs/core/Base32.js.map +1 -0
- package/_cjs/core/CompactSize.js +91 -0
- package/_cjs/core/CompactSize.js.map +1 -0
- package/_cjs/index.js +4 -2
- package/_cjs/index.js.map +1 -1
- package/_cjs/tempo/TempoAddress.js +116 -0
- package/_cjs/tempo/TempoAddress.js.map +1 -0
- package/_cjs/tempo/index.js +2 -1
- package/_cjs/tempo/index.js.map +1 -1
- package/_cjs/version.js +1 -1
- package/_esm/core/Base32.js +119 -0
- package/_esm/core/Base32.js.map +1 -0
- package/_esm/core/CompactSize.js +150 -0
- package/_esm/core/CompactSize.js.map +1 -0
- package/_esm/index.js +48 -0
- package/_esm/index.js.map +1 -1
- package/_esm/tempo/TempoAddress.js +181 -0
- package/_esm/tempo/TempoAddress.js.map +1 -0
- package/_esm/tempo/index.js +21 -0
- package/_esm/tempo/index.js.map +1 -1
- package/_esm/version.js +1 -1
- package/_types/core/Base32.d.ts +79 -0
- package/_types/core/Base32.d.ts.map +1 -0
- package/_types/core/CompactSize.d.ts +107 -0
- package/_types/core/CompactSize.d.ts.map +1 -0
- package/_types/index.d.ts +48 -0
- package/_types/index.d.ts.map +1 -1
- package/_types/tempo/TempoAddress.d.ts +118 -0
- package/_types/tempo/TempoAddress.d.ts.map +1 -0
- package/_types/tempo/index.d.ts +21 -0
- package/_types/tempo/index.d.ts.map +1 -1
- package/_types/version.d.ts +1 -1
- package/core/Base32.ts +134 -0
- package/core/CompactSize.ts +169 -0
- package/index.ts +51 -0
- package/package.json +16 -1
- package/tempo/TempoAddress/package.json +6 -0
- package/tempo/TempoAddress.test.ts +202 -0
- package/tempo/TempoAddress.ts +225 -0
- package/tempo/index.ts +21 -3
- package/version.ts +1 -1
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { Address } from 'ox'
|
|
2
|
+
import { TempoAddress } from 'ox/tempo'
|
|
3
|
+
import { describe, expect, test } from 'vitest'
|
|
4
|
+
|
|
5
|
+
const rawAddress = Address.checksum(
|
|
6
|
+
'0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28',
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
describe('format', () => {
|
|
10
|
+
test('mainnet address', () => {
|
|
11
|
+
expect(TempoAddress.format(rawAddress)).toMatchInlineSnapshot(
|
|
12
|
+
`"tempo1wskntnrxxnq9x2f95wuyf0y7wk2l90fg8zd8djs"`,
|
|
13
|
+
)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('zone address (zone ID = 1)', () => {
|
|
17
|
+
expect(
|
|
18
|
+
TempoAddress.format(rawAddress, { zoneId: 1 }),
|
|
19
|
+
).toMatchInlineSnapshot(`"tempoz1q96z6dwvvc6vq5efyk3ms39une6etu4a9zeqtx3q"`)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('zone address (zone ID = 252)', () => {
|
|
23
|
+
expect(
|
|
24
|
+
TempoAddress.format(rawAddress, { zoneId: 252 }),
|
|
25
|
+
).toMatchInlineSnapshot(`"tempoz1l36z6dwvvc6vq5efyk3ms39une6etu4a9z8vgw44"`)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('zone address (zone ID = 253)', () => {
|
|
29
|
+
expect(
|
|
30
|
+
TempoAddress.format(rawAddress, { zoneId: 253 }),
|
|
31
|
+
).toMatchInlineSnapshot(
|
|
32
|
+
`"tempoz1lh7sqapdxhxxvdxq2v5jtgacgj7fuav4727jsx0032us"`,
|
|
33
|
+
)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('zone address (zone ID = 65535)', () => {
|
|
37
|
+
expect(
|
|
38
|
+
TempoAddress.format(rawAddress, { zoneId: 65535 }),
|
|
39
|
+
).toMatchInlineSnapshot(
|
|
40
|
+
`"tempoz1lhll7apdxhxxvdxq2v5jtgacgj7fuav4727j37cldu7q"`,
|
|
41
|
+
)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('zone address (zone ID = 65536)', () => {
|
|
45
|
+
expect(
|
|
46
|
+
TempoAddress.format(rawAddress, { zoneId: 65536 }),
|
|
47
|
+
).toMatchInlineSnapshot(
|
|
48
|
+
`"tempoz1lcqqqqgqwskntnrxxnq9x2f95wuyf0y7wk2l90fga965qjc"`,
|
|
49
|
+
)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('zone address (zone ID = 4294967295)', () => {
|
|
53
|
+
expect(
|
|
54
|
+
TempoAddress.format(rawAddress, { zoneId: 4294967295 }),
|
|
55
|
+
).toMatchInlineSnapshot(
|
|
56
|
+
`"tempoz1lmllllllwskntnrxxnq9x2f95wuyf0y7wk2l90fgxg58ulq"`,
|
|
57
|
+
)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('zone address (zone ID > 4294967295)', () => {
|
|
61
|
+
expect(
|
|
62
|
+
TempoAddress.format(rawAddress, { zoneId: BigInt('4294967296') }),
|
|
63
|
+
).toMatchInlineSnapshot(
|
|
64
|
+
`"tempoz1luqqqqqqqyqqqqr5956uce35cpfjjfdrhpzte8n4jhet62pnyj7cc"`,
|
|
65
|
+
)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('lowercase output', () => {
|
|
69
|
+
const result = TempoAddress.format(rawAddress)
|
|
70
|
+
expect(result).toBe(result.toLowerCase())
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
describe('parse', () => {
|
|
75
|
+
test('mainnet', () => {
|
|
76
|
+
const encoded = TempoAddress.format(rawAddress)
|
|
77
|
+
expect(TempoAddress.parse(encoded)).toMatchInlineSnapshot(`
|
|
78
|
+
{
|
|
79
|
+
"address": "0x742d35CC6634c0532925a3B844bc9e7595F2Bd28",
|
|
80
|
+
"zoneId": undefined,
|
|
81
|
+
}
|
|
82
|
+
`)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test('zone (zone ID = 1)', () => {
|
|
86
|
+
const encoded = TempoAddress.format(rawAddress, { zoneId: 1 })
|
|
87
|
+
expect(TempoAddress.parse(encoded)).toMatchInlineSnapshot(`
|
|
88
|
+
{
|
|
89
|
+
"address": "0x742d35CC6634c0532925a3B844bc9e7595F2Bd28",
|
|
90
|
+
"zoneId": 1n,
|
|
91
|
+
}
|
|
92
|
+
`)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
test('zone (zone ID = 252)', () => {
|
|
96
|
+
const encoded = TempoAddress.format(rawAddress, { zoneId: 252 })
|
|
97
|
+
expect(TempoAddress.parse(encoded)).toMatchInlineSnapshot(`
|
|
98
|
+
{
|
|
99
|
+
"address": "0x742d35CC6634c0532925a3B844bc9e7595F2Bd28",
|
|
100
|
+
"zoneId": 252n,
|
|
101
|
+
}
|
|
102
|
+
`)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test('zone (zone ID = 253)', () => {
|
|
106
|
+
const encoded = TempoAddress.format(rawAddress, { zoneId: 253 })
|
|
107
|
+
expect(TempoAddress.parse(encoded)).toMatchInlineSnapshot(`
|
|
108
|
+
{
|
|
109
|
+
"address": "0x742d35CC6634c0532925a3B844bc9e7595F2Bd28",
|
|
110
|
+
"zoneId": 253n,
|
|
111
|
+
}
|
|
112
|
+
`)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
test('zone (zone ID = 65535)', () => {
|
|
116
|
+
const encoded = TempoAddress.format(rawAddress, { zoneId: 65535 })
|
|
117
|
+
expect(TempoAddress.parse(encoded)).toMatchInlineSnapshot(`
|
|
118
|
+
{
|
|
119
|
+
"address": "0x742d35CC6634c0532925a3B844bc9e7595F2Bd28",
|
|
120
|
+
"zoneId": 65535n,
|
|
121
|
+
}
|
|
122
|
+
`)
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
test('zone (zone ID = 65536)', () => {
|
|
126
|
+
const encoded = TempoAddress.format(rawAddress, { zoneId: 65536 })
|
|
127
|
+
expect(TempoAddress.parse(encoded)).toMatchInlineSnapshot(`
|
|
128
|
+
{
|
|
129
|
+
"address": "0x742d35CC6634c0532925a3B844bc9e7595F2Bd28",
|
|
130
|
+
"zoneId": 65536n,
|
|
131
|
+
}
|
|
132
|
+
`)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
test('zone (large zone ID)', () => {
|
|
136
|
+
const encoded = TempoAddress.format(rawAddress, {
|
|
137
|
+
zoneId: BigInt('18446744073709551615'),
|
|
138
|
+
})
|
|
139
|
+
expect(TempoAddress.parse(encoded)).toMatchInlineSnapshot(`
|
|
140
|
+
{
|
|
141
|
+
"address": "0x742d35CC6634c0532925a3B844bc9e7595F2Bd28",
|
|
142
|
+
"zoneId": 18446744073709551615n,
|
|
143
|
+
}
|
|
144
|
+
`)
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
test('case insensitive', () => {
|
|
148
|
+
const encoded = TempoAddress.format(rawAddress)
|
|
149
|
+
const upper = encoded.slice(0, 6) + encoded.slice(6).toUpperCase()
|
|
150
|
+
expect(TempoAddress.parse(upper).address).toBe(rawAddress)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
test('error: invalid prefix', () => {
|
|
154
|
+
expect(() =>
|
|
155
|
+
TempoAddress.parse('bitcoin1abc'),
|
|
156
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
157
|
+
`[TempoAddress.InvalidPrefixError: Tempo address "bitcoin1abc" has an invalid prefix. Expected "tempo1" or "tempoz1".]`,
|
|
158
|
+
)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
test('error: invalid checksum', () => {
|
|
162
|
+
const encoded = TempoAddress.format(rawAddress)
|
|
163
|
+
const tampered = encoded.slice(0, -1) + (encoded.endsWith('q') ? 'p' : 'q')
|
|
164
|
+
expect(() =>
|
|
165
|
+
TempoAddress.parse(tampered),
|
|
166
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
167
|
+
`[TempoAddress.InvalidChecksumError: Tempo address "${tampered}" has an invalid checksum.]`,
|
|
168
|
+
)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
test('error: prefix swap detected', () => {
|
|
172
|
+
const mainnet = TempoAddress.format(rawAddress)
|
|
173
|
+
const swapped = 'tempoz1' + mainnet.slice(6)
|
|
174
|
+
expect(() =>
|
|
175
|
+
TempoAddress.parse(swapped),
|
|
176
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
177
|
+
`[TempoAddress.InvalidLengthError: Tempo address "${swapped}" has an invalid payload length. Expected 24 bytes, got 23.]`,
|
|
178
|
+
)
|
|
179
|
+
})
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
describe('validate', () => {
|
|
183
|
+
test('valid mainnet address', () => {
|
|
184
|
+
const encoded = TempoAddress.format(rawAddress)
|
|
185
|
+
expect(TempoAddress.validate(encoded)).toMatchInlineSnapshot(`true`)
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
test('valid zone address', () => {
|
|
189
|
+
const encoded = TempoAddress.format(rawAddress, { zoneId: 1 })
|
|
190
|
+
expect(TempoAddress.validate(encoded)).toMatchInlineSnapshot(`true`)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
test('invalid address', () => {
|
|
194
|
+
expect(TempoAddress.validate('invalid')).toMatchInlineSnapshot(`false`)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
test('tampered address', () => {
|
|
198
|
+
const encoded = TempoAddress.format(rawAddress)
|
|
199
|
+
const tampered = encoded.slice(0, -1) + (encoded.endsWith('q') ? 'p' : 'q')
|
|
200
|
+
expect(TempoAddress.validate(tampered)).toMatchInlineSnapshot(`false`)
|
|
201
|
+
})
|
|
202
|
+
})
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import * as Address from '../core/Address.js'
|
|
2
|
+
import * as Base32 from '../core/Base32.js'
|
|
3
|
+
import * as Bytes from '../core/Bytes.js'
|
|
4
|
+
import * as CompactSize from '../core/CompactSize.js'
|
|
5
|
+
import * as Errors from '../core/Errors.js'
|
|
6
|
+
import * as Hash from '../core/Hash.js'
|
|
7
|
+
import * as Hex from '../core/Hex.js'
|
|
8
|
+
|
|
9
|
+
/** Root type for a Tempo Address. */
|
|
10
|
+
export type TempoAddress = `tempo1${string}` | `tempoz1${string}`
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Formats a raw Ethereum address (and optional zone ID) into a Tempo address string.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts twoslash
|
|
17
|
+
* import { TempoAddress } from 'ox/tempo'
|
|
18
|
+
*
|
|
19
|
+
* const address = TempoAddress.format('0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28')
|
|
20
|
+
* // @log: 'tempo1wskntnrxxnq9x2f95wuyf0y7wk2l90fg8zd8djs'
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ### Zone Address
|
|
25
|
+
* ```ts twoslash
|
|
26
|
+
* import { TempoAddress } from 'ox/tempo'
|
|
27
|
+
*
|
|
28
|
+
* const address = TempoAddress.format(
|
|
29
|
+
* '0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28',
|
|
30
|
+
* { zoneId: 1 },
|
|
31
|
+
* )
|
|
32
|
+
* // @log: 'tempoz1q96z6dwvvc6vq5efyk3ms39une6etu4a9zeqtx3q'
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @param address - The raw 20-byte Ethereum address.
|
|
36
|
+
* @param options - Options.
|
|
37
|
+
* @returns The encoded Tempo address string.
|
|
38
|
+
*/
|
|
39
|
+
export function format(
|
|
40
|
+
address: Address.Address,
|
|
41
|
+
options: format.Options = {},
|
|
42
|
+
): TempoAddress {
|
|
43
|
+
const { zoneId } = options
|
|
44
|
+
|
|
45
|
+
const prefix = zoneId != null ? 'tempoz1' : 'tempo1'
|
|
46
|
+
const zone = zoneId != null ? CompactSize.toBytes(zoneId) : new Uint8Array()
|
|
47
|
+
const address_bytes = Bytes.fromHex(address)
|
|
48
|
+
|
|
49
|
+
const input = Bytes.concat(Bytes.fromString(prefix), zone, address_bytes)
|
|
50
|
+
const checksum = Hash.sha256(Hash.sha256(input, { as: 'Bytes' }), {
|
|
51
|
+
as: 'Bytes',
|
|
52
|
+
}).slice(0, 4)
|
|
53
|
+
|
|
54
|
+
const payload = Bytes.concat(zone, address_bytes, checksum)
|
|
55
|
+
return `${prefix}${Base32.fromBytes(payload)}` as TempoAddress
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export declare namespace format {
|
|
59
|
+
type Options = {
|
|
60
|
+
/** Zone ID for zone addresses. */
|
|
61
|
+
zoneId?: bigint | number | undefined
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
type ErrorType = Errors.GlobalErrorType
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Parses a Tempo address string into a raw Ethereum address and optional zone ID.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ### Mainnet Address
|
|
72
|
+
* ```ts twoslash
|
|
73
|
+
* import { TempoAddress } from 'ox/tempo'
|
|
74
|
+
*
|
|
75
|
+
* const result = TempoAddress.parse(
|
|
76
|
+
* 'tempo1wst8d6qejxtdg4y5r3zarvary0c5xw7kvmgh8pm',
|
|
77
|
+
* )
|
|
78
|
+
* // { address: '0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28' }
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ### Zone Address
|
|
83
|
+
* ```ts twoslash
|
|
84
|
+
* import { TempoAddress } from 'ox/tempo'
|
|
85
|
+
*
|
|
86
|
+
* const result = TempoAddress.parse(
|
|
87
|
+
* 'tempoz1qwst8d6qejxtdg4y5r3zarvary0c5xw7kvmgh8pm',
|
|
88
|
+
* )
|
|
89
|
+
* // { address: '0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28', zoneId: 1 }
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* @param tempoAddress - The Tempo address string to parse.
|
|
93
|
+
* @returns The parsed raw address and optional zone ID.
|
|
94
|
+
*/
|
|
95
|
+
export function parse(tempoAddress: string): parse.ReturnType {
|
|
96
|
+
const lower = tempoAddress.toLowerCase()
|
|
97
|
+
|
|
98
|
+
let prefix: string
|
|
99
|
+
let hasZone: boolean
|
|
100
|
+
if (lower.startsWith('tempoz1')) {
|
|
101
|
+
prefix = 'tempoz1'
|
|
102
|
+
hasZone = true
|
|
103
|
+
} else if (lower.startsWith('tempo1')) {
|
|
104
|
+
prefix = 'tempo1'
|
|
105
|
+
hasZone = false
|
|
106
|
+
} else {
|
|
107
|
+
throw new InvalidPrefixError({ address: tempoAddress })
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const payload = Base32.toBytes(lower.slice(prefix.length))
|
|
111
|
+
|
|
112
|
+
let zoneId: bigint | undefined
|
|
113
|
+
let remaining: Uint8Array
|
|
114
|
+
if (hasZone) {
|
|
115
|
+
const { value, size } = CompactSize.fromBytes(payload)
|
|
116
|
+
zoneId = value
|
|
117
|
+
remaining = payload.slice(size)
|
|
118
|
+
} else {
|
|
119
|
+
zoneId = undefined
|
|
120
|
+
remaining = payload
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (remaining.length !== 24)
|
|
124
|
+
throw new InvalidLengthError({
|
|
125
|
+
address: tempoAddress,
|
|
126
|
+
expected: 24,
|
|
127
|
+
actual: remaining.length,
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
const rawAddress = remaining.slice(0, 20)
|
|
131
|
+
const checksum = remaining.slice(20, 24)
|
|
132
|
+
|
|
133
|
+
const zoneBytes =
|
|
134
|
+
zoneId != null ? CompactSize.toBytes(zoneId) : new Uint8Array()
|
|
135
|
+
const checksumInput = Bytes.concat(
|
|
136
|
+
Bytes.fromString(prefix),
|
|
137
|
+
zoneBytes,
|
|
138
|
+
rawAddress,
|
|
139
|
+
)
|
|
140
|
+
const expected = Hash.sha256(Hash.sha256(checksumInput, { as: 'Bytes' }), {
|
|
141
|
+
as: 'Bytes',
|
|
142
|
+
}).slice(0, 4)
|
|
143
|
+
|
|
144
|
+
if (!Bytes.isEqual(checksum, expected))
|
|
145
|
+
throw new InvalidChecksumError({ address: tempoAddress })
|
|
146
|
+
|
|
147
|
+
const address = Address.checksum(Hex.fromBytes(rawAddress) as Address.Address)
|
|
148
|
+
|
|
149
|
+
return { address, zoneId }
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export declare namespace parse {
|
|
153
|
+
type ReturnType = {
|
|
154
|
+
/** The raw 20-byte Ethereum address. */
|
|
155
|
+
address: Address.Address
|
|
156
|
+
/** The zone ID, or `undefined` for mainnet addresses. */
|
|
157
|
+
zoneId: bigint | undefined
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
type ErrorType =
|
|
161
|
+
| InvalidPrefixError
|
|
162
|
+
| InvalidLengthError
|
|
163
|
+
| InvalidChecksumError
|
|
164
|
+
| Errors.GlobalErrorType
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Validates a Tempo address string.
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```ts twoslash
|
|
172
|
+
* import { TempoAddress } from 'ox/tempo'
|
|
173
|
+
*
|
|
174
|
+
* const valid = TempoAddress.validate(
|
|
175
|
+
* 'tempo1wst8d6qejxtdg4y5r3zarvary0c5xw7kvmgh8pm',
|
|
176
|
+
* )
|
|
177
|
+
* // true
|
|
178
|
+
* ```
|
|
179
|
+
*
|
|
180
|
+
* @param tempoAddress - The Tempo address string to validate.
|
|
181
|
+
* @returns Whether the address is valid.
|
|
182
|
+
*/
|
|
183
|
+
export function validate(tempoAddress: string): boolean {
|
|
184
|
+
try {
|
|
185
|
+
parse(tempoAddress)
|
|
186
|
+
return true
|
|
187
|
+
} catch {
|
|
188
|
+
return false
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Thrown when a Tempo address has an invalid prefix. */
|
|
193
|
+
export class InvalidPrefixError extends Errors.BaseError {
|
|
194
|
+
override readonly name = 'TempoAddress.InvalidPrefixError'
|
|
195
|
+
|
|
196
|
+
constructor({ address }: { address: string }) {
|
|
197
|
+
super(
|
|
198
|
+
`Tempo address "${address}" has an invalid prefix. Expected "tempo1" or "tempoz1".`,
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Thrown when a Tempo address has an invalid payload length. */
|
|
204
|
+
export class InvalidLengthError extends Errors.BaseError {
|
|
205
|
+
override readonly name = 'TempoAddress.InvalidLengthError'
|
|
206
|
+
|
|
207
|
+
constructor({
|
|
208
|
+
address,
|
|
209
|
+
expected,
|
|
210
|
+
actual,
|
|
211
|
+
}: { address: string; expected: number; actual: number }) {
|
|
212
|
+
super(
|
|
213
|
+
`Tempo address "${address}" has an invalid payload length. Expected ${expected} bytes, got ${actual}.`,
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** Thrown when a Tempo address has an invalid checksum. */
|
|
219
|
+
export class InvalidChecksumError extends Errors.BaseError {
|
|
220
|
+
override readonly name = 'TempoAddress.InvalidChecksumError'
|
|
221
|
+
|
|
222
|
+
constructor({ address }: { address: string }) {
|
|
223
|
+
super(`Tempo address "${address}" has an invalid checksum.`)
|
|
224
|
+
}
|
|
225
|
+
}
|
package/tempo/index.ts
CHANGED
|
@@ -120,7 +120,27 @@ export * as PoolId from './PoolId.js'
|
|
|
120
120
|
* @category Reference
|
|
121
121
|
*/
|
|
122
122
|
export * as SignatureEnvelope from './SignatureEnvelope.js'
|
|
123
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Tempo address encoding/decoding utilities for human-readable addresses.
|
|
125
|
+
*
|
|
126
|
+
* Tempo addresses use a bech32 base32-encoded format with `tempo1` prefix for mainnet
|
|
127
|
+
* and `tempoz1` prefix for zone addresses. Includes CompactSize zone ID encoding
|
|
128
|
+
* and double-SHA256 checksumming.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts twoslash
|
|
132
|
+
* import { TempoAddress } from 'ox/tempo'
|
|
133
|
+
*
|
|
134
|
+
* const encoded = TempoAddress.format('0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28')
|
|
135
|
+
* // @log: 'tempo1wskntnrxxnq9x2f95wuyf0y7wk2l90fg8zd8djs'
|
|
136
|
+
*
|
|
137
|
+
* const { address, zoneId } = TempoAddress.parse(encoded)
|
|
138
|
+
* // @log: { address: '0x742d35CC6634c0532925a3B844bc9e7595F2Bd28' }
|
|
139
|
+
* ```
|
|
140
|
+
*
|
|
141
|
+
* @category Reference
|
|
142
|
+
*/
|
|
143
|
+
export * as TempoAddress from './TempoAddress.js'
|
|
124
144
|
/**
|
|
125
145
|
* Tick-based pricing utilities for DEX price conversions.
|
|
126
146
|
*
|
|
@@ -141,7 +161,6 @@ export * as SignatureEnvelope from './SignatureEnvelope.js'
|
|
|
141
161
|
* @category Reference
|
|
142
162
|
*/
|
|
143
163
|
export * as Tick from './Tick.js'
|
|
144
|
-
|
|
145
164
|
/**
|
|
146
165
|
* TIP-20 token ID utilities for converting between token IDs and addresses.
|
|
147
166
|
*
|
|
@@ -163,7 +182,6 @@ export * as Tick from './Tick.js'
|
|
|
163
182
|
* @category Reference
|
|
164
183
|
*/
|
|
165
184
|
export * as TokenId from './TokenId.js'
|
|
166
|
-
|
|
167
185
|
/**
|
|
168
186
|
* Token role utilities for serializing role identifiers to keccak256 hashes.
|
|
169
187
|
*
|
package/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** @internal */
|
|
2
|
-
export const version = '0.13.
|
|
2
|
+
export const version = '0.13.2'
|