tempo.ts 0.0.0 → 0.0.1
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/README.md +92 -0
- package/dist/chains.d.ts +1477 -0
- package/dist/chains.d.ts.map +1 -0
- package/dist/chains.js +43 -0
- package/dist/chains.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/types.d.ts +284 -0
- package/dist/internal/types.d.ts.map +1 -0
- package/dist/internal/types.js +2 -0
- package/dist/internal/types.js.map +1 -0
- package/dist/ox/TokenId.d.ts +18 -0
- package/dist/ox/TokenId.d.ts.map +1 -0
- package/dist/ox/TokenId.js +29 -0
- package/dist/ox/TokenId.js.map +1 -0
- package/dist/ox/TokenRole.d.ts +11 -0
- package/dist/ox/TokenRole.d.ts.map +1 -0
- package/dist/ox/TokenRole.js +22 -0
- package/dist/ox/TokenRole.js.map +1 -0
- package/dist/ox/Transaction.d.ts +161 -0
- package/dist/ox/Transaction.d.ts.map +1 -0
- package/dist/ox/Transaction.js +117 -0
- package/dist/ox/Transaction.js.map +1 -0
- package/dist/ox/TransactionEnvelopeFeeToken.d.ts +393 -0
- package/dist/ox/TransactionEnvelopeFeeToken.d.ts.map +1 -0
- package/dist/ox/TransactionEnvelopeFeeToken.js +452 -0
- package/dist/ox/TransactionEnvelopeFeeToken.js.map +1 -0
- package/dist/ox/TransactionRequest.d.ts +62 -0
- package/dist/ox/TransactionRequest.d.ts.map +1 -0
- package/dist/ox/TransactionRequest.js +66 -0
- package/dist/ox/TransactionRequest.js.map +1 -0
- package/dist/ox/index.d.ts +5 -0
- package/dist/ox/index.d.ts.map +1 -0
- package/dist/ox/index.js +5 -0
- package/dist/ox/index.js.map +1 -0
- package/dist/prool/Instance.d.ts +92 -0
- package/dist/prool/Instance.d.ts.map +1 -0
- package/dist/prool/Instance.js +96 -0
- package/dist/prool/Instance.js.map +1 -0
- package/dist/prool/index.d.ts +2 -0
- package/dist/prool/index.d.ts.map +1 -0
- package/dist/prool/index.js +2 -0
- package/dist/prool/index.js.map +1 -0
- package/dist/viem/abis.d.ts +2058 -0
- package/dist/viem/abis.d.ts.map +1 -0
- package/dist/viem/abis.js +1599 -0
- package/dist/viem/abis.js.map +1 -0
- package/dist/viem/actions/amm.d.ts +2091 -0
- package/dist/viem/actions/amm.d.ts.map +1 -0
- package/dist/viem/actions/amm.js +876 -0
- package/dist/viem/actions/amm.js.map +1 -0
- package/dist/viem/actions/fee.d.ts +727 -0
- package/dist/viem/actions/fee.d.ts.map +1 -0
- package/dist/viem/actions/fee.js +230 -0
- package/dist/viem/actions/fee.js.map +1 -0
- package/dist/viem/actions/index.d.ts +5 -0
- package/dist/viem/actions/index.d.ts.map +1 -0
- package/dist/viem/actions/index.js +5 -0
- package/dist/viem/actions/index.js.map +1 -0
- package/dist/viem/actions/policy.d.ts +1900 -0
- package/dist/viem/actions/policy.d.ts.map +1 -0
- package/dist/viem/actions/policy.js +841 -0
- package/dist/viem/actions/policy.js.map +1 -0
- package/dist/viem/actions/token.d.ts +13759 -0
- package/dist/viem/actions/token.d.ts.map +1 -0
- package/dist/viem/actions/token.js +2579 -0
- package/dist/viem/actions/token.js.map +1 -0
- package/dist/viem/addresses.d.ts +8 -0
- package/dist/viem/addresses.d.ts.map +1 -0
- package/dist/viem/addresses.js +8 -0
- package/dist/viem/addresses.js.map +1 -0
- package/dist/viem/chain.d.ts +341 -0
- package/dist/viem/chain.d.ts.map +1 -0
- package/dist/viem/chain.js +22 -0
- package/dist/viem/chain.js.map +1 -0
- package/dist/viem/client.d.ts +27 -0
- package/dist/viem/client.d.ts.map +1 -0
- package/dist/viem/client.js +28 -0
- package/dist/viem/client.js.map +1 -0
- package/dist/viem/decorator.d.ts +1636 -0
- package/dist/viem/decorator.d.ts.map +1 -0
- package/dist/viem/decorator.js +95 -0
- package/dist/viem/decorator.js.map +1 -0
- package/dist/viem/formatters.d.ts +4 -0
- package/dist/viem/formatters.d.ts.map +1 -0
- package/dist/viem/formatters.js +69 -0
- package/dist/viem/formatters.js.map +1 -0
- package/dist/viem/index.d.ts +9 -0
- package/dist/viem/index.d.ts.map +1 -0
- package/dist/viem/index.js +9 -0
- package/dist/viem/index.js.map +1 -0
- package/dist/viem/transaction.d.ts +54 -0
- package/dist/viem/transaction.d.ts.map +1 -0
- package/dist/viem/transaction.js +108 -0
- package/dist/viem/transaction.js.map +1 -0
- package/dist/viem/transport.d.ts +16 -0
- package/dist/viem/transport.d.ts.map +1 -0
- package/dist/viem/transport.js +33 -0
- package/dist/viem/transport.js.map +1 -0
- package/dist/viem/types.d.ts +10 -0
- package/dist/viem/types.d.ts.map +1 -0
- package/dist/viem/types.js +2 -0
- package/dist/viem/types.js.map +1 -0
- package/dist/viem/utils.d.ts +8 -0
- package/dist/viem/utils.d.ts.map +1 -0
- package/dist/viem/utils.js +9 -0
- package/dist/viem/utils.js.map +1 -0
- package/package.json +100 -2
- package/src/chains.ts +46 -0
- package/src/index.ts +1 -0
- package/src/internal/types.ts +414 -0
- package/src/ox/TokenId.test.ts +29 -0
- package/src/ox/TokenId.ts +35 -0
- package/src/ox/TokenRole.test.ts +20 -0
- package/src/ox/TokenRole.ts +27 -0
- package/src/ox/Transaction.test.ts +257 -0
- package/src/ox/Transaction.ts +247 -0
- package/src/ox/TransactionEnvelopeFeeToken.test.ts +1215 -0
- package/src/ox/TransactionEnvelopeFeeToken.ts +717 -0
- package/src/ox/TransactionRequest.ts +100 -0
- package/src/ox/index.ts +4 -0
- package/src/prool/Instance.test.ts +43 -0
- package/src/prool/Instance.ts +190 -0
- package/src/prool/index.ts +1 -0
- package/src/prool/internal/chain.json +106 -0
- package/src/prool/internal/consensus.toml +32 -0
- package/src/viem/abis.ts +1606 -0
- package/src/viem/actions/amm.test.ts +425 -0
- package/src/viem/actions/amm.ts +1308 -0
- package/src/viem/actions/fee.test.ts +281 -0
- package/src/viem/actions/fee.ts +362 -0
- package/src/viem/actions/index.ts +4 -0
- package/src/viem/actions/policy.test.ts +514 -0
- package/src/viem/actions/policy.ts +1284 -0
- package/src/viem/actions/token.test.ts +2172 -0
- package/src/viem/actions/token.ts +3830 -0
- package/src/viem/addresses.ts +10 -0
- package/src/viem/chain.ts +27 -0
- package/src/viem/client.bench-d.ts +8 -0
- package/src/viem/client.test.ts +152 -0
- package/src/viem/client.ts +91 -0
- package/src/viem/decorator.bench-d.ts +11 -0
- package/src/viem/decorator.test.ts +35 -0
- package/src/viem/decorator.ts +1914 -0
- package/src/viem/e2e.test.ts +410 -0
- package/src/viem/formatters.ts +100 -0
- package/src/viem/index.ts +8 -0
- package/src/viem/transaction.ts +253 -0
- package/src/viem/transport.ts +47 -0
- package/src/viem/types.ts +55 -0
- package/src/viem/utils.ts +37 -0
|
@@ -0,0 +1,2172 @@
|
|
|
1
|
+
import { setTimeout } from 'node:timers/promises'
|
|
2
|
+
import { Hex } from 'ox'
|
|
3
|
+
import * as actions from 'tempo.ts/viem/actions'
|
|
4
|
+
import { parseEther, publicActions } from 'viem'
|
|
5
|
+
import { mnemonicToAccount } from 'viem/accounts'
|
|
6
|
+
import { getCode, writeContractSync } from 'viem/actions'
|
|
7
|
+
import { describe, expect, test } from 'vitest'
|
|
8
|
+
import { tempoTest } from '../../../test/viem/config.js'
|
|
9
|
+
import { tip20Abi } from '../abis.js'
|
|
10
|
+
import { usdAddress, usdId } from '../addresses.js'
|
|
11
|
+
import { createTempoClient } from '../client.js'
|
|
12
|
+
|
|
13
|
+
const account = mnemonicToAccount(
|
|
14
|
+
'test test test test test test test test test test test junk',
|
|
15
|
+
)
|
|
16
|
+
const account2 = mnemonicToAccount(
|
|
17
|
+
'test test test test test test test test test test test junk',
|
|
18
|
+
{ accountIndex: 1 },
|
|
19
|
+
)
|
|
20
|
+
const account3 = mnemonicToAccount(
|
|
21
|
+
'test test test test test test test test test test test junk',
|
|
22
|
+
{ accountIndex: 2 },
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
const client = createTempoClient({
|
|
26
|
+
account,
|
|
27
|
+
chain: tempoTest,
|
|
28
|
+
pollingInterval: 100,
|
|
29
|
+
}).extend(publicActions)
|
|
30
|
+
|
|
31
|
+
describe('approve', () => {
|
|
32
|
+
test('default', async () => {
|
|
33
|
+
{
|
|
34
|
+
// approve
|
|
35
|
+
const { receipt, ...result } = await actions.token.approveSync(client, {
|
|
36
|
+
spender: account2.address,
|
|
37
|
+
amount: parseEther('100'),
|
|
38
|
+
})
|
|
39
|
+
expect(receipt).toBeDefined()
|
|
40
|
+
expect(result).toMatchInlineSnapshot(`
|
|
41
|
+
{
|
|
42
|
+
"amount": 100000000000000000000n,
|
|
43
|
+
"owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
44
|
+
"spender": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
45
|
+
}
|
|
46
|
+
`)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
{
|
|
50
|
+
// check allowance
|
|
51
|
+
const allowance = await actions.token.getAllowance(client, {
|
|
52
|
+
spender: account2.address,
|
|
53
|
+
})
|
|
54
|
+
expect(allowance).toBe(parseEther('100'))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// transfer tokens for gas
|
|
58
|
+
await writeContractSync(client, {
|
|
59
|
+
abi: tip20Abi,
|
|
60
|
+
address: usdAddress,
|
|
61
|
+
functionName: 'transfer',
|
|
62
|
+
args: [account2.address, parseEther('1')],
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
// transfer tokens from approved account
|
|
66
|
+
await actions.token.transferSync(client, {
|
|
67
|
+
amount: parseEther('50'),
|
|
68
|
+
account: account2,
|
|
69
|
+
from: account.address,
|
|
70
|
+
to: '0x0000000000000000000000000000000000000001',
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
{
|
|
74
|
+
// verify updated allowance
|
|
75
|
+
const allowance = await actions.token.getAllowance(client, {
|
|
76
|
+
spender: account2.address,
|
|
77
|
+
})
|
|
78
|
+
expect(allowance).toBe(parseEther('50'))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// verify balance
|
|
82
|
+
const balance = await actions.token.getBalance(client, {
|
|
83
|
+
account: '0x0000000000000000000000000000000000000001',
|
|
84
|
+
})
|
|
85
|
+
expect(balance).toBe(parseEther('50'))
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
test('behavior: token address', async () => {
|
|
89
|
+
{
|
|
90
|
+
// approve
|
|
91
|
+
const { receipt, ...result } = await actions.token.approveSync(client, {
|
|
92
|
+
amount: parseEther('100'),
|
|
93
|
+
token: usdAddress,
|
|
94
|
+
spender: account2.address,
|
|
95
|
+
})
|
|
96
|
+
expect(receipt).toBeDefined()
|
|
97
|
+
expect(result).toMatchInlineSnapshot(`
|
|
98
|
+
{
|
|
99
|
+
"amount": 100000000000000000000n,
|
|
100
|
+
"owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
101
|
+
"spender": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
102
|
+
}
|
|
103
|
+
`)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
{
|
|
107
|
+
// check allowance
|
|
108
|
+
const allowance = await actions.token.getAllowance(client, {
|
|
109
|
+
token: usdAddress,
|
|
110
|
+
spender: account2.address,
|
|
111
|
+
})
|
|
112
|
+
expect(allowance).toBe(parseEther('100'))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// transfer tokens for gas
|
|
116
|
+
await writeContractSync(client, {
|
|
117
|
+
abi: tip20Abi,
|
|
118
|
+
address: usdAddress,
|
|
119
|
+
functionName: 'transfer',
|
|
120
|
+
args: [account2.address, parseEther('1')],
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// transfer tokens from approved account
|
|
124
|
+
await actions.token.transferSync(client, {
|
|
125
|
+
amount: parseEther('50'),
|
|
126
|
+
account: account2,
|
|
127
|
+
from: account.address,
|
|
128
|
+
to: '0x0000000000000000000000000000000000000001',
|
|
129
|
+
token: usdAddress,
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
{
|
|
133
|
+
// verify updated allowance
|
|
134
|
+
const allowance = await actions.token.getAllowance(client, {
|
|
135
|
+
spender: account2.address,
|
|
136
|
+
token: usdAddress,
|
|
137
|
+
})
|
|
138
|
+
expect(allowance).toBe(parseEther('50'))
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// verify balance
|
|
142
|
+
const balance = await actions.token.getBalance(client, {
|
|
143
|
+
account: '0x0000000000000000000000000000000000000001',
|
|
144
|
+
token: usdAddress,
|
|
145
|
+
})
|
|
146
|
+
expect(balance).toBe(parseEther('50'))
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
test('behavior: token address', async () => {
|
|
150
|
+
{
|
|
151
|
+
// approve
|
|
152
|
+
const { receipt, ...result } = await actions.token.approveSync(client, {
|
|
153
|
+
amount: parseEther('100'),
|
|
154
|
+
token: usdId,
|
|
155
|
+
spender: account2.address,
|
|
156
|
+
})
|
|
157
|
+
expect(receipt).toBeDefined()
|
|
158
|
+
expect(result).toMatchInlineSnapshot(`
|
|
159
|
+
{
|
|
160
|
+
"amount": 100000000000000000000n,
|
|
161
|
+
"owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
162
|
+
"spender": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
163
|
+
}
|
|
164
|
+
`)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
{
|
|
168
|
+
// check allowance
|
|
169
|
+
const allowance = await actions.token.getAllowance(client, {
|
|
170
|
+
token: usdId,
|
|
171
|
+
spender: account2.address,
|
|
172
|
+
})
|
|
173
|
+
expect(allowance).toBe(parseEther('100'))
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// transfer tokens for gas
|
|
177
|
+
await writeContractSync(client, {
|
|
178
|
+
abi: tip20Abi,
|
|
179
|
+
address: usdAddress,
|
|
180
|
+
functionName: 'transfer',
|
|
181
|
+
args: [account2.address, parseEther('1')],
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
// transfer tokens from approved account
|
|
185
|
+
await actions.token.transferSync(client, {
|
|
186
|
+
amount: parseEther('50'),
|
|
187
|
+
account: account2,
|
|
188
|
+
from: account.address,
|
|
189
|
+
to: '0x0000000000000000000000000000000000000001',
|
|
190
|
+
token: usdId,
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
{
|
|
194
|
+
// verify updated allowance
|
|
195
|
+
const allowance = await actions.token.getAllowance(client, {
|
|
196
|
+
spender: account2.address,
|
|
197
|
+
token: usdId,
|
|
198
|
+
})
|
|
199
|
+
expect(allowance).toBe(parseEther('50'))
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// verify balance
|
|
203
|
+
const balance = await actions.token.getBalance(client, {
|
|
204
|
+
account: '0x0000000000000000000000000000000000000001',
|
|
205
|
+
token: usdId,
|
|
206
|
+
})
|
|
207
|
+
expect(balance).toBe(parseEther('50'))
|
|
208
|
+
})
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
describe('create', () => {
|
|
212
|
+
test('default', async () => {
|
|
213
|
+
const { receipt, ...result } = await actions.token.createSync(client, {
|
|
214
|
+
currency: 'USD',
|
|
215
|
+
name: 'Test USD',
|
|
216
|
+
symbol: 'TUSD',
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
expect(result).toMatchInlineSnapshot(`
|
|
220
|
+
{
|
|
221
|
+
"admin": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
222
|
+
"currency": "USD",
|
|
223
|
+
"name": "Test USD",
|
|
224
|
+
"symbol": "TUSD",
|
|
225
|
+
"token": "0x20C0000000000000000000000000000000000001",
|
|
226
|
+
"tokenId": 1n,
|
|
227
|
+
}
|
|
228
|
+
`)
|
|
229
|
+
expect(receipt).toBeDefined()
|
|
230
|
+
|
|
231
|
+
const code = await getCode(client, {
|
|
232
|
+
address: result.token,
|
|
233
|
+
})
|
|
234
|
+
expect(code).toBe('0xef')
|
|
235
|
+
})
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
describe('getAllowance', () => {
|
|
239
|
+
test('default', async () => {
|
|
240
|
+
// First, approve some allowance
|
|
241
|
+
await writeContractSync(client, {
|
|
242
|
+
abi: tip20Abi,
|
|
243
|
+
address: usdAddress,
|
|
244
|
+
functionName: 'approve',
|
|
245
|
+
args: [account2.address, parseEther('50')],
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
{
|
|
249
|
+
// Test with default token
|
|
250
|
+
const allowance = await actions.token.getAllowance(client, {
|
|
251
|
+
spender: account2.address,
|
|
252
|
+
})
|
|
253
|
+
expect(allowance).toBe(parseEther('50'))
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
{
|
|
257
|
+
// Test with token address
|
|
258
|
+
const allowance = await actions.token.getAllowance(client, {
|
|
259
|
+
token: usdAddress,
|
|
260
|
+
spender: account2.address,
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
expect(allowance).toBe(parseEther('50'))
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
{
|
|
267
|
+
// Test with token ID
|
|
268
|
+
const allowance = await actions.token.getAllowance(client, {
|
|
269
|
+
token: usdId,
|
|
270
|
+
spender: account2.address,
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
expect(allowance).toBe(parseEther('50'))
|
|
274
|
+
}
|
|
275
|
+
})
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
describe('getBalance', () => {
|
|
279
|
+
test('default', async () => {
|
|
280
|
+
{
|
|
281
|
+
// Test with default token
|
|
282
|
+
const balance = await actions.token.getBalance(client)
|
|
283
|
+
expect(balance).toBeGreaterThan(0n)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
{
|
|
287
|
+
// Test with token address
|
|
288
|
+
const balance = await actions.token.getBalance(client, {
|
|
289
|
+
token: usdAddress,
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
expect(balance).toBeGreaterThan(0n)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
{
|
|
296
|
+
// Test with token ID & different account
|
|
297
|
+
const balance = await actions.token.getBalance(client, {
|
|
298
|
+
token: usdId,
|
|
299
|
+
account: Hex.random(20),
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
expect(balance).toBe(0n)
|
|
303
|
+
}
|
|
304
|
+
})
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
describe('getMetadata', () => {
|
|
308
|
+
test('default', async () => {
|
|
309
|
+
const metadata = await actions.token.getMetadata(client)
|
|
310
|
+
|
|
311
|
+
expect(metadata).toMatchInlineSnapshot(`
|
|
312
|
+
{
|
|
313
|
+
"currency": "USD",
|
|
314
|
+
"decimals": 6,
|
|
315
|
+
"name": "TestUSD",
|
|
316
|
+
"paused": false,
|
|
317
|
+
"supplyCap": 115792089237316195423570985008687907853269984665640564039457584007913129639935n,
|
|
318
|
+
"symbol": "TestUSD",
|
|
319
|
+
"totalSupply": 340282366920938463647842048168863727605n,
|
|
320
|
+
"transferPolicy": "always-allow",
|
|
321
|
+
}
|
|
322
|
+
`)
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
test('behavior: custom token (address)', async () => {
|
|
326
|
+
const { token } = await actions.token.createSync(client, {
|
|
327
|
+
currency: 'USD',
|
|
328
|
+
name: 'Test USD',
|
|
329
|
+
symbol: 'TUSD',
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
const metadata = await actions.token.getMetadata(client, {
|
|
333
|
+
token,
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
expect(metadata).toMatchInlineSnapshot(`
|
|
337
|
+
{
|
|
338
|
+
"currency": "USD",
|
|
339
|
+
"decimals": 6,
|
|
340
|
+
"name": "Test USD",
|
|
341
|
+
"paused": false,
|
|
342
|
+
"supplyCap": 115792089237316195423570985008687907853269984665640564039457584007913129639935n,
|
|
343
|
+
"symbol": "TUSD",
|
|
344
|
+
"totalSupply": 0n,
|
|
345
|
+
"transferPolicy": "always-allow",
|
|
346
|
+
}
|
|
347
|
+
`)
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
test('behavior: custom token (id)', async () => {
|
|
351
|
+
const token = await actions.token.createSync(client, {
|
|
352
|
+
currency: 'USD',
|
|
353
|
+
name: 'Test USD',
|
|
354
|
+
symbol: 'TUSD',
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
const metadata = await actions.token.getMetadata(client, {
|
|
358
|
+
token: token.tokenId,
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
expect(metadata).toMatchInlineSnapshot(`
|
|
362
|
+
{
|
|
363
|
+
"currency": "USD",
|
|
364
|
+
"decimals": 6,
|
|
365
|
+
"name": "Test USD",
|
|
366
|
+
"paused": false,
|
|
367
|
+
"supplyCap": 115792089237316195423570985008687907853269984665640564039457584007913129639935n,
|
|
368
|
+
"symbol": "TUSD",
|
|
369
|
+
"totalSupply": 0n,
|
|
370
|
+
"transferPolicy": "always-allow",
|
|
371
|
+
}
|
|
372
|
+
`)
|
|
373
|
+
})
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
describe('mint', () => {
|
|
377
|
+
test('default', async () => {
|
|
378
|
+
// Create a new token where we're the admin
|
|
379
|
+
const { token } = await actions.token.createSync(client, {
|
|
380
|
+
currency: 'USD',
|
|
381
|
+
name: 'Mintable Token',
|
|
382
|
+
symbol: 'MINT',
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
// Grant issuer role
|
|
386
|
+
await actions.token.grantRolesSync(client, {
|
|
387
|
+
token,
|
|
388
|
+
roles: ['issuer'],
|
|
389
|
+
to: client.account.address,
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
// Check initial balance
|
|
393
|
+
const balanceBefore = await actions.token.getBalance(client, {
|
|
394
|
+
token,
|
|
395
|
+
account: account2.address,
|
|
396
|
+
})
|
|
397
|
+
expect(balanceBefore).toBe(0n)
|
|
398
|
+
|
|
399
|
+
// Mint tokens
|
|
400
|
+
const { receipt: mintReceipt, ...mintResult } =
|
|
401
|
+
await actions.token.mintSync(client, {
|
|
402
|
+
token,
|
|
403
|
+
to: account2.address,
|
|
404
|
+
amount: parseEther('1000'),
|
|
405
|
+
})
|
|
406
|
+
expect(mintReceipt).toBeDefined()
|
|
407
|
+
expect(mintResult).toMatchInlineSnapshot(`
|
|
408
|
+
{
|
|
409
|
+
"amount": 1000000000000000000000n,
|
|
410
|
+
"to": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
411
|
+
}
|
|
412
|
+
`)
|
|
413
|
+
|
|
414
|
+
// Check balance after mint
|
|
415
|
+
const balanceAfter = await actions.token.getBalance(client, {
|
|
416
|
+
token,
|
|
417
|
+
account: account2.address,
|
|
418
|
+
})
|
|
419
|
+
expect(balanceAfter).toBe(parseEther('1000'))
|
|
420
|
+
|
|
421
|
+
// Check total supply
|
|
422
|
+
const metadata = await actions.token.getMetadata(client, {
|
|
423
|
+
token,
|
|
424
|
+
})
|
|
425
|
+
expect(metadata.totalSupply).toBe(parseEther('1000'))
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
// TODO: fix
|
|
429
|
+
test.skip('with memo', async () => {
|
|
430
|
+
// Create a new token
|
|
431
|
+
const { token } = await actions.token.createSync(client, {
|
|
432
|
+
admin: client.account,
|
|
433
|
+
currency: 'USD',
|
|
434
|
+
name: 'Mintable Token 2',
|
|
435
|
+
symbol: 'MINT2',
|
|
436
|
+
})
|
|
437
|
+
|
|
438
|
+
// Grant issuer role
|
|
439
|
+
await actions.token.grantRolesSync(client, {
|
|
440
|
+
token,
|
|
441
|
+
roles: ['issuer'],
|
|
442
|
+
to: client.account.address,
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
// Mint tokens with memo
|
|
446
|
+
const { receipt: mintMemoReceipt, ...mintMemoResult } =
|
|
447
|
+
await actions.token.mintSync(client, {
|
|
448
|
+
token,
|
|
449
|
+
to: account2.address,
|
|
450
|
+
amount: parseEther('500'),
|
|
451
|
+
memo: Hex.fromString('test'),
|
|
452
|
+
})
|
|
453
|
+
expect(mintMemoReceipt.status).toBe('success')
|
|
454
|
+
expect(mintMemoResult).toMatchInlineSnapshot(`
|
|
455
|
+
{
|
|
456
|
+
"amount": 500000000000000000000n,
|
|
457
|
+
"to": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
458
|
+
}
|
|
459
|
+
`)
|
|
460
|
+
|
|
461
|
+
// Verify balance
|
|
462
|
+
const balance = await actions.token.getBalance(client, {
|
|
463
|
+
token,
|
|
464
|
+
account: account2.address,
|
|
465
|
+
})
|
|
466
|
+
expect(balance).toBe(parseEther('500'))
|
|
467
|
+
})
|
|
468
|
+
})
|
|
469
|
+
|
|
470
|
+
describe.todo('permitToken')
|
|
471
|
+
|
|
472
|
+
describe('transfer', () => {
|
|
473
|
+
test('default', async () => {
|
|
474
|
+
// Get initial balances
|
|
475
|
+
const senderBalanceBefore = await actions.token.getBalance(client, {
|
|
476
|
+
account: account.address,
|
|
477
|
+
})
|
|
478
|
+
const receiverBalanceBefore = await actions.token.getBalance(client, {
|
|
479
|
+
account: account2.address,
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
// Transfer tokens
|
|
483
|
+
const { receipt: transferReceipt, ...transferResult } =
|
|
484
|
+
await actions.token.transferSync(client, {
|
|
485
|
+
to: account2.address,
|
|
486
|
+
amount: parseEther('10'),
|
|
487
|
+
})
|
|
488
|
+
expect(transferReceipt).toBeDefined()
|
|
489
|
+
expect(transferResult).toMatchInlineSnapshot(`
|
|
490
|
+
{
|
|
491
|
+
"amount": 10000000000000000000n,
|
|
492
|
+
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
493
|
+
"to": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
494
|
+
}
|
|
495
|
+
`)
|
|
496
|
+
|
|
497
|
+
// Verify balances
|
|
498
|
+
const senderBalanceAfter = await actions.token.getBalance(client, {
|
|
499
|
+
account: account.address,
|
|
500
|
+
})
|
|
501
|
+
const receiverBalanceAfter = await actions.token.getBalance(client, {
|
|
502
|
+
account: account2.address,
|
|
503
|
+
})
|
|
504
|
+
|
|
505
|
+
expect(senderBalanceAfter - senderBalanceBefore).toBeLessThan(
|
|
506
|
+
parseEther('10'),
|
|
507
|
+
)
|
|
508
|
+
expect(receiverBalanceAfter - receiverBalanceBefore).toBe(parseEther('10'))
|
|
509
|
+
})
|
|
510
|
+
|
|
511
|
+
test('behavior: with custom token', async () => {
|
|
512
|
+
// Create a new token
|
|
513
|
+
const { token } = await actions.token.createSync(client, {
|
|
514
|
+
currency: 'USD',
|
|
515
|
+
name: 'Transfer Token',
|
|
516
|
+
symbol: 'XFER',
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
// Grant issuer role and mint tokens
|
|
520
|
+
await actions.token.grantRolesSync(client, {
|
|
521
|
+
token,
|
|
522
|
+
roles: ['issuer'],
|
|
523
|
+
to: client.account.address,
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
await actions.token.mintSync(client, {
|
|
527
|
+
token,
|
|
528
|
+
to: client.account.address,
|
|
529
|
+
amount: parseEther('1000'),
|
|
530
|
+
})
|
|
531
|
+
|
|
532
|
+
// Transfer custom tokens
|
|
533
|
+
await actions.token.transferSync(client, {
|
|
534
|
+
token,
|
|
535
|
+
to: account2.address,
|
|
536
|
+
amount: parseEther('100'),
|
|
537
|
+
})
|
|
538
|
+
|
|
539
|
+
// Verify balance
|
|
540
|
+
const balance = await actions.token.getBalance(client, {
|
|
541
|
+
token,
|
|
542
|
+
account: account2.address,
|
|
543
|
+
})
|
|
544
|
+
expect(balance).toBe(parseEther('100'))
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
test('behavior: with memo', async () => {
|
|
548
|
+
const memo = Hex.fromString('Payment for services')
|
|
549
|
+
|
|
550
|
+
const { receipt: transferMemoReceipt, ...transferMemoResult } =
|
|
551
|
+
await actions.token.transferSync(client, {
|
|
552
|
+
to: account2.address,
|
|
553
|
+
amount: parseEther('5'),
|
|
554
|
+
memo,
|
|
555
|
+
})
|
|
556
|
+
|
|
557
|
+
expect(transferMemoReceipt.status).toBe('success')
|
|
558
|
+
expect(transferMemoResult).toMatchInlineSnapshot(`
|
|
559
|
+
{
|
|
560
|
+
"amount": 5000000000000000000n,
|
|
561
|
+
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
562
|
+
"to": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
563
|
+
}
|
|
564
|
+
`)
|
|
565
|
+
})
|
|
566
|
+
|
|
567
|
+
test('behavior: from another account (transferFrom)', async () => {
|
|
568
|
+
// First approve account2 to spend tokens
|
|
569
|
+
await actions.token.approveSync(client, {
|
|
570
|
+
spender: account2.address,
|
|
571
|
+
amount: parseEther('50'),
|
|
572
|
+
})
|
|
573
|
+
|
|
574
|
+
// Transfer tokens for gas
|
|
575
|
+
await writeContractSync(client, {
|
|
576
|
+
abi: tip20Abi,
|
|
577
|
+
address: usdAddress,
|
|
578
|
+
functionName: 'transfer',
|
|
579
|
+
args: [account2.address, parseEther('1')],
|
|
580
|
+
})
|
|
581
|
+
|
|
582
|
+
// Get initial balance
|
|
583
|
+
const balanceBefore = await actions.token.getBalance(client, {
|
|
584
|
+
account: account3.address,
|
|
585
|
+
})
|
|
586
|
+
|
|
587
|
+
// Account2 transfers from account to account3
|
|
588
|
+
await actions.token.transferSync(client, {
|
|
589
|
+
account: account2,
|
|
590
|
+
from: account.address,
|
|
591
|
+
to: account3.address,
|
|
592
|
+
amount: parseEther('25'),
|
|
593
|
+
})
|
|
594
|
+
|
|
595
|
+
// Verify balance
|
|
596
|
+
const balanceAfter = await actions.token.getBalance(client, {
|
|
597
|
+
account: account3.address,
|
|
598
|
+
})
|
|
599
|
+
expect(balanceAfter - balanceBefore).toBe(parseEther('25'))
|
|
600
|
+
|
|
601
|
+
// Verify allowance was reduced
|
|
602
|
+
const allowance = await actions.token.getAllowance(client, {
|
|
603
|
+
spender: account2.address,
|
|
604
|
+
})
|
|
605
|
+
expect(allowance).toBe(parseEther('25'))
|
|
606
|
+
})
|
|
607
|
+
})
|
|
608
|
+
|
|
609
|
+
describe('burn', () => {
|
|
610
|
+
test('default', async () => {
|
|
611
|
+
// Create a new token where we have issuer role
|
|
612
|
+
const { token } = await actions.token.createSync(client, {
|
|
613
|
+
currency: 'USD',
|
|
614
|
+
name: 'Burnable Token',
|
|
615
|
+
symbol: 'BURN',
|
|
616
|
+
})
|
|
617
|
+
|
|
618
|
+
// Grant issuer role
|
|
619
|
+
await actions.token.grantRolesSync(client, {
|
|
620
|
+
token,
|
|
621
|
+
roles: ['issuer'],
|
|
622
|
+
to: client.account.address,
|
|
623
|
+
})
|
|
624
|
+
|
|
625
|
+
// Mint some tokens
|
|
626
|
+
await actions.token.mintSync(client, {
|
|
627
|
+
token,
|
|
628
|
+
to: client.account.address,
|
|
629
|
+
amount: parseEther('1000'),
|
|
630
|
+
})
|
|
631
|
+
|
|
632
|
+
// Check balance before burn
|
|
633
|
+
const balanceBefore = await actions.token.getBalance(client, {
|
|
634
|
+
token,
|
|
635
|
+
})
|
|
636
|
+
expect(balanceBefore).toBe(parseEther('1000'))
|
|
637
|
+
|
|
638
|
+
// Check total supply before
|
|
639
|
+
const metadataBefore = await actions.token.getMetadata(client, {
|
|
640
|
+
token,
|
|
641
|
+
})
|
|
642
|
+
expect(metadataBefore.totalSupply).toBe(parseEther('1000'))
|
|
643
|
+
|
|
644
|
+
// Burn tokens
|
|
645
|
+
const { receipt, ...result } = await actions.token.burnSync(client, {
|
|
646
|
+
token,
|
|
647
|
+
amount: parseEther('100'),
|
|
648
|
+
})
|
|
649
|
+
expect(receipt).toBeDefined()
|
|
650
|
+
expect(result).toMatchInlineSnapshot(`
|
|
651
|
+
{
|
|
652
|
+
"amount": 100000000000000000000n,
|
|
653
|
+
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
654
|
+
}
|
|
655
|
+
`)
|
|
656
|
+
|
|
657
|
+
// Check balance after burn
|
|
658
|
+
const balanceAfter = await actions.token.getBalance(client, {
|
|
659
|
+
token,
|
|
660
|
+
})
|
|
661
|
+
expect(balanceAfter).toBe(parseEther('900'))
|
|
662
|
+
|
|
663
|
+
// Check total supply after
|
|
664
|
+
const metadataAfter = await actions.token.getMetadata(client, {
|
|
665
|
+
token,
|
|
666
|
+
})
|
|
667
|
+
expect(metadataAfter.totalSupply).toBe(parseEther('900'))
|
|
668
|
+
})
|
|
669
|
+
|
|
670
|
+
test('behavior: requires issuer role', async () => {
|
|
671
|
+
// Create a new token
|
|
672
|
+
const { token } = await actions.token.createSync(client, {
|
|
673
|
+
currency: 'USD',
|
|
674
|
+
name: 'Restricted Burn Token',
|
|
675
|
+
symbol: 'RBURN',
|
|
676
|
+
})
|
|
677
|
+
|
|
678
|
+
// Grant issuer role to account2 (not us)
|
|
679
|
+
await actions.token.grantRolesSync(client, {
|
|
680
|
+
token,
|
|
681
|
+
roles: ['issuer'],
|
|
682
|
+
to: account2.address,
|
|
683
|
+
})
|
|
684
|
+
|
|
685
|
+
// Transfer gas to account2
|
|
686
|
+
await writeContractSync(client, {
|
|
687
|
+
abi: tip20Abi,
|
|
688
|
+
address: usdAddress,
|
|
689
|
+
functionName: 'transfer',
|
|
690
|
+
args: [account2.address, parseEther('1')],
|
|
691
|
+
})
|
|
692
|
+
|
|
693
|
+
await actions.token.mintSync(client, {
|
|
694
|
+
account: account2,
|
|
695
|
+
token,
|
|
696
|
+
to: client.account.address,
|
|
697
|
+
amount: parseEther('100'),
|
|
698
|
+
})
|
|
699
|
+
|
|
700
|
+
// Try to burn without issuer role - should fail
|
|
701
|
+
await expect(
|
|
702
|
+
actions.token.burnSync(client, {
|
|
703
|
+
token,
|
|
704
|
+
amount: parseEther('10'),
|
|
705
|
+
}),
|
|
706
|
+
).rejects.toThrow()
|
|
707
|
+
})
|
|
708
|
+
})
|
|
709
|
+
|
|
710
|
+
describe.todo('burnBlockedToken')
|
|
711
|
+
|
|
712
|
+
describe.todo('changeTokenTransferPolicy')
|
|
713
|
+
|
|
714
|
+
describe('pause', () => {
|
|
715
|
+
test('default', async () => {
|
|
716
|
+
// Create a new token
|
|
717
|
+
const { token } = await actions.token.createSync(client, {
|
|
718
|
+
currency: 'USD',
|
|
719
|
+
name: 'Pausable Token',
|
|
720
|
+
symbol: 'PAUSE',
|
|
721
|
+
})
|
|
722
|
+
|
|
723
|
+
// Grant pause role
|
|
724
|
+
await actions.token.grantRolesSync(client, {
|
|
725
|
+
token,
|
|
726
|
+
roles: ['pause'],
|
|
727
|
+
to: client.account.address,
|
|
728
|
+
})
|
|
729
|
+
|
|
730
|
+
// Grant issuer role and mint tokens
|
|
731
|
+
await actions.token.grantRolesSync(client, {
|
|
732
|
+
token,
|
|
733
|
+
roles: ['issuer'],
|
|
734
|
+
to: client.account.address,
|
|
735
|
+
})
|
|
736
|
+
|
|
737
|
+
await actions.token.mintSync(client, {
|
|
738
|
+
token,
|
|
739
|
+
to: account2.address,
|
|
740
|
+
amount: parseEther('1000'),
|
|
741
|
+
})
|
|
742
|
+
|
|
743
|
+
// Verify token is not paused
|
|
744
|
+
let metadata = await actions.token.getMetadata(client, {
|
|
745
|
+
token,
|
|
746
|
+
})
|
|
747
|
+
expect(metadata.paused).toBe(false)
|
|
748
|
+
|
|
749
|
+
// Transfer gas
|
|
750
|
+
await writeContractSync(client, {
|
|
751
|
+
abi: tip20Abi,
|
|
752
|
+
address: usdAddress,
|
|
753
|
+
functionName: 'transfer',
|
|
754
|
+
args: [account2.address, parseEther('1')],
|
|
755
|
+
})
|
|
756
|
+
|
|
757
|
+
await actions.token.transferSync(client, {
|
|
758
|
+
account: account2,
|
|
759
|
+
token,
|
|
760
|
+
to: account3.address,
|
|
761
|
+
amount: parseEther('100'),
|
|
762
|
+
})
|
|
763
|
+
|
|
764
|
+
// Pause the token
|
|
765
|
+
const { receipt: pauseReceipt, ...pauseResult } =
|
|
766
|
+
await actions.token.pauseSync(client, {
|
|
767
|
+
token,
|
|
768
|
+
})
|
|
769
|
+
expect(pauseReceipt).toBeDefined()
|
|
770
|
+
expect(pauseResult).toMatchInlineSnapshot(`
|
|
771
|
+
{
|
|
772
|
+
"isPaused": true,
|
|
773
|
+
"updater": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
774
|
+
}
|
|
775
|
+
`)
|
|
776
|
+
|
|
777
|
+
// Verify token is paused
|
|
778
|
+
metadata = await actions.token.getMetadata(client, {
|
|
779
|
+
token,
|
|
780
|
+
})
|
|
781
|
+
expect(metadata.paused).toBe(true)
|
|
782
|
+
|
|
783
|
+
// Transfers should now fail
|
|
784
|
+
await expect(
|
|
785
|
+
actions.token.transferSync(client, {
|
|
786
|
+
account: account2,
|
|
787
|
+
token,
|
|
788
|
+
to: account3.address,
|
|
789
|
+
amount: parseEther('100'),
|
|
790
|
+
}),
|
|
791
|
+
).rejects.toThrow()
|
|
792
|
+
})
|
|
793
|
+
|
|
794
|
+
test('behavior: requires pause role', async () => {
|
|
795
|
+
// Create a new token
|
|
796
|
+
const { token } = await actions.token.createSync(client, {
|
|
797
|
+
currency: 'USD',
|
|
798
|
+
name: 'Restricted Pause Token',
|
|
799
|
+
symbol: 'RPAUSE',
|
|
800
|
+
})
|
|
801
|
+
|
|
802
|
+
// Try to pause without pause role - should fail
|
|
803
|
+
await expect(
|
|
804
|
+
actions.token.pauseSync(client, {
|
|
805
|
+
token,
|
|
806
|
+
}),
|
|
807
|
+
).rejects.toThrow()
|
|
808
|
+
|
|
809
|
+
// Grant pause role to account2
|
|
810
|
+
await actions.token.grantRolesSync(client, {
|
|
811
|
+
token,
|
|
812
|
+
roles: ['pause'],
|
|
813
|
+
to: account2.address,
|
|
814
|
+
})
|
|
815
|
+
|
|
816
|
+
// Transfer gas to account2
|
|
817
|
+
await writeContractSync(client, {
|
|
818
|
+
abi: tip20Abi,
|
|
819
|
+
address: usdAddress,
|
|
820
|
+
functionName: 'transfer',
|
|
821
|
+
args: [account2.address, parseEther('1')],
|
|
822
|
+
})
|
|
823
|
+
|
|
824
|
+
await actions.token.pauseSync(client, {
|
|
825
|
+
account: account2,
|
|
826
|
+
token,
|
|
827
|
+
})
|
|
828
|
+
|
|
829
|
+
// Verify token is paused
|
|
830
|
+
const metadata = await actions.token.getMetadata(client, {
|
|
831
|
+
token,
|
|
832
|
+
})
|
|
833
|
+
expect(metadata.paused).toBe(true)
|
|
834
|
+
})
|
|
835
|
+
|
|
836
|
+
test('behavior: cannot pause already paused token', async () => {
|
|
837
|
+
// Create a new token
|
|
838
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
839
|
+
currency: 'USD',
|
|
840
|
+
name: 'Double Pause Token',
|
|
841
|
+
symbol: 'DPAUSE',
|
|
842
|
+
})
|
|
843
|
+
|
|
844
|
+
// Grant pause role
|
|
845
|
+
await actions.token.grantRolesSync(client, {
|
|
846
|
+
token: address,
|
|
847
|
+
roles: ['pause'],
|
|
848
|
+
to: client.account.address,
|
|
849
|
+
})
|
|
850
|
+
|
|
851
|
+
// Pause the token
|
|
852
|
+
await actions.token.pauseSync(client, {
|
|
853
|
+
token: address,
|
|
854
|
+
})
|
|
855
|
+
|
|
856
|
+
// Try to pause again - implementation may vary, but typically this succeeds without error
|
|
857
|
+
const { receipt: doublePauseReceipt, ...doublePauseResult } =
|
|
858
|
+
await actions.token.pauseSync(client, {
|
|
859
|
+
token: address,
|
|
860
|
+
})
|
|
861
|
+
expect(doublePauseReceipt.status).toBe('success')
|
|
862
|
+
expect(doublePauseResult).toMatchInlineSnapshot(`
|
|
863
|
+
{
|
|
864
|
+
"isPaused": true,
|
|
865
|
+
"updater": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
866
|
+
}
|
|
867
|
+
`)
|
|
868
|
+
})
|
|
869
|
+
})
|
|
870
|
+
|
|
871
|
+
describe('unpause', () => {
|
|
872
|
+
test('default', async () => {
|
|
873
|
+
// Create a new token
|
|
874
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
875
|
+
currency: 'USD',
|
|
876
|
+
name: 'Unpausable Token',
|
|
877
|
+
symbol: 'UNPAUSE',
|
|
878
|
+
})
|
|
879
|
+
|
|
880
|
+
// Grant pause and unpause roles
|
|
881
|
+
await actions.token.grantRolesSync(client, {
|
|
882
|
+
token: address,
|
|
883
|
+
roles: ['pause'],
|
|
884
|
+
to: client.account.address,
|
|
885
|
+
})
|
|
886
|
+
|
|
887
|
+
await actions.token.grantRolesSync(client, {
|
|
888
|
+
token: address,
|
|
889
|
+
roles: ['unpause'],
|
|
890
|
+
to: client.account.address,
|
|
891
|
+
})
|
|
892
|
+
|
|
893
|
+
// Grant issuer role and mint tokens
|
|
894
|
+
await actions.token.grantRolesSync(client, {
|
|
895
|
+
token: address,
|
|
896
|
+
roles: ['issuer'],
|
|
897
|
+
to: client.account.address,
|
|
898
|
+
})
|
|
899
|
+
|
|
900
|
+
await actions.token.mintSync(client, {
|
|
901
|
+
token: address,
|
|
902
|
+
to: account2.address,
|
|
903
|
+
amount: parseEther('1000'),
|
|
904
|
+
})
|
|
905
|
+
|
|
906
|
+
// First pause the token
|
|
907
|
+
await actions.token.pauseSync(client, {
|
|
908
|
+
token: address,
|
|
909
|
+
})
|
|
910
|
+
|
|
911
|
+
// Verify token is paused
|
|
912
|
+
let metadata = await actions.token.getMetadata(client, {
|
|
913
|
+
token: address,
|
|
914
|
+
})
|
|
915
|
+
expect(metadata.paused).toBe(true)
|
|
916
|
+
|
|
917
|
+
// Transfer gas to account2
|
|
918
|
+
await writeContractSync(client, {
|
|
919
|
+
abi: tip20Abi,
|
|
920
|
+
address: usdAddress,
|
|
921
|
+
functionName: 'transfer',
|
|
922
|
+
args: [account2.address, parseEther('1')],
|
|
923
|
+
})
|
|
924
|
+
|
|
925
|
+
// Verify transfers fail when paused
|
|
926
|
+
await expect(
|
|
927
|
+
actions.token.transferSync(client, {
|
|
928
|
+
account: account2,
|
|
929
|
+
token: address,
|
|
930
|
+
to: account3.address,
|
|
931
|
+
amount: parseEther('100'),
|
|
932
|
+
}),
|
|
933
|
+
).rejects.toThrow()
|
|
934
|
+
|
|
935
|
+
// Unpause the token
|
|
936
|
+
const { receipt: unpauseReceipt, ...unpauseResult } =
|
|
937
|
+
await actions.token.unpauseSync(client, {
|
|
938
|
+
token: address,
|
|
939
|
+
})
|
|
940
|
+
expect(unpauseReceipt).toBeDefined()
|
|
941
|
+
expect(unpauseResult).toMatchInlineSnapshot(`
|
|
942
|
+
{
|
|
943
|
+
"isPaused": false,
|
|
944
|
+
"updater": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
945
|
+
}
|
|
946
|
+
`)
|
|
947
|
+
|
|
948
|
+
// Verify token is unpaused
|
|
949
|
+
metadata = await actions.token.getMetadata(client, {
|
|
950
|
+
token: address,
|
|
951
|
+
})
|
|
952
|
+
expect(metadata.paused).toBe(false)
|
|
953
|
+
|
|
954
|
+
// Transfers should work again
|
|
955
|
+
await actions.token.transferSync(client, {
|
|
956
|
+
account: account2,
|
|
957
|
+
token: address,
|
|
958
|
+
to: account3.address,
|
|
959
|
+
amount: parseEther('100'),
|
|
960
|
+
})
|
|
961
|
+
|
|
962
|
+
const balance = await actions.token.getBalance(client, {
|
|
963
|
+
token: address,
|
|
964
|
+
account: account3.address,
|
|
965
|
+
})
|
|
966
|
+
expect(balance).toBe(parseEther('100'))
|
|
967
|
+
})
|
|
968
|
+
|
|
969
|
+
test('behavior: requires unpause role', async () => {
|
|
970
|
+
// Create a new token
|
|
971
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
972
|
+
currency: 'USD',
|
|
973
|
+
name: 'Restricted Unpause Token',
|
|
974
|
+
symbol: 'RUNPAUSE',
|
|
975
|
+
})
|
|
976
|
+
|
|
977
|
+
// Grant pause role and pause the token
|
|
978
|
+
await actions.token.grantRolesSync(client, {
|
|
979
|
+
token: address,
|
|
980
|
+
roles: ['pause'],
|
|
981
|
+
to: client.account.address,
|
|
982
|
+
})
|
|
983
|
+
|
|
984
|
+
await actions.token.pauseSync(client, {
|
|
985
|
+
token: address,
|
|
986
|
+
})
|
|
987
|
+
|
|
988
|
+
// Try to unpause without unpause role - should fail
|
|
989
|
+
await expect(
|
|
990
|
+
actions.token.unpauseSync(client, {
|
|
991
|
+
token: address,
|
|
992
|
+
}),
|
|
993
|
+
).rejects.toThrow()
|
|
994
|
+
|
|
995
|
+
// Grant unpause role to account2
|
|
996
|
+
await actions.token.grantRolesSync(client, {
|
|
997
|
+
token: address,
|
|
998
|
+
roles: ['unpause'],
|
|
999
|
+
to: account2.address,
|
|
1000
|
+
})
|
|
1001
|
+
|
|
1002
|
+
// Transfer gas to account2
|
|
1003
|
+
await writeContractSync(client, {
|
|
1004
|
+
abi: tip20Abi,
|
|
1005
|
+
address: usdAddress,
|
|
1006
|
+
functionName: 'transfer',
|
|
1007
|
+
args: [account2.address, parseEther('1')],
|
|
1008
|
+
})
|
|
1009
|
+
|
|
1010
|
+
// Now account2 should be able to unpause
|
|
1011
|
+
await actions.token.unpauseSync(client, {
|
|
1012
|
+
account: account2,
|
|
1013
|
+
token: address,
|
|
1014
|
+
})
|
|
1015
|
+
|
|
1016
|
+
// Verify token is unpaused
|
|
1017
|
+
const metadata = await actions.token.getMetadata(client, {
|
|
1018
|
+
token: address,
|
|
1019
|
+
})
|
|
1020
|
+
expect(metadata.paused).toBe(false)
|
|
1021
|
+
})
|
|
1022
|
+
|
|
1023
|
+
test('behavior: different roles for pause and unpause', async () => {
|
|
1024
|
+
// Create a new token
|
|
1025
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1026
|
+
currency: 'USD',
|
|
1027
|
+
name: 'Split Role Token',
|
|
1028
|
+
symbol: 'SPLIT',
|
|
1029
|
+
})
|
|
1030
|
+
|
|
1031
|
+
// Grant pause role to account2
|
|
1032
|
+
await actions.token.grantRolesSync(client, {
|
|
1033
|
+
token: address,
|
|
1034
|
+
roles: ['pause'],
|
|
1035
|
+
to: account2.address,
|
|
1036
|
+
})
|
|
1037
|
+
|
|
1038
|
+
// Grant unpause role to account3
|
|
1039
|
+
await actions.token.grantRolesSync(client, {
|
|
1040
|
+
token: address,
|
|
1041
|
+
roles: ['unpause'],
|
|
1042
|
+
to: account3.address,
|
|
1043
|
+
})
|
|
1044
|
+
|
|
1045
|
+
// Transfer gas to both accounts
|
|
1046
|
+
await writeContractSync(client, {
|
|
1047
|
+
abi: tip20Abi,
|
|
1048
|
+
address: usdAddress,
|
|
1049
|
+
functionName: 'transfer',
|
|
1050
|
+
args: [account2.address, parseEther('1')],
|
|
1051
|
+
})
|
|
1052
|
+
|
|
1053
|
+
await writeContractSync(client, {
|
|
1054
|
+
abi: tip20Abi,
|
|
1055
|
+
address: usdAddress,
|
|
1056
|
+
functionName: 'transfer',
|
|
1057
|
+
args: [account3.address, parseEther('1')],
|
|
1058
|
+
})
|
|
1059
|
+
|
|
1060
|
+
// Account2 can pause
|
|
1061
|
+
await actions.token.pauseSync(client, {
|
|
1062
|
+
account: account2,
|
|
1063
|
+
token: address,
|
|
1064
|
+
})
|
|
1065
|
+
|
|
1066
|
+
// Account2 cannot unpause
|
|
1067
|
+
await expect(
|
|
1068
|
+
actions.token.unpauseSync(client, {
|
|
1069
|
+
account: account2,
|
|
1070
|
+
token: address,
|
|
1071
|
+
}),
|
|
1072
|
+
).rejects.toThrow()
|
|
1073
|
+
|
|
1074
|
+
// Account3 can unpause
|
|
1075
|
+
await actions.token.unpauseSync(client, {
|
|
1076
|
+
account: account3,
|
|
1077
|
+
token: address,
|
|
1078
|
+
})
|
|
1079
|
+
|
|
1080
|
+
// Verify token is unpaused
|
|
1081
|
+
const metadata = await actions.token.getMetadata(client, {
|
|
1082
|
+
token: address,
|
|
1083
|
+
})
|
|
1084
|
+
expect(metadata.paused).toBe(false)
|
|
1085
|
+
})
|
|
1086
|
+
})
|
|
1087
|
+
|
|
1088
|
+
describe.todo('setTokenSupplyCap')
|
|
1089
|
+
|
|
1090
|
+
describe('grantRoles', () => {
|
|
1091
|
+
test('default', async () => {
|
|
1092
|
+
// Create a new token where we're the admin
|
|
1093
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1094
|
+
admin: client.account,
|
|
1095
|
+
currency: 'USD',
|
|
1096
|
+
name: 'Test Token',
|
|
1097
|
+
symbol: 'TEST',
|
|
1098
|
+
})
|
|
1099
|
+
|
|
1100
|
+
// Grant issuer role to account2
|
|
1101
|
+
const { receipt: grantReceipt, value: grantValue } =
|
|
1102
|
+
await actions.token.grantRolesSync(client, {
|
|
1103
|
+
token: address,
|
|
1104
|
+
roles: ['issuer'],
|
|
1105
|
+
to: account2.address,
|
|
1106
|
+
})
|
|
1107
|
+
|
|
1108
|
+
expect(grantReceipt.status).toBe('success')
|
|
1109
|
+
expect(grantValue).toMatchInlineSnapshot(`
|
|
1110
|
+
[
|
|
1111
|
+
{
|
|
1112
|
+
"account": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
1113
|
+
"hasRole": true,
|
|
1114
|
+
"role": "0x114e74f6ea3bd819998f78687bfcb11b140da08e9b7d222fa9c1f1ba1f2aa122",
|
|
1115
|
+
"sender": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1116
|
+
},
|
|
1117
|
+
]
|
|
1118
|
+
`)
|
|
1119
|
+
})
|
|
1120
|
+
})
|
|
1121
|
+
|
|
1122
|
+
describe('revokeTokenRole', async () => {
|
|
1123
|
+
test('default', async () => {
|
|
1124
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1125
|
+
admin: client.account,
|
|
1126
|
+
currency: 'USD',
|
|
1127
|
+
name: 'Test Token 2',
|
|
1128
|
+
symbol: 'TEST2',
|
|
1129
|
+
})
|
|
1130
|
+
|
|
1131
|
+
await actions.token.grantRolesSync(client, {
|
|
1132
|
+
token: address,
|
|
1133
|
+
roles: ['issuer'],
|
|
1134
|
+
to: account2.address,
|
|
1135
|
+
})
|
|
1136
|
+
|
|
1137
|
+
const { receipt: revokeReceipt, value: revokeValue } =
|
|
1138
|
+
await actions.token.revokeRolesSync(client, {
|
|
1139
|
+
from: account2.address,
|
|
1140
|
+
token: address,
|
|
1141
|
+
roles: ['issuer'],
|
|
1142
|
+
})
|
|
1143
|
+
|
|
1144
|
+
expect(revokeReceipt.status).toBe('success')
|
|
1145
|
+
expect(revokeValue).toMatchInlineSnapshot(`
|
|
1146
|
+
[
|
|
1147
|
+
{
|
|
1148
|
+
"account": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
1149
|
+
"hasRole": false,
|
|
1150
|
+
"role": "0x114e74f6ea3bd819998f78687bfcb11b140da08e9b7d222fa9c1f1ba1f2aa122",
|
|
1151
|
+
"sender": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1152
|
+
},
|
|
1153
|
+
]
|
|
1154
|
+
`)
|
|
1155
|
+
})
|
|
1156
|
+
})
|
|
1157
|
+
|
|
1158
|
+
describe('renounceTokenRole', async () => {
|
|
1159
|
+
test('default', async () => {
|
|
1160
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1161
|
+
admin: client.account,
|
|
1162
|
+
currency: 'USD',
|
|
1163
|
+
name: 'Test Token 3',
|
|
1164
|
+
symbol: 'TEST3',
|
|
1165
|
+
})
|
|
1166
|
+
|
|
1167
|
+
const { receipt: grantReceipt } = await actions.token.grantRolesSync(
|
|
1168
|
+
client,
|
|
1169
|
+
{
|
|
1170
|
+
token: address,
|
|
1171
|
+
roles: ['issuer'],
|
|
1172
|
+
to: client.account.address,
|
|
1173
|
+
},
|
|
1174
|
+
)
|
|
1175
|
+
expect(grantReceipt.status).toBe('success')
|
|
1176
|
+
|
|
1177
|
+
const { receipt: renounceReceipt, value: renounceValue } =
|
|
1178
|
+
await actions.token.renounceRolesSync(client, {
|
|
1179
|
+
token: address,
|
|
1180
|
+
roles: ['issuer'],
|
|
1181
|
+
})
|
|
1182
|
+
|
|
1183
|
+
expect(renounceReceipt.status).toBe('success')
|
|
1184
|
+
expect(renounceValue).toMatchInlineSnapshot(`
|
|
1185
|
+
[
|
|
1186
|
+
{
|
|
1187
|
+
"account": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1188
|
+
"hasRole": false,
|
|
1189
|
+
"role": "0x114e74f6ea3bd819998f78687bfcb11b140da08e9b7d222fa9c1f1ba1f2aa122",
|
|
1190
|
+
"sender": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1191
|
+
},
|
|
1192
|
+
]
|
|
1193
|
+
`)
|
|
1194
|
+
})
|
|
1195
|
+
})
|
|
1196
|
+
|
|
1197
|
+
describe.todo('setRoleAdmin')
|
|
1198
|
+
|
|
1199
|
+
describe('watchCreate', () => {
|
|
1200
|
+
test('default', async () => {
|
|
1201
|
+
const receivedTokens: Array<{
|
|
1202
|
+
args: actions.token.watchCreate.Args
|
|
1203
|
+
log: actions.token.watchCreate.Log
|
|
1204
|
+
}> = []
|
|
1205
|
+
|
|
1206
|
+
const unwatch = actions.token.watchCreate(client, {
|
|
1207
|
+
onTokenCreated: (args, log) => {
|
|
1208
|
+
receivedTokens.push({ args, log })
|
|
1209
|
+
},
|
|
1210
|
+
})
|
|
1211
|
+
|
|
1212
|
+
try {
|
|
1213
|
+
await actions.token.createSync(client, {
|
|
1214
|
+
currency: 'USD',
|
|
1215
|
+
name: 'Watch Test Token 1',
|
|
1216
|
+
symbol: 'WATCH1',
|
|
1217
|
+
})
|
|
1218
|
+
|
|
1219
|
+
await actions.token.createSync(client, {
|
|
1220
|
+
currency: 'USD',
|
|
1221
|
+
name: 'Watch Test Token 2',
|
|
1222
|
+
symbol: 'WATCH2',
|
|
1223
|
+
})
|
|
1224
|
+
|
|
1225
|
+
await setTimeout(100)
|
|
1226
|
+
|
|
1227
|
+
expect(receivedTokens).toHaveLength(2)
|
|
1228
|
+
|
|
1229
|
+
expect(receivedTokens.at(0)!.args).toMatchInlineSnapshot(`
|
|
1230
|
+
{
|
|
1231
|
+
"admin": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1232
|
+
"currency": "USD",
|
|
1233
|
+
"name": "Watch Test Token 1",
|
|
1234
|
+
"symbol": "WATCH1",
|
|
1235
|
+
"token": "0x20C0000000000000000000000000000000000001",
|
|
1236
|
+
"tokenId": 1n,
|
|
1237
|
+
}
|
|
1238
|
+
`)
|
|
1239
|
+
expect(receivedTokens.at(1)!.args).toMatchInlineSnapshot(`
|
|
1240
|
+
{
|
|
1241
|
+
"admin": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1242
|
+
"currency": "USD",
|
|
1243
|
+
"name": "Watch Test Token 2",
|
|
1244
|
+
"symbol": "WATCH2",
|
|
1245
|
+
"token": "0x20C0000000000000000000000000000000000002",
|
|
1246
|
+
"tokenId": 2n,
|
|
1247
|
+
}
|
|
1248
|
+
`)
|
|
1249
|
+
} finally {
|
|
1250
|
+
// Clean up watcher
|
|
1251
|
+
if (unwatch) unwatch()
|
|
1252
|
+
}
|
|
1253
|
+
})
|
|
1254
|
+
|
|
1255
|
+
test('behavior: filter by tokenId', async () => {
|
|
1256
|
+
// First, create a token to know what ID we're at
|
|
1257
|
+
const { tokenId: firstId } = await actions.token.createSync(client, {
|
|
1258
|
+
currency: 'USD',
|
|
1259
|
+
name: 'Setup Token',
|
|
1260
|
+
symbol: 'SETUP',
|
|
1261
|
+
})
|
|
1262
|
+
|
|
1263
|
+
// We want to watch for the token with ID = firstId + 2
|
|
1264
|
+
const targetTokenId = firstId + 2n
|
|
1265
|
+
|
|
1266
|
+
const receivedTokens: Array<{
|
|
1267
|
+
args: actions.token.watchCreate.Args
|
|
1268
|
+
log: actions.token.watchCreate.Log
|
|
1269
|
+
}> = []
|
|
1270
|
+
|
|
1271
|
+
// Start watching for token creation events only for targetTokenId
|
|
1272
|
+
const unwatch = actions.token.watchCreate(client, {
|
|
1273
|
+
args: {
|
|
1274
|
+
tokenId: targetTokenId,
|
|
1275
|
+
},
|
|
1276
|
+
onTokenCreated: (args, log) => {
|
|
1277
|
+
receivedTokens.push({ args, log })
|
|
1278
|
+
},
|
|
1279
|
+
})
|
|
1280
|
+
|
|
1281
|
+
try {
|
|
1282
|
+
// Create first token (should NOT be captured - ID will be firstId + 1)
|
|
1283
|
+
await actions.token.createSync(client, {
|
|
1284
|
+
currency: 'USD',
|
|
1285
|
+
name: 'Filtered Watch Token 1',
|
|
1286
|
+
symbol: 'FWATCH1',
|
|
1287
|
+
})
|
|
1288
|
+
|
|
1289
|
+
// Create second token (should be captured - ID will be firstId + 2 = targetTokenId)
|
|
1290
|
+
const { tokenId: id2 } = await actions.token.createSync(client, {
|
|
1291
|
+
currency: 'USD',
|
|
1292
|
+
name: 'Filtered Watch Token 2',
|
|
1293
|
+
symbol: 'FWATCH2',
|
|
1294
|
+
})
|
|
1295
|
+
|
|
1296
|
+
// Create third token (should NOT be captured - ID will be firstId + 3)
|
|
1297
|
+
await actions.token.createSync(client, {
|
|
1298
|
+
currency: 'USD',
|
|
1299
|
+
name: 'Filtered Watch Token 3',
|
|
1300
|
+
symbol: 'FWATCH3',
|
|
1301
|
+
})
|
|
1302
|
+
|
|
1303
|
+
await setTimeout(100)
|
|
1304
|
+
|
|
1305
|
+
// Should only receive 1 event (for targetTokenId)
|
|
1306
|
+
expect(receivedTokens).toHaveLength(1)
|
|
1307
|
+
|
|
1308
|
+
expect(receivedTokens.at(0)!.args.tokenId).toBe(targetTokenId)
|
|
1309
|
+
expect(receivedTokens.at(0)!.args.tokenId).toBe(id2)
|
|
1310
|
+
expect(receivedTokens.at(0)!.args).toMatchInlineSnapshot(`
|
|
1311
|
+
{
|
|
1312
|
+
"admin": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1313
|
+
"currency": "USD",
|
|
1314
|
+
"name": "Filtered Watch Token 2",
|
|
1315
|
+
"symbol": "FWATCH2",
|
|
1316
|
+
"token": "0x20C0000000000000000000000000000000000003",
|
|
1317
|
+
"tokenId": 3n,
|
|
1318
|
+
}
|
|
1319
|
+
`)
|
|
1320
|
+
|
|
1321
|
+
// Verify the received token has the expected tokenId
|
|
1322
|
+
expect(receivedTokens.at(0)!.args.tokenId).toBe(targetTokenId)
|
|
1323
|
+
} finally {
|
|
1324
|
+
if (unwatch) unwatch()
|
|
1325
|
+
}
|
|
1326
|
+
})
|
|
1327
|
+
})
|
|
1328
|
+
|
|
1329
|
+
describe('watchMint', () => {
|
|
1330
|
+
test('default', async () => {
|
|
1331
|
+
// Create a new token for testing
|
|
1332
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1333
|
+
currency: 'USD',
|
|
1334
|
+
name: 'Mint Watch Token',
|
|
1335
|
+
symbol: 'MINT',
|
|
1336
|
+
})
|
|
1337
|
+
|
|
1338
|
+
// Grant issuer role
|
|
1339
|
+
await actions.token.grantRolesSync(client, {
|
|
1340
|
+
token: address,
|
|
1341
|
+
roles: ['issuer'],
|
|
1342
|
+
to: client.account.address,
|
|
1343
|
+
})
|
|
1344
|
+
|
|
1345
|
+
const receivedMints: Array<{
|
|
1346
|
+
args: actions.token.watchMint.Args
|
|
1347
|
+
log: actions.token.watchMint.Log
|
|
1348
|
+
}> = []
|
|
1349
|
+
|
|
1350
|
+
// Start watching for mint events
|
|
1351
|
+
const unwatch = actions.token.watchMint(client, {
|
|
1352
|
+
token: address,
|
|
1353
|
+
onMint: (args, log) => {
|
|
1354
|
+
receivedMints.push({ args, log })
|
|
1355
|
+
},
|
|
1356
|
+
})
|
|
1357
|
+
|
|
1358
|
+
try {
|
|
1359
|
+
// Mint first batch
|
|
1360
|
+
await actions.token.mintSync(client, {
|
|
1361
|
+
token: address,
|
|
1362
|
+
to: account2.address,
|
|
1363
|
+
amount: parseEther('100'),
|
|
1364
|
+
})
|
|
1365
|
+
|
|
1366
|
+
// Mint second batch
|
|
1367
|
+
await actions.token.mintSync(client, {
|
|
1368
|
+
token: address,
|
|
1369
|
+
to: account3.address,
|
|
1370
|
+
amount: parseEther('50'),
|
|
1371
|
+
})
|
|
1372
|
+
|
|
1373
|
+
await setTimeout(100)
|
|
1374
|
+
|
|
1375
|
+
expect(receivedMints).toHaveLength(2)
|
|
1376
|
+
|
|
1377
|
+
expect(receivedMints.at(0)!.args).toMatchInlineSnapshot(`
|
|
1378
|
+
{
|
|
1379
|
+
"amount": 100000000000000000000n,
|
|
1380
|
+
"to": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
1381
|
+
}
|
|
1382
|
+
`)
|
|
1383
|
+
expect(receivedMints.at(1)!.args).toMatchInlineSnapshot(`
|
|
1384
|
+
{
|
|
1385
|
+
"amount": 50000000000000000000n,
|
|
1386
|
+
"to": "0x98e503f35D0a019cB0a251aD243a4cCFCF371F46",
|
|
1387
|
+
}
|
|
1388
|
+
`)
|
|
1389
|
+
} finally {
|
|
1390
|
+
if (unwatch) unwatch()
|
|
1391
|
+
}
|
|
1392
|
+
})
|
|
1393
|
+
|
|
1394
|
+
test('behavior: filter by to address', async () => {
|
|
1395
|
+
// Create a new token for testing
|
|
1396
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1397
|
+
currency: 'USD',
|
|
1398
|
+
name: 'Filtered Mint Token',
|
|
1399
|
+
symbol: 'FMINT',
|
|
1400
|
+
})
|
|
1401
|
+
|
|
1402
|
+
// Grant issuer role
|
|
1403
|
+
await actions.token.grantRolesSync(client, {
|
|
1404
|
+
token: address,
|
|
1405
|
+
roles: ['issuer'],
|
|
1406
|
+
to: client.account.address,
|
|
1407
|
+
})
|
|
1408
|
+
|
|
1409
|
+
const receivedMints: Array<{
|
|
1410
|
+
args: actions.token.watchMint.Args
|
|
1411
|
+
log: actions.token.watchMint.Log
|
|
1412
|
+
}> = []
|
|
1413
|
+
|
|
1414
|
+
// Start watching for mint events only to account2
|
|
1415
|
+
const unwatch = actions.token.watchMint(client, {
|
|
1416
|
+
token: address,
|
|
1417
|
+
args: {
|
|
1418
|
+
to: account2.address,
|
|
1419
|
+
},
|
|
1420
|
+
onMint: (args, log) => {
|
|
1421
|
+
receivedMints.push({ args, log })
|
|
1422
|
+
},
|
|
1423
|
+
})
|
|
1424
|
+
|
|
1425
|
+
try {
|
|
1426
|
+
// Mint to account2 (should be captured)
|
|
1427
|
+
await actions.token.mintSync(client, {
|
|
1428
|
+
token: address,
|
|
1429
|
+
to: account2.address,
|
|
1430
|
+
amount: parseEther('100'),
|
|
1431
|
+
})
|
|
1432
|
+
|
|
1433
|
+
// Mint to account3 (should NOT be captured)
|
|
1434
|
+
await actions.token.mintSync(client, {
|
|
1435
|
+
token: address,
|
|
1436
|
+
to: account3.address,
|
|
1437
|
+
amount: parseEther('50'),
|
|
1438
|
+
})
|
|
1439
|
+
|
|
1440
|
+
// Mint to account2 again (should be captured)
|
|
1441
|
+
await actions.token.mintSync(client, {
|
|
1442
|
+
token: address,
|
|
1443
|
+
to: account2.address,
|
|
1444
|
+
amount: parseEther('75'),
|
|
1445
|
+
})
|
|
1446
|
+
|
|
1447
|
+
await setTimeout(100)
|
|
1448
|
+
|
|
1449
|
+
// Should only receive 2 events (for account2)
|
|
1450
|
+
expect(receivedMints).toHaveLength(2)
|
|
1451
|
+
|
|
1452
|
+
expect(receivedMints.at(0)!.args).toMatchInlineSnapshot(`
|
|
1453
|
+
{
|
|
1454
|
+
"amount": 100000000000000000000n,
|
|
1455
|
+
"to": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
1456
|
+
}
|
|
1457
|
+
`)
|
|
1458
|
+
expect(receivedMints.at(1)!.args).toMatchInlineSnapshot(`
|
|
1459
|
+
{
|
|
1460
|
+
"amount": 75000000000000000000n,
|
|
1461
|
+
"to": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
1462
|
+
}
|
|
1463
|
+
`)
|
|
1464
|
+
|
|
1465
|
+
// Verify all received mints are to account2
|
|
1466
|
+
for (const mint of receivedMints) {
|
|
1467
|
+
expect(mint.args.to).toBe(account2.address)
|
|
1468
|
+
}
|
|
1469
|
+
} finally {
|
|
1470
|
+
if (unwatch) unwatch()
|
|
1471
|
+
}
|
|
1472
|
+
})
|
|
1473
|
+
})
|
|
1474
|
+
|
|
1475
|
+
describe('watchApprove', () => {
|
|
1476
|
+
test('default', async () => {
|
|
1477
|
+
// Create a new token for testing
|
|
1478
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1479
|
+
currency: 'USD',
|
|
1480
|
+
name: 'Approval Watch Token',
|
|
1481
|
+
symbol: 'APPR',
|
|
1482
|
+
})
|
|
1483
|
+
|
|
1484
|
+
const receivedApprovals: Array<{
|
|
1485
|
+
args: actions.token.watchApprove.Args
|
|
1486
|
+
log: actions.token.watchApprove.Log
|
|
1487
|
+
}> = []
|
|
1488
|
+
|
|
1489
|
+
// Start watching for approval events
|
|
1490
|
+
const unwatch = actions.token.watchApprove(client, {
|
|
1491
|
+
token: address,
|
|
1492
|
+
onApproval: (args, log) => {
|
|
1493
|
+
receivedApprovals.push({ args, log })
|
|
1494
|
+
},
|
|
1495
|
+
})
|
|
1496
|
+
|
|
1497
|
+
try {
|
|
1498
|
+
// Approve account2
|
|
1499
|
+
await actions.token.approveSync(client, {
|
|
1500
|
+
token: address,
|
|
1501
|
+
spender: account2.address,
|
|
1502
|
+
amount: parseEther('100'),
|
|
1503
|
+
})
|
|
1504
|
+
|
|
1505
|
+
// Approve account3
|
|
1506
|
+
await actions.token.approveSync(client, {
|
|
1507
|
+
token: address,
|
|
1508
|
+
spender: account3.address,
|
|
1509
|
+
amount: parseEther('50'),
|
|
1510
|
+
})
|
|
1511
|
+
|
|
1512
|
+
await setTimeout(100)
|
|
1513
|
+
|
|
1514
|
+
expect(receivedApprovals).toHaveLength(2)
|
|
1515
|
+
|
|
1516
|
+
expect(receivedApprovals.at(0)!.args).toMatchInlineSnapshot(`
|
|
1517
|
+
{
|
|
1518
|
+
"amount": 100000000000000000000n,
|
|
1519
|
+
"owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1520
|
+
"spender": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
1521
|
+
}
|
|
1522
|
+
`)
|
|
1523
|
+
expect(receivedApprovals.at(1)!.args).toMatchInlineSnapshot(`
|
|
1524
|
+
{
|
|
1525
|
+
"amount": 50000000000000000000n,
|
|
1526
|
+
"owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1527
|
+
"spender": "0x98e503f35D0a019cB0a251aD243a4cCFCF371F46",
|
|
1528
|
+
}
|
|
1529
|
+
`)
|
|
1530
|
+
} finally {
|
|
1531
|
+
if (unwatch) unwatch()
|
|
1532
|
+
}
|
|
1533
|
+
})
|
|
1534
|
+
|
|
1535
|
+
test('behavior: filter by spender address', async () => {
|
|
1536
|
+
// Create a new token for testing
|
|
1537
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1538
|
+
currency: 'USD',
|
|
1539
|
+
name: 'Filtered Approval Token',
|
|
1540
|
+
symbol: 'FAPPR',
|
|
1541
|
+
})
|
|
1542
|
+
|
|
1543
|
+
const receivedApprovals: Array<{
|
|
1544
|
+
args: actions.token.watchApprove.Args
|
|
1545
|
+
log: actions.token.watchApprove.Log
|
|
1546
|
+
}> = []
|
|
1547
|
+
|
|
1548
|
+
// Start watching for approval events only to account2
|
|
1549
|
+
const unwatch = actions.token.watchApprove(client, {
|
|
1550
|
+
token: address,
|
|
1551
|
+
args: {
|
|
1552
|
+
spender: account2.address,
|
|
1553
|
+
},
|
|
1554
|
+
onApproval: (args, log) => {
|
|
1555
|
+
receivedApprovals.push({ args, log })
|
|
1556
|
+
},
|
|
1557
|
+
})
|
|
1558
|
+
|
|
1559
|
+
try {
|
|
1560
|
+
// Approve account2 (should be captured)
|
|
1561
|
+
await actions.token.approveSync(client, {
|
|
1562
|
+
token: address,
|
|
1563
|
+
spender: account2.address,
|
|
1564
|
+
amount: parseEther('100'),
|
|
1565
|
+
})
|
|
1566
|
+
|
|
1567
|
+
// Approve account3 (should NOT be captured)
|
|
1568
|
+
await actions.token.approveSync(client, {
|
|
1569
|
+
token: address,
|
|
1570
|
+
spender: account3.address,
|
|
1571
|
+
amount: parseEther('50'),
|
|
1572
|
+
})
|
|
1573
|
+
|
|
1574
|
+
// Approve account2 again (should be captured)
|
|
1575
|
+
await actions.token.approveSync(client, {
|
|
1576
|
+
token: address,
|
|
1577
|
+
spender: account2.address,
|
|
1578
|
+
amount: parseEther('75'),
|
|
1579
|
+
})
|
|
1580
|
+
|
|
1581
|
+
await setTimeout(100)
|
|
1582
|
+
|
|
1583
|
+
// Should only receive 2 events (for account2)
|
|
1584
|
+
expect(receivedApprovals).toHaveLength(2)
|
|
1585
|
+
|
|
1586
|
+
expect(receivedApprovals.at(0)!.args).toMatchInlineSnapshot(`
|
|
1587
|
+
{
|
|
1588
|
+
"amount": 100000000000000000000n,
|
|
1589
|
+
"owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1590
|
+
"spender": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
1591
|
+
}
|
|
1592
|
+
`)
|
|
1593
|
+
expect(receivedApprovals.at(1)!.args).toMatchInlineSnapshot(`
|
|
1594
|
+
{
|
|
1595
|
+
"amount": 75000000000000000000n,
|
|
1596
|
+
"owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1597
|
+
"spender": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
1598
|
+
}
|
|
1599
|
+
`)
|
|
1600
|
+
|
|
1601
|
+
// Verify all received approvals are for account2
|
|
1602
|
+
for (const approval of receivedApprovals) {
|
|
1603
|
+
expect(approval.args.spender).toBe(account2.address)
|
|
1604
|
+
}
|
|
1605
|
+
} finally {
|
|
1606
|
+
if (unwatch) unwatch()
|
|
1607
|
+
}
|
|
1608
|
+
})
|
|
1609
|
+
})
|
|
1610
|
+
|
|
1611
|
+
describe('watchBurn', () => {
|
|
1612
|
+
test('default', async () => {
|
|
1613
|
+
// Create a new token for testing
|
|
1614
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1615
|
+
currency: 'USD',
|
|
1616
|
+
name: 'Burn Watch Token',
|
|
1617
|
+
symbol: 'BURN',
|
|
1618
|
+
})
|
|
1619
|
+
|
|
1620
|
+
// Grant issuer role to mint/burn tokens
|
|
1621
|
+
await actions.token.grantRolesSync(client, {
|
|
1622
|
+
token: address,
|
|
1623
|
+
roles: ['issuer'],
|
|
1624
|
+
to: client.account.address,
|
|
1625
|
+
})
|
|
1626
|
+
|
|
1627
|
+
// Grant issuer role to mint/burn tokens
|
|
1628
|
+
await actions.token.grantRolesSync(client, {
|
|
1629
|
+
token: address,
|
|
1630
|
+
roles: ['issuer'],
|
|
1631
|
+
to: account2.address,
|
|
1632
|
+
})
|
|
1633
|
+
|
|
1634
|
+
// Mint tokens to burn later
|
|
1635
|
+
await actions.token.mintSync(client, {
|
|
1636
|
+
token: address,
|
|
1637
|
+
to: client.account.address,
|
|
1638
|
+
amount: parseEther('200'),
|
|
1639
|
+
})
|
|
1640
|
+
|
|
1641
|
+
await actions.token.mintSync(client, {
|
|
1642
|
+
token: address,
|
|
1643
|
+
to: account2.address,
|
|
1644
|
+
amount: parseEther('100'),
|
|
1645
|
+
})
|
|
1646
|
+
|
|
1647
|
+
const receivedBurns: Array<{
|
|
1648
|
+
args: actions.token.watchBurn.Args
|
|
1649
|
+
log: actions.token.watchBurn.Log
|
|
1650
|
+
}> = []
|
|
1651
|
+
|
|
1652
|
+
// Start watching for burn events
|
|
1653
|
+
const unwatch = actions.token.watchBurn(client, {
|
|
1654
|
+
token: address,
|
|
1655
|
+
onBurn: (args, log) => {
|
|
1656
|
+
receivedBurns.push({ args, log })
|
|
1657
|
+
},
|
|
1658
|
+
})
|
|
1659
|
+
|
|
1660
|
+
try {
|
|
1661
|
+
// Burn first batch
|
|
1662
|
+
await actions.token.burnSync(client, {
|
|
1663
|
+
token: address,
|
|
1664
|
+
amount: parseEther('50'),
|
|
1665
|
+
})
|
|
1666
|
+
|
|
1667
|
+
// Transfer gas to account2
|
|
1668
|
+
await writeContractSync(client, {
|
|
1669
|
+
abi: tip20Abi,
|
|
1670
|
+
address: usdAddress,
|
|
1671
|
+
functionName: 'transfer',
|
|
1672
|
+
args: [account2.address, parseEther('1')],
|
|
1673
|
+
})
|
|
1674
|
+
|
|
1675
|
+
// Burn second batch from account2
|
|
1676
|
+
await actions.token.burnSync(client, {
|
|
1677
|
+
account: account2,
|
|
1678
|
+
token: address,
|
|
1679
|
+
amount: parseEther('25'),
|
|
1680
|
+
})
|
|
1681
|
+
|
|
1682
|
+
await setTimeout(100)
|
|
1683
|
+
|
|
1684
|
+
expect(receivedBurns).toHaveLength(2)
|
|
1685
|
+
|
|
1686
|
+
expect(receivedBurns.at(0)!.args).toMatchInlineSnapshot(`
|
|
1687
|
+
{
|
|
1688
|
+
"amount": 50000000000000000000n,
|
|
1689
|
+
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1690
|
+
}
|
|
1691
|
+
`)
|
|
1692
|
+
expect(receivedBurns.at(1)!.args).toMatchInlineSnapshot(`
|
|
1693
|
+
{
|
|
1694
|
+
"amount": 25000000000000000000n,
|
|
1695
|
+
"from": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
1696
|
+
}
|
|
1697
|
+
`)
|
|
1698
|
+
} finally {
|
|
1699
|
+
if (unwatch) unwatch()
|
|
1700
|
+
}
|
|
1701
|
+
})
|
|
1702
|
+
|
|
1703
|
+
test('behavior: filter by from address', async () => {
|
|
1704
|
+
// Create a new token for testing
|
|
1705
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1706
|
+
currency: 'USD',
|
|
1707
|
+
name: 'Filtered Burn Token',
|
|
1708
|
+
symbol: 'FBURN',
|
|
1709
|
+
})
|
|
1710
|
+
|
|
1711
|
+
// Grant issuer role
|
|
1712
|
+
await actions.token.grantRolesSync(client, {
|
|
1713
|
+
token: address,
|
|
1714
|
+
roles: ['issuer'],
|
|
1715
|
+
to: client.account.address,
|
|
1716
|
+
})
|
|
1717
|
+
|
|
1718
|
+
// Grant issuer role
|
|
1719
|
+
await actions.token.grantRolesSync(client, {
|
|
1720
|
+
token: address,
|
|
1721
|
+
roles: ['issuer'],
|
|
1722
|
+
to: account2.address,
|
|
1723
|
+
})
|
|
1724
|
+
|
|
1725
|
+
// Mint tokens to multiple accounts
|
|
1726
|
+
await actions.token.mintSync(client, {
|
|
1727
|
+
token: address,
|
|
1728
|
+
to: client.account.address,
|
|
1729
|
+
amount: parseEther('200'),
|
|
1730
|
+
})
|
|
1731
|
+
|
|
1732
|
+
await actions.token.mintSync(client, {
|
|
1733
|
+
token: address,
|
|
1734
|
+
to: account2.address,
|
|
1735
|
+
amount: parseEther('200'),
|
|
1736
|
+
})
|
|
1737
|
+
|
|
1738
|
+
const receivedBurns: Array<{
|
|
1739
|
+
args: actions.token.watchBurn.Args
|
|
1740
|
+
log: actions.token.watchBurn.Log
|
|
1741
|
+
}> = []
|
|
1742
|
+
|
|
1743
|
+
// Start watching for burn events only from client.account
|
|
1744
|
+
const unwatch = actions.token.watchBurn(client, {
|
|
1745
|
+
token: address,
|
|
1746
|
+
args: {
|
|
1747
|
+
from: client.account.address,
|
|
1748
|
+
},
|
|
1749
|
+
onBurn: (args, log) => {
|
|
1750
|
+
receivedBurns.push({ args, log })
|
|
1751
|
+
},
|
|
1752
|
+
})
|
|
1753
|
+
|
|
1754
|
+
try {
|
|
1755
|
+
// Burn from client.account (should be captured)
|
|
1756
|
+
await actions.token.burnSync(client, {
|
|
1757
|
+
token: address,
|
|
1758
|
+
amount: parseEther('50'),
|
|
1759
|
+
})
|
|
1760
|
+
|
|
1761
|
+
// Transfer gas to account2
|
|
1762
|
+
await writeContractSync(client, {
|
|
1763
|
+
abi: tip20Abi,
|
|
1764
|
+
address: usdAddress,
|
|
1765
|
+
functionName: 'transfer',
|
|
1766
|
+
args: [account2.address, parseEther('1')],
|
|
1767
|
+
})
|
|
1768
|
+
|
|
1769
|
+
// Burn from account2 (should NOT be captured)
|
|
1770
|
+
await actions.token.burnSync(client, {
|
|
1771
|
+
account: account2,
|
|
1772
|
+
token: address,
|
|
1773
|
+
amount: parseEther('25'),
|
|
1774
|
+
})
|
|
1775
|
+
|
|
1776
|
+
// Burn from client.account again (should be captured)
|
|
1777
|
+
await actions.token.burnSync(client, {
|
|
1778
|
+
token: address,
|
|
1779
|
+
amount: parseEther('75'),
|
|
1780
|
+
})
|
|
1781
|
+
|
|
1782
|
+
await setTimeout(100)
|
|
1783
|
+
|
|
1784
|
+
// Should only receive 2 events (from client.account)
|
|
1785
|
+
expect(receivedBurns).toHaveLength(2)
|
|
1786
|
+
|
|
1787
|
+
expect(receivedBurns.at(0)!.args).toMatchInlineSnapshot(`
|
|
1788
|
+
{
|
|
1789
|
+
"amount": 50000000000000000000n,
|
|
1790
|
+
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1791
|
+
}
|
|
1792
|
+
`)
|
|
1793
|
+
expect(receivedBurns.at(1)!.args).toMatchInlineSnapshot(`
|
|
1794
|
+
{
|
|
1795
|
+
"amount": 75000000000000000000n,
|
|
1796
|
+
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1797
|
+
}
|
|
1798
|
+
`)
|
|
1799
|
+
|
|
1800
|
+
// Verify all received burns are from client.account
|
|
1801
|
+
for (const burn of receivedBurns) {
|
|
1802
|
+
expect(burn.args.from).toBe(client.account.address)
|
|
1803
|
+
}
|
|
1804
|
+
} finally {
|
|
1805
|
+
if (unwatch) unwatch()
|
|
1806
|
+
}
|
|
1807
|
+
})
|
|
1808
|
+
})
|
|
1809
|
+
|
|
1810
|
+
describe('watchAdminRole', () => {
|
|
1811
|
+
test('default', async () => {
|
|
1812
|
+
// Create a new token for testing
|
|
1813
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1814
|
+
currency: 'USD',
|
|
1815
|
+
name: 'Admin Role Watch Token',
|
|
1816
|
+
symbol: 'ADMIN',
|
|
1817
|
+
})
|
|
1818
|
+
|
|
1819
|
+
const receivedAdminUpdates: Array<{
|
|
1820
|
+
args: actions.token.watchAdminRole.Args
|
|
1821
|
+
log: actions.token.watchAdminRole.Log
|
|
1822
|
+
}> = []
|
|
1823
|
+
|
|
1824
|
+
// Start watching for role admin updates
|
|
1825
|
+
const unwatch = actions.token.watchAdminRole(client, {
|
|
1826
|
+
token: address,
|
|
1827
|
+
onRoleAdminUpdated: (args, log) => {
|
|
1828
|
+
receivedAdminUpdates.push({ args, log })
|
|
1829
|
+
},
|
|
1830
|
+
})
|
|
1831
|
+
|
|
1832
|
+
try {
|
|
1833
|
+
// Set role admin for issuer role
|
|
1834
|
+
const { receipt: setRoleAdmin1Receipt, ...setRoleAdmin1Result } =
|
|
1835
|
+
await actions.token.setRoleAdminSync(client, {
|
|
1836
|
+
token: address,
|
|
1837
|
+
role: 'issuer',
|
|
1838
|
+
adminRole: 'pause',
|
|
1839
|
+
})
|
|
1840
|
+
expect(setRoleAdmin1Receipt).toBeDefined()
|
|
1841
|
+
expect(setRoleAdmin1Result).toMatchInlineSnapshot(`
|
|
1842
|
+
{
|
|
1843
|
+
"newAdminRole": "0x139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d",
|
|
1844
|
+
"role": "0x114e74f6ea3bd819998f78687bfcb11b140da08e9b7d222fa9c1f1ba1f2aa122",
|
|
1845
|
+
"sender": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
1846
|
+
}
|
|
1847
|
+
`)
|
|
1848
|
+
|
|
1849
|
+
// Set role admin for pause role
|
|
1850
|
+
await actions.token.setRoleAdminSync(client, {
|
|
1851
|
+
token: address,
|
|
1852
|
+
role: 'pause',
|
|
1853
|
+
adminRole: 'unpause',
|
|
1854
|
+
})
|
|
1855
|
+
|
|
1856
|
+
await setTimeout(100)
|
|
1857
|
+
|
|
1858
|
+
expect(receivedAdminUpdates).toHaveLength(2)
|
|
1859
|
+
|
|
1860
|
+
expect(receivedAdminUpdates.at(0)!.args.sender).toBe(
|
|
1861
|
+
client.account.address,
|
|
1862
|
+
)
|
|
1863
|
+
expect(receivedAdminUpdates.at(1)!.args.sender).toBe(
|
|
1864
|
+
client.account.address,
|
|
1865
|
+
)
|
|
1866
|
+
} finally {
|
|
1867
|
+
if (unwatch) unwatch()
|
|
1868
|
+
}
|
|
1869
|
+
})
|
|
1870
|
+
})
|
|
1871
|
+
|
|
1872
|
+
describe('watchRole', () => {
|
|
1873
|
+
test('default', async () => {
|
|
1874
|
+
// Create a new token for testing
|
|
1875
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1876
|
+
currency: 'USD',
|
|
1877
|
+
name: 'Role Watch Token',
|
|
1878
|
+
symbol: 'ROLE',
|
|
1879
|
+
})
|
|
1880
|
+
|
|
1881
|
+
const receivedRoleUpdates: Array<{
|
|
1882
|
+
args: actions.token.watchRole.Args
|
|
1883
|
+
log: actions.token.watchRole.Log
|
|
1884
|
+
}> = []
|
|
1885
|
+
|
|
1886
|
+
// Start watching for role membership updates
|
|
1887
|
+
const unwatch = actions.token.watchRole(client, {
|
|
1888
|
+
token: address,
|
|
1889
|
+
onRoleUpdated: (args, log) => {
|
|
1890
|
+
receivedRoleUpdates.push({ args, log })
|
|
1891
|
+
},
|
|
1892
|
+
})
|
|
1893
|
+
|
|
1894
|
+
try {
|
|
1895
|
+
// Grant issuer role to account2
|
|
1896
|
+
await actions.token.grantRolesSync(client, {
|
|
1897
|
+
token: address,
|
|
1898
|
+
roles: ['issuer'],
|
|
1899
|
+
to: account2.address,
|
|
1900
|
+
})
|
|
1901
|
+
|
|
1902
|
+
// Grant pause role to account3
|
|
1903
|
+
await actions.token.grantRolesSync(client, {
|
|
1904
|
+
token: address,
|
|
1905
|
+
roles: ['pause'],
|
|
1906
|
+
to: account3.address,
|
|
1907
|
+
})
|
|
1908
|
+
|
|
1909
|
+
// Revoke issuer role from account2
|
|
1910
|
+
await actions.token.revokeRolesSync(client, {
|
|
1911
|
+
token: address,
|
|
1912
|
+
roles: ['issuer'],
|
|
1913
|
+
from: account2.address,
|
|
1914
|
+
})
|
|
1915
|
+
|
|
1916
|
+
await setTimeout(100)
|
|
1917
|
+
|
|
1918
|
+
expect(receivedRoleUpdates).toHaveLength(3)
|
|
1919
|
+
|
|
1920
|
+
// First event: grant issuer
|
|
1921
|
+
expect(receivedRoleUpdates.at(0)!.args.type).toBe('granted')
|
|
1922
|
+
expect(receivedRoleUpdates.at(0)!.args.account).toBe(account2.address)
|
|
1923
|
+
expect(receivedRoleUpdates.at(0)!.args.hasRole).toBe(true)
|
|
1924
|
+
|
|
1925
|
+
// Second event: grant pause
|
|
1926
|
+
expect(receivedRoleUpdates.at(1)!.args.type).toBe('granted')
|
|
1927
|
+
expect(receivedRoleUpdates.at(1)!.args.account).toBe(account3.address)
|
|
1928
|
+
expect(receivedRoleUpdates.at(1)!.args.hasRole).toBe(true)
|
|
1929
|
+
|
|
1930
|
+
// Third event: revoke issuer
|
|
1931
|
+
expect(receivedRoleUpdates.at(2)!.args.type).toBe('revoked')
|
|
1932
|
+
expect(receivedRoleUpdates.at(2)!.args.account).toBe(account2.address)
|
|
1933
|
+
expect(receivedRoleUpdates.at(2)!.args.hasRole).toBe(false)
|
|
1934
|
+
} finally {
|
|
1935
|
+
if (unwatch) unwatch()
|
|
1936
|
+
}
|
|
1937
|
+
})
|
|
1938
|
+
|
|
1939
|
+
test('behavior: filter by account address', async () => {
|
|
1940
|
+
// Create a new token for testing
|
|
1941
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
1942
|
+
currency: 'USD',
|
|
1943
|
+
name: 'Filtered Role Token',
|
|
1944
|
+
symbol: 'FROLE',
|
|
1945
|
+
})
|
|
1946
|
+
|
|
1947
|
+
const receivedRoleUpdates: Array<{
|
|
1948
|
+
args: actions.token.watchRole.Args
|
|
1949
|
+
log: actions.token.watchRole.Log
|
|
1950
|
+
}> = []
|
|
1951
|
+
|
|
1952
|
+
// Start watching for role updates only for account2
|
|
1953
|
+
const unwatch = actions.token.watchRole(client, {
|
|
1954
|
+
token: address,
|
|
1955
|
+
args: {
|
|
1956
|
+
account: account2.address,
|
|
1957
|
+
},
|
|
1958
|
+
onRoleUpdated: (args, log) => {
|
|
1959
|
+
receivedRoleUpdates.push({ args, log })
|
|
1960
|
+
},
|
|
1961
|
+
})
|
|
1962
|
+
|
|
1963
|
+
try {
|
|
1964
|
+
// Grant issuer role to account2 (should be captured)
|
|
1965
|
+
await actions.token.grantRolesSync(client, {
|
|
1966
|
+
token: address,
|
|
1967
|
+
roles: ['issuer'],
|
|
1968
|
+
to: account2.address,
|
|
1969
|
+
})
|
|
1970
|
+
|
|
1971
|
+
// Grant pause role to account3 (should NOT be captured)
|
|
1972
|
+
await actions.token.grantRolesSync(client, {
|
|
1973
|
+
token: address,
|
|
1974
|
+
roles: ['pause'],
|
|
1975
|
+
to: account3.address,
|
|
1976
|
+
})
|
|
1977
|
+
|
|
1978
|
+
// Revoke issuer role from account2 (should be captured)
|
|
1979
|
+
await actions.token.revokeRolesSync(client, {
|
|
1980
|
+
token: address,
|
|
1981
|
+
roles: ['issuer'],
|
|
1982
|
+
from: account2.address,
|
|
1983
|
+
})
|
|
1984
|
+
|
|
1985
|
+
await setTimeout(100)
|
|
1986
|
+
|
|
1987
|
+
// Should only receive 2 events (for account2)
|
|
1988
|
+
expect(receivedRoleUpdates).toHaveLength(2)
|
|
1989
|
+
|
|
1990
|
+
// First: grant to account2
|
|
1991
|
+
expect(receivedRoleUpdates.at(0)!.args.type).toBe('granted')
|
|
1992
|
+
expect(receivedRoleUpdates.at(0)!.args.account).toBe(account2.address)
|
|
1993
|
+
expect(receivedRoleUpdates.at(0)!.args.hasRole).toBe(true)
|
|
1994
|
+
|
|
1995
|
+
// Second: revoke from account2
|
|
1996
|
+
expect(receivedRoleUpdates.at(1)!.args.type).toBe('revoked')
|
|
1997
|
+
expect(receivedRoleUpdates.at(1)!.args.account).toBe(account2.address)
|
|
1998
|
+
expect(receivedRoleUpdates.at(1)!.args.hasRole).toBe(false)
|
|
1999
|
+
|
|
2000
|
+
// Verify all received events are for account2
|
|
2001
|
+
for (const update of receivedRoleUpdates) {
|
|
2002
|
+
expect(update.args.account).toBe(account2.address)
|
|
2003
|
+
}
|
|
2004
|
+
} finally {
|
|
2005
|
+
if (unwatch) unwatch()
|
|
2006
|
+
}
|
|
2007
|
+
})
|
|
2008
|
+
})
|
|
2009
|
+
|
|
2010
|
+
describe('watchTransfer', () => {
|
|
2011
|
+
test('default', async () => {
|
|
2012
|
+
// Create a new token for testing
|
|
2013
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
2014
|
+
currency: 'USD',
|
|
2015
|
+
name: 'Transfer Watch Token',
|
|
2016
|
+
symbol: 'XFER',
|
|
2017
|
+
})
|
|
2018
|
+
|
|
2019
|
+
// Grant issuer role to mint tokens
|
|
2020
|
+
await actions.token.grantRolesSync(client, {
|
|
2021
|
+
token: address,
|
|
2022
|
+
roles: ['issuer'],
|
|
2023
|
+
to: client.account.address,
|
|
2024
|
+
})
|
|
2025
|
+
|
|
2026
|
+
// Mint tokens to transfer
|
|
2027
|
+
await actions.token.mintSync(client, {
|
|
2028
|
+
token: address,
|
|
2029
|
+
to: client.account.address,
|
|
2030
|
+
amount: parseEther('500'),
|
|
2031
|
+
})
|
|
2032
|
+
|
|
2033
|
+
const receivedTransfers: Array<{
|
|
2034
|
+
args: actions.token.watchTransfer.Args
|
|
2035
|
+
log: actions.token.watchTransfer.Log
|
|
2036
|
+
}> = []
|
|
2037
|
+
|
|
2038
|
+
// Start watching for transfer events
|
|
2039
|
+
const unwatch = actions.token.watchTransfer(client, {
|
|
2040
|
+
token: address,
|
|
2041
|
+
onTransfer: (args, log) => {
|
|
2042
|
+
receivedTransfers.push({ args, log })
|
|
2043
|
+
},
|
|
2044
|
+
})
|
|
2045
|
+
|
|
2046
|
+
try {
|
|
2047
|
+
// Transfer to account2
|
|
2048
|
+
await actions.token.transferSync(client, {
|
|
2049
|
+
token: address,
|
|
2050
|
+
to: account2.address,
|
|
2051
|
+
amount: parseEther('100'),
|
|
2052
|
+
})
|
|
2053
|
+
|
|
2054
|
+
// Transfer to account3
|
|
2055
|
+
await actions.token.transferSync(client, {
|
|
2056
|
+
token: address,
|
|
2057
|
+
to: account3.address,
|
|
2058
|
+
amount: parseEther('50'),
|
|
2059
|
+
})
|
|
2060
|
+
|
|
2061
|
+
await setTimeout(200)
|
|
2062
|
+
|
|
2063
|
+
expect(receivedTransfers).toHaveLength(2)
|
|
2064
|
+
|
|
2065
|
+
expect(receivedTransfers.at(0)!.args).toMatchInlineSnapshot(`
|
|
2066
|
+
{
|
|
2067
|
+
"amount": 100000000000000000000n,
|
|
2068
|
+
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
2069
|
+
"to": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
2070
|
+
}
|
|
2071
|
+
`)
|
|
2072
|
+
expect(receivedTransfers.at(1)!.args).toMatchInlineSnapshot(`
|
|
2073
|
+
{
|
|
2074
|
+
"amount": 50000000000000000000n,
|
|
2075
|
+
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
2076
|
+
"to": "0x98e503f35D0a019cB0a251aD243a4cCFCF371F46",
|
|
2077
|
+
}
|
|
2078
|
+
`)
|
|
2079
|
+
} finally {
|
|
2080
|
+
if (unwatch) unwatch()
|
|
2081
|
+
}
|
|
2082
|
+
})
|
|
2083
|
+
|
|
2084
|
+
test('behavior: filter by to address', async () => {
|
|
2085
|
+
// Create a new token for testing
|
|
2086
|
+
const { token: address } = await actions.token.createSync(client, {
|
|
2087
|
+
currency: 'USD',
|
|
2088
|
+
name: 'Filtered Transfer Token',
|
|
2089
|
+
symbol: 'FXFER',
|
|
2090
|
+
})
|
|
2091
|
+
|
|
2092
|
+
// Grant issuer role
|
|
2093
|
+
await actions.token.grantRolesSync(client, {
|
|
2094
|
+
token: address,
|
|
2095
|
+
roles: ['issuer'],
|
|
2096
|
+
to: client.account.address,
|
|
2097
|
+
})
|
|
2098
|
+
|
|
2099
|
+
// Mint tokens
|
|
2100
|
+
await actions.token.mintSync(client, {
|
|
2101
|
+
token: address,
|
|
2102
|
+
to: client.account.address,
|
|
2103
|
+
amount: parseEther('500'),
|
|
2104
|
+
})
|
|
2105
|
+
|
|
2106
|
+
const receivedTransfers: Array<{
|
|
2107
|
+
args: actions.token.watchTransfer.Args
|
|
2108
|
+
log: actions.token.watchTransfer.Log
|
|
2109
|
+
}> = []
|
|
2110
|
+
|
|
2111
|
+
// Start watching for transfer events only to account2
|
|
2112
|
+
const unwatch = actions.token.watchTransfer(client, {
|
|
2113
|
+
token: address,
|
|
2114
|
+
args: {
|
|
2115
|
+
to: account2.address,
|
|
2116
|
+
},
|
|
2117
|
+
onTransfer: (args, log) => {
|
|
2118
|
+
receivedTransfers.push({ args, log })
|
|
2119
|
+
},
|
|
2120
|
+
})
|
|
2121
|
+
|
|
2122
|
+
try {
|
|
2123
|
+
// Transfer to account2 (should be captured)
|
|
2124
|
+
await actions.token.transferSync(client, {
|
|
2125
|
+
token: address,
|
|
2126
|
+
to: account2.address,
|
|
2127
|
+
amount: parseEther('100'),
|
|
2128
|
+
})
|
|
2129
|
+
|
|
2130
|
+
// Transfer to account3 (should NOT be captured)
|
|
2131
|
+
await actions.token.transferSync(client, {
|
|
2132
|
+
token: address,
|
|
2133
|
+
to: account3.address,
|
|
2134
|
+
amount: parseEther('50'),
|
|
2135
|
+
})
|
|
2136
|
+
|
|
2137
|
+
// Transfer to account2 again (should be captured)
|
|
2138
|
+
await actions.token.transferSync(client, {
|
|
2139
|
+
token: address,
|
|
2140
|
+
to: account2.address,
|
|
2141
|
+
amount: parseEther('75'),
|
|
2142
|
+
})
|
|
2143
|
+
|
|
2144
|
+
await setTimeout(100)
|
|
2145
|
+
|
|
2146
|
+
// Should only receive 2 events (to account2)
|
|
2147
|
+
expect(receivedTransfers).toHaveLength(2)
|
|
2148
|
+
|
|
2149
|
+
expect(receivedTransfers.at(0)!.args).toMatchInlineSnapshot(`
|
|
2150
|
+
{
|
|
2151
|
+
"amount": 100000000000000000000n,
|
|
2152
|
+
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
2153
|
+
"to": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
2154
|
+
}
|
|
2155
|
+
`)
|
|
2156
|
+
expect(receivedTransfers.at(1)!.args).toMatchInlineSnapshot(`
|
|
2157
|
+
{
|
|
2158
|
+
"amount": 75000000000000000000n,
|
|
2159
|
+
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
|
2160
|
+
"to": "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
|
|
2161
|
+
}
|
|
2162
|
+
`)
|
|
2163
|
+
|
|
2164
|
+
// Verify all received transfers are to account2
|
|
2165
|
+
for (const transfer of receivedTransfers) {
|
|
2166
|
+
expect(transfer.args.to).toBe(account2.address)
|
|
2167
|
+
}
|
|
2168
|
+
} finally {
|
|
2169
|
+
if (unwatch) unwatch()
|
|
2170
|
+
}
|
|
2171
|
+
})
|
|
2172
|
+
})
|