@layerzerolabs/lz-v2-stellar-sdk 0.2.121 → 0.2.122
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/.turbo/turbo-build.log +235 -1
- package/.turbo/turbo-lint.log +8 -0
- package/.turbo/turbo-test.log +41 -1361
- package/dist/generated/dvn.d.ts +2 -2
- package/dist/generated/dvn.js +2 -2
- package/dist/generated/endpoint.d.ts +2 -2
- package/dist/generated/endpoint.js +2 -2
- package/dist/generated/executor.d.ts +3 -3
- package/dist/generated/executor.d.ts.map +1 -1
- package/dist/generated/executor.js +3 -3
- package/dist/generated/executor.js.map +1 -1
- package/dist/generated/price_feed.d.ts +2 -2
- package/dist/generated/price_feed.js +2 -2
- package/dist/generated/sml.d.ts +2 -2
- package/dist/generated/sml.js +2 -2
- package/dist/generated/uln302.d.ts +2 -2
- package/dist/generated/uln302.js +2 -2
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -4
- package/dist/index.js.map +1 -1
- package/package.json +13 -12
- package/rust-toolchain.toml +4 -0
- package/src/index.ts +0 -5
- package/test/suites/constants.ts +30 -51
- package/test/suites/deploy.ts +13 -273
- package/test/suites/globalSetup.ts +3 -602
- package/test/upgrader.test.ts +1 -0
- package/test/utils.ts +11 -658
- package/ts-bindings-gen.toml +59 -0
- package/dist/generated/counter.d.ts +0 -1253
- package/dist/generated/counter.d.ts.map +0 -1
- package/dist/generated/counter.js +0 -391
- package/dist/generated/counter.js.map +0 -1
- package/dist/generated/oft.d.ts +0 -1638
- package/dist/generated/oft.d.ts.map +0 -1
- package/dist/generated/oft.js +0 -463
- package/dist/generated/oft.js.map +0 -1
- package/dist/generated/sac_manager.d.ts +0 -567
- package/dist/generated/sac_manager.d.ts.map +0 -1
- package/dist/generated/sac_manager.js +0 -198
- package/dist/generated/sac_manager.js.map +0 -1
- package/src/generated/bml.ts +0 -672
- package/src/generated/counter.ts +0 -1208
- package/src/generated/dvn.ts +0 -1508
- package/src/generated/dvn_fee_lib.ts +0 -595
- package/src/generated/endpoint.ts +0 -1181
- package/src/generated/executor.ts +0 -1521
- package/src/generated/executor_fee_lib.ts +0 -1027
- package/src/generated/executor_helper.ts +0 -833
- package/src/generated/layerzero_view.ts +0 -1119
- package/src/generated/oft.ts +0 -1609
- package/src/generated/price_feed.ts +0 -793
- package/src/generated/sac_manager.ts +0 -555
- package/src/generated/sml.ts +0 -921
- package/src/generated/treasury.ts +0 -887
- package/src/generated/uln302.ts +0 -1224
- package/src/generated/upgrader.ts +0 -276
- package/test/counter-sml.test.ts +0 -480
- package/test/counter-uln.test.ts +0 -584
- package/test/oft-sml.test.ts +0 -750
- package/test/sac-manager.test.ts +0 -464
- package/test/secp256k1.ts +0 -59
- package/test/suites/dummyContractClient.ts +0 -168
- package/test/suites/localnet.ts +0 -192
- package/test/suites/scan.ts +0 -202
- package/turbo.json +0 -15
package/test/sac-manager.test.ts
DELETED
|
@@ -1,464 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Address,
|
|
3
|
-
Asset,
|
|
4
|
-
AuthClawbackEnabledFlag,
|
|
5
|
-
type AuthFlag,
|
|
6
|
-
AuthRevocableFlag,
|
|
7
|
-
BASE_FEE,
|
|
8
|
-
Keypair,
|
|
9
|
-
Operation,
|
|
10
|
-
rpc,
|
|
11
|
-
TransactionBuilder,
|
|
12
|
-
} from '@stellar/stellar-sdk';
|
|
13
|
-
import path from 'path';
|
|
14
|
-
import { beforeAll, describe, expect, it } from 'vitest';
|
|
15
|
-
|
|
16
|
-
import { getFullyQualifiedRepoRootPath } from '@layerzerolabs/common-node-utils';
|
|
17
|
-
|
|
18
|
-
import { Client as SACManagerClient } from '../src/generated/sac_manager.js';
|
|
19
|
-
import { DEFAULT_DEPLOYER, NETWORK_PASSPHRASE, RPC_URL } from './suites/constants.js';
|
|
20
|
-
import { deployAssetSac, deployContract } from './suites/deploy.js';
|
|
21
|
-
import { fundAccount } from './suites/localnet.js';
|
|
22
|
-
import { getTokenAuthorized, getTokenBalance } from './utils.js';
|
|
23
|
-
|
|
24
|
-
// ============================================================================
|
|
25
|
-
// Test Accounts
|
|
26
|
-
// ============================================================================
|
|
27
|
-
|
|
28
|
-
const TOKEN_ISSUER = Keypair.random();
|
|
29
|
-
const USER_A = Keypair.random();
|
|
30
|
-
const USER_B = Keypair.random();
|
|
31
|
-
const USER_C = Keypair.random();
|
|
32
|
-
|
|
33
|
-
// Token configuration
|
|
34
|
-
const TOKEN_CODE = 'RTKN';
|
|
35
|
-
let TOKEN_ASSET: Asset;
|
|
36
|
-
|
|
37
|
-
// Contract addresses
|
|
38
|
-
let sacTokenAddress = '';
|
|
39
|
-
let sacManagerAddress = '';
|
|
40
|
-
|
|
41
|
-
// Clients
|
|
42
|
-
let sacManagerClient: SACManagerClient;
|
|
43
|
-
|
|
44
|
-
// Initial token amounts
|
|
45
|
-
const INITIAL_TOKEN_AMOUNT = '1000'; // 1000 tokens
|
|
46
|
-
const MINT_AMOUNT = 100_0000000n; // 100 tokens (7 decimals)
|
|
47
|
-
|
|
48
|
-
// ============================================================================
|
|
49
|
-
// Helper Functions
|
|
50
|
-
// ============================================================================
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Creates a SACManagerClient with a specific signer
|
|
54
|
-
*/
|
|
55
|
-
function createClientWithSigner(contractId: string, signer: Keypair): SACManagerClient {
|
|
56
|
-
return new SACManagerClient({
|
|
57
|
-
contractId,
|
|
58
|
-
publicKey: signer.publicKey(),
|
|
59
|
-
signTransaction: async (tx: string) => {
|
|
60
|
-
const transaction = TransactionBuilder.fromXDR(tx, NETWORK_PASSPHRASE);
|
|
61
|
-
transaction.sign(signer);
|
|
62
|
-
return {
|
|
63
|
-
signedTxXdr: transaction.toXDR(),
|
|
64
|
-
signerAddress: signer.publicKey(),
|
|
65
|
-
};
|
|
66
|
-
},
|
|
67
|
-
rpcUrl: RPC_URL,
|
|
68
|
-
networkPassphrase: NETWORK_PASSPHRASE,
|
|
69
|
-
allowHttp: true,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Invokes a SAC contract function using raw transaction building
|
|
75
|
-
*/
|
|
76
|
-
async function invokeSacFunction(
|
|
77
|
-
sacAddress: string,
|
|
78
|
-
functionName: string,
|
|
79
|
-
args: any[],
|
|
80
|
-
signer: Keypair,
|
|
81
|
-
): Promise<void> {
|
|
82
|
-
const server = new rpc.Server(RPC_URL, { allowHttp: true });
|
|
83
|
-
const account = await server.getAccount(signer.publicKey());
|
|
84
|
-
|
|
85
|
-
const tx = new TransactionBuilder(account, {
|
|
86
|
-
fee: BASE_FEE,
|
|
87
|
-
networkPassphrase: NETWORK_PASSPHRASE,
|
|
88
|
-
})
|
|
89
|
-
.addOperation(
|
|
90
|
-
Operation.invokeContractFunction({
|
|
91
|
-
contract: sacAddress,
|
|
92
|
-
function: functionName,
|
|
93
|
-
args,
|
|
94
|
-
}),
|
|
95
|
-
)
|
|
96
|
-
.setTimeout(30)
|
|
97
|
-
.build();
|
|
98
|
-
|
|
99
|
-
const simulated = await server.simulateTransaction(tx);
|
|
100
|
-
if (rpc.Api.isSimulationError(simulated)) {
|
|
101
|
-
throw new Error(`Simulation failed: ${JSON.stringify(simulated)}`);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const preparedTx = rpc.assembleTransaction(tx, simulated).build();
|
|
105
|
-
preparedTx.sign(signer);
|
|
106
|
-
|
|
107
|
-
const sendResult = await server.sendTransaction(preparedTx);
|
|
108
|
-
if (sendResult.status !== 'PENDING') {
|
|
109
|
-
throw new Error(`Transaction failed to send: ${JSON.stringify(sendResult)}`);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const txResult = await server.pollTransaction(sendResult.hash);
|
|
113
|
-
if (txResult.status !== 'SUCCESS') {
|
|
114
|
-
throw new Error(`Transaction not successful: ${JSON.stringify(txResult)}`);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// ============================================================================
|
|
119
|
-
// Test Suite
|
|
120
|
-
// ============================================================================
|
|
121
|
-
|
|
122
|
-
describe('SAC Manager E2E Tests', async () => {
|
|
123
|
-
const repoRoot = await getFullyQualifiedRepoRootPath();
|
|
124
|
-
const wasmDir = path.join(
|
|
125
|
-
repoRoot,
|
|
126
|
-
'contracts',
|
|
127
|
-
'protocol',
|
|
128
|
-
'stellar',
|
|
129
|
-
'target',
|
|
130
|
-
'wasm32v1-none',
|
|
131
|
-
'release',
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
const SAC_MANAGER_WASM_PATH = path.join(wasmDir, 'sac_manager.wasm');
|
|
135
|
-
|
|
136
|
-
beforeAll(async () => {
|
|
137
|
-
console.log('\n====================================');
|
|
138
|
-
console.log('SAC Manager E2E Tests');
|
|
139
|
-
console.log('====================================\n');
|
|
140
|
-
|
|
141
|
-
console.log('Funding test accounts...');
|
|
142
|
-
await Promise.all([
|
|
143
|
-
fundAccount(TOKEN_ISSUER.publicKey()),
|
|
144
|
-
fundAccount(USER_A.publicKey()),
|
|
145
|
-
fundAccount(USER_B.publicKey()),
|
|
146
|
-
fundAccount(USER_C.publicKey()),
|
|
147
|
-
]);
|
|
148
|
-
console.log('Test accounts funded');
|
|
149
|
-
|
|
150
|
-
TOKEN_ASSET = new Asset(TOKEN_CODE, TOKEN_ISSUER.publicKey());
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
// ========================================================================
|
|
154
|
-
// Setup SAC Manager with SAC
|
|
155
|
-
// ========================================================================
|
|
156
|
-
|
|
157
|
-
describe('Setup SAC Manager with SAC', () => {
|
|
158
|
-
it('Set AUTH_REVOCABLE and AUTH_CLAWBACK_ENABLED flags on issuer account', async () => {
|
|
159
|
-
const server = new rpc.Server(RPC_URL, { allowHttp: true });
|
|
160
|
-
const issuerAccount = await server.getAccount(TOKEN_ISSUER.publicKey());
|
|
161
|
-
|
|
162
|
-
const authFlags = (AuthRevocableFlag | AuthClawbackEnabledFlag) as AuthFlag;
|
|
163
|
-
const setOptionsTx = new TransactionBuilder(issuerAccount, {
|
|
164
|
-
fee: BASE_FEE,
|
|
165
|
-
networkPassphrase: NETWORK_PASSPHRASE,
|
|
166
|
-
})
|
|
167
|
-
.addOperation(
|
|
168
|
-
Operation.setOptions({
|
|
169
|
-
setFlags: authFlags,
|
|
170
|
-
}),
|
|
171
|
-
)
|
|
172
|
-
.setTimeout(30)
|
|
173
|
-
.build();
|
|
174
|
-
|
|
175
|
-
setOptionsTx.sign(TOKEN_ISSUER);
|
|
176
|
-
|
|
177
|
-
const sendResult = await server.sendTransaction(setOptionsTx);
|
|
178
|
-
if (sendResult.status !== 'PENDING') {
|
|
179
|
-
throw new Error(`Failed to set auth flags: ${JSON.stringify(sendResult)}`);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const txResult = await server.pollTransaction(sendResult.hash);
|
|
183
|
-
if (txResult.status !== 'SUCCESS') {
|
|
184
|
-
throw new Error(`Failed to set auth flags: ${JSON.stringify(txResult)}`);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
console.log('AUTH_REVOCABLE and AUTH_CLAWBACK_ENABLED flags set on issuer');
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it('Deploy SAC with trustlines and issue tokens', async () => {
|
|
191
|
-
const server = new rpc.Server(RPC_URL, { allowHttp: true });
|
|
192
|
-
|
|
193
|
-
const issuerAccount = await server.getAccount(TOKEN_ISSUER.publicKey());
|
|
194
|
-
const issueTx = new TransactionBuilder(issuerAccount, {
|
|
195
|
-
fee: BASE_FEE,
|
|
196
|
-
networkPassphrase: NETWORK_PASSPHRASE,
|
|
197
|
-
})
|
|
198
|
-
.addOperation(
|
|
199
|
-
Operation.changeTrust({
|
|
200
|
-
asset: TOKEN_ASSET,
|
|
201
|
-
source: DEFAULT_DEPLOYER.publicKey(),
|
|
202
|
-
}),
|
|
203
|
-
)
|
|
204
|
-
.addOperation(
|
|
205
|
-
Operation.changeTrust({
|
|
206
|
-
asset: TOKEN_ASSET,
|
|
207
|
-
source: USER_A.publicKey(),
|
|
208
|
-
}),
|
|
209
|
-
)
|
|
210
|
-
.addOperation(
|
|
211
|
-
Operation.changeTrust({
|
|
212
|
-
asset: TOKEN_ASSET,
|
|
213
|
-
source: USER_B.publicKey(),
|
|
214
|
-
}),
|
|
215
|
-
)
|
|
216
|
-
.addOperation(
|
|
217
|
-
Operation.changeTrust({
|
|
218
|
-
asset: TOKEN_ASSET,
|
|
219
|
-
source: USER_C.publicKey(),
|
|
220
|
-
}),
|
|
221
|
-
)
|
|
222
|
-
.addOperation(
|
|
223
|
-
Operation.payment({
|
|
224
|
-
asset: TOKEN_ASSET,
|
|
225
|
-
amount: INITIAL_TOKEN_AMOUNT,
|
|
226
|
-
destination: USER_A.publicKey(),
|
|
227
|
-
}),
|
|
228
|
-
)
|
|
229
|
-
.addOperation(
|
|
230
|
-
Operation.payment({
|
|
231
|
-
asset: TOKEN_ASSET,
|
|
232
|
-
amount: INITIAL_TOKEN_AMOUNT,
|
|
233
|
-
destination: USER_B.publicKey(),
|
|
234
|
-
}),
|
|
235
|
-
)
|
|
236
|
-
.setTimeout(30)
|
|
237
|
-
.build();
|
|
238
|
-
|
|
239
|
-
issueTx.sign(TOKEN_ISSUER, DEFAULT_DEPLOYER, USER_A, USER_B, USER_C);
|
|
240
|
-
|
|
241
|
-
const sendResult = await server.sendTransaction(issueTx);
|
|
242
|
-
if (sendResult.status !== 'PENDING') {
|
|
243
|
-
throw new Error(`Failed to setup trustlines: ${JSON.stringify(sendResult)}`);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const txResult = await server.pollTransaction(sendResult.hash);
|
|
247
|
-
if (txResult.status !== 'SUCCESS') {
|
|
248
|
-
throw new Error(`Failed to setup trustlines: ${JSON.stringify(txResult)}`);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
console.log('Trustlines created and tokens issued');
|
|
252
|
-
|
|
253
|
-
sacTokenAddress = await deployAssetSac(TOKEN_ASSET);
|
|
254
|
-
console.log('SAC deployed at:', sacTokenAddress);
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it('Deploy SAC Manager contract', async () => {
|
|
258
|
-
sacManagerClient = await deployContract<SACManagerClient>(
|
|
259
|
-
SACManagerClient,
|
|
260
|
-
SAC_MANAGER_WASM_PATH,
|
|
261
|
-
{
|
|
262
|
-
sac_token: sacTokenAddress,
|
|
263
|
-
owner: DEFAULT_DEPLOYER.publicKey(),
|
|
264
|
-
},
|
|
265
|
-
DEFAULT_DEPLOYER,
|
|
266
|
-
);
|
|
267
|
-
|
|
268
|
-
sacManagerAddress = sacManagerClient.options.contractId;
|
|
269
|
-
console.log('SAC Manager deployed at:', sacManagerAddress);
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
it('Grant all roles to owner', async () => {
|
|
273
|
-
for (const role of [
|
|
274
|
-
'ADMIN_MANAGER_ROLE',
|
|
275
|
-
'MINTER_ROLE',
|
|
276
|
-
'BLACKLISTER_ROLE',
|
|
277
|
-
'CLAWBACK_ROLE',
|
|
278
|
-
]) {
|
|
279
|
-
const assembledTx = await sacManagerClient.grant_role({
|
|
280
|
-
account: DEFAULT_DEPLOYER.publicKey(),
|
|
281
|
-
role,
|
|
282
|
-
caller: DEFAULT_DEPLOYER.publicKey(),
|
|
283
|
-
});
|
|
284
|
-
await assembledTx.signAndSend();
|
|
285
|
-
}
|
|
286
|
-
console.log('All roles granted to owner');
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
it('Set SAC admin to SAC Manager', async () => {
|
|
290
|
-
await invokeSacFunction(
|
|
291
|
-
sacTokenAddress,
|
|
292
|
-
'set_admin',
|
|
293
|
-
[Address.fromString(sacManagerAddress).toScVal()],
|
|
294
|
-
TOKEN_ISSUER,
|
|
295
|
-
);
|
|
296
|
-
console.log('SAC admin set to SAC Manager');
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
it('Verify owner (DEFAULT_DEPLOYER) starts with zero balance', async () => {
|
|
300
|
-
const ownerBalance = await getTokenBalance(
|
|
301
|
-
DEFAULT_DEPLOYER.publicKey(),
|
|
302
|
-
sacTokenAddress,
|
|
303
|
-
);
|
|
304
|
-
console.log('Owner (DEFAULT_DEPLOYER) balance:', ownerBalance.toString());
|
|
305
|
-
expect(ownerBalance).toBe(0n);
|
|
306
|
-
});
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
// ========================================================================
|
|
310
|
-
// Blacklist Management
|
|
311
|
-
// ========================================================================
|
|
312
|
-
|
|
313
|
-
describe('Blacklist Management', () => {
|
|
314
|
-
it('Verify all accounts start authorized', async () => {
|
|
315
|
-
const [userAAuthorized, userBAuthorized, userCAuthorized] = await Promise.all([
|
|
316
|
-
getTokenAuthorized(USER_A.publicKey(), sacTokenAddress),
|
|
317
|
-
getTokenAuthorized(USER_B.publicKey(), sacTokenAddress),
|
|
318
|
-
getTokenAuthorized(USER_C.publicKey(), sacTokenAddress),
|
|
319
|
-
]);
|
|
320
|
-
|
|
321
|
-
expect(userAAuthorized).toBe(true);
|
|
322
|
-
expect(userBAuthorized).toBe(true);
|
|
323
|
-
expect(userCAuthorized).toBe(true);
|
|
324
|
-
console.log('All users start authorized');
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
it('Blacklist USER_B via set_authorized', async () => {
|
|
328
|
-
// operator: caller must have BLACKLISTER_ROLE (generated client will include operator after regeneration)
|
|
329
|
-
const assembledTx = await (
|
|
330
|
-
sacManagerClient.set_authorized as (args: {
|
|
331
|
-
id: string;
|
|
332
|
-
authorize: boolean;
|
|
333
|
-
operator: string;
|
|
334
|
-
}) => ReturnType<typeof sacManagerClient.set_authorized>
|
|
335
|
-
)({
|
|
336
|
-
id: USER_B.publicKey(),
|
|
337
|
-
authorize: false,
|
|
338
|
-
operator: DEFAULT_DEPLOYER.publicKey(),
|
|
339
|
-
});
|
|
340
|
-
await assembledTx.signAndSend();
|
|
341
|
-
console.log('USER_B blacklisted (authorized=false)');
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
it('Verify USER_B is blacklisted', async () => {
|
|
345
|
-
const authorized = await getTokenAuthorized(USER_B.publicKey(), sacTokenAddress);
|
|
346
|
-
expect(authorized).toBe(false);
|
|
347
|
-
console.log('USER_B authorized:', authorized);
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
it('Non-admin cannot call set_authorized', async () => {
|
|
351
|
-
const userClient = createClientWithSigner(sacManagerAddress, USER_A);
|
|
352
|
-
// operator: USER_A does not have BLACKLISTER_ROLE (generated client will include operator after regeneration)
|
|
353
|
-
const assembledTx = await (
|
|
354
|
-
userClient.set_authorized as (args: {
|
|
355
|
-
id: string;
|
|
356
|
-
authorize: boolean;
|
|
357
|
-
operator: string;
|
|
358
|
-
}) => ReturnType<typeof userClient.set_authorized>
|
|
359
|
-
)({
|
|
360
|
-
id: USER_C.publicKey(),
|
|
361
|
-
authorize: false,
|
|
362
|
-
operator: USER_A.publicKey(),
|
|
363
|
-
});
|
|
364
|
-
await expect(assembledTx.signAndSend()).rejects.toThrow();
|
|
365
|
-
console.log('Non-admin correctly rejected from calling set_authorized');
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
it('Un-blacklist USER_B via set_authorized', async () => {
|
|
369
|
-
// operator: caller must have BLACKLISTER_ROLE (generated client will include operator after regeneration)
|
|
370
|
-
const assembledTx = await (
|
|
371
|
-
sacManagerClient.set_authorized as (args: {
|
|
372
|
-
id: string;
|
|
373
|
-
authorize: boolean;
|
|
374
|
-
operator: string;
|
|
375
|
-
}) => ReturnType<typeof sacManagerClient.set_authorized>
|
|
376
|
-
)({
|
|
377
|
-
id: USER_B.publicKey(),
|
|
378
|
-
authorize: true,
|
|
379
|
-
operator: DEFAULT_DEPLOYER.publicKey(),
|
|
380
|
-
});
|
|
381
|
-
await assembledTx.signAndSend();
|
|
382
|
-
const authorized = await getTokenAuthorized(USER_B.publicKey(), sacTokenAddress);
|
|
383
|
-
expect(authorized).toBe(true);
|
|
384
|
-
console.log('USER_B un-blacklisted');
|
|
385
|
-
});
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
// ========================================================================
|
|
389
|
-
// Mint (operator must have MINTER_ROLE)
|
|
390
|
-
// ========================================================================
|
|
391
|
-
|
|
392
|
-
describe('Mint', () => {
|
|
393
|
-
it('Verify initial balances', async () => {
|
|
394
|
-
const [userABalance, userBBalance, userCBalance, ownerBalance] = await Promise.all([
|
|
395
|
-
getTokenBalance(USER_A.publicKey(), sacTokenAddress),
|
|
396
|
-
getTokenBalance(USER_B.publicKey(), sacTokenAddress),
|
|
397
|
-
getTokenBalance(USER_C.publicKey(), sacTokenAddress),
|
|
398
|
-
getTokenBalance(DEFAULT_DEPLOYER.publicKey(), sacTokenAddress),
|
|
399
|
-
]);
|
|
400
|
-
|
|
401
|
-
console.log('\nInitial Balances:');
|
|
402
|
-
console.log(` USER_A: ${userABalance}`);
|
|
403
|
-
console.log(` USER_B: ${userBBalance}`);
|
|
404
|
-
console.log(` USER_C: ${userCBalance}`);
|
|
405
|
-
console.log(` Owner: ${ownerBalance}`);
|
|
406
|
-
|
|
407
|
-
expect(userABalance).toBe(10000000000n);
|
|
408
|
-
expect(userBBalance).toBe(10000000000n);
|
|
409
|
-
expect(userCBalance).toBe(0n);
|
|
410
|
-
expect(ownerBalance).toBe(0n);
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
it('Minter can mint to non-blacklisted address', async () => {
|
|
414
|
-
const userCBalanceBefore = await getTokenBalance(USER_C.publicKey(), sacTokenAddress);
|
|
415
|
-
|
|
416
|
-
const assembledTx = await sacManagerClient.mint({
|
|
417
|
-
to: USER_C.publicKey(),
|
|
418
|
-
amount: MINT_AMOUNT,
|
|
419
|
-
operator: DEFAULT_DEPLOYER.publicKey(),
|
|
420
|
-
});
|
|
421
|
-
await assembledTx.signAndSend();
|
|
422
|
-
|
|
423
|
-
const userCBalance = await getTokenBalance(USER_C.publicKey(), sacTokenAddress);
|
|
424
|
-
console.log('\nAfter mint to USER_C:', userCBalance);
|
|
425
|
-
expect(userCBalance).toBe(userCBalanceBefore + MINT_AMOUNT);
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
it('Non-minter cannot mint', async () => {
|
|
429
|
-
const userClient = createClientWithSigner(sacManagerAddress, USER_A);
|
|
430
|
-
const assembledTx = await userClient.mint({
|
|
431
|
-
to: USER_C.publicKey(),
|
|
432
|
-
amount: MINT_AMOUNT,
|
|
433
|
-
operator: USER_A.publicKey(),
|
|
434
|
-
});
|
|
435
|
-
await expect(assembledTx.signAndSend()).rejects.toThrow();
|
|
436
|
-
console.log('Non-minter correctly rejected');
|
|
437
|
-
});
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
// ========================================================================
|
|
441
|
-
// Final Summary
|
|
442
|
-
// ========================================================================
|
|
443
|
-
|
|
444
|
-
describe('Final Summary', () => {
|
|
445
|
-
it('Print final balances', async () => {
|
|
446
|
-
const [userABalance, userBBalance, userCBalance, ownerBalance] = await Promise.all([
|
|
447
|
-
getTokenBalance(USER_A.publicKey(), sacTokenAddress),
|
|
448
|
-
getTokenBalance(USER_B.publicKey(), sacTokenAddress),
|
|
449
|
-
getTokenBalance(USER_C.publicKey(), sacTokenAddress),
|
|
450
|
-
getTokenBalance(DEFAULT_DEPLOYER.publicKey(), sacTokenAddress),
|
|
451
|
-
]);
|
|
452
|
-
|
|
453
|
-
console.log('\n========================================');
|
|
454
|
-
console.log('Final Balance Summary');
|
|
455
|
-
console.log('========================================');
|
|
456
|
-
console.log(` USER_A: ${userABalance}`);
|
|
457
|
-
console.log(` USER_B: ${userBBalance}`);
|
|
458
|
-
console.log(` USER_C: ${userCBalance}`);
|
|
459
|
-
console.log(` Owner: ${ownerBalance}`);
|
|
460
|
-
console.log('========================================\n');
|
|
461
|
-
console.log('SAC Manager E2E tests completed successfully!');
|
|
462
|
-
});
|
|
463
|
-
});
|
|
464
|
-
});
|
package/test/secp256k1.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { keccak_256 } from '@noble/hashes/sha3';
|
|
2
|
-
import * as secp from '@noble/secp256k1';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* A secp256k1 key pair with private key and derived Ethereum-style address.
|
|
6
|
-
* Used for DVN multisig signing.
|
|
7
|
-
*/
|
|
8
|
-
export class Secp256k1KeyPair {
|
|
9
|
-
private privateKey: Uint8Array;
|
|
10
|
-
public readonly ethAddress: Buffer;
|
|
11
|
-
|
|
12
|
-
constructor(privateKey: Uint8Array | Buffer | string) {
|
|
13
|
-
if (typeof privateKey === 'string') {
|
|
14
|
-
// Remove 0x prefix if present
|
|
15
|
-
const hex = privateKey.startsWith('0x') ? privateKey.slice(2) : privateKey;
|
|
16
|
-
this.privateKey = Buffer.from(hex, 'hex');
|
|
17
|
-
} else {
|
|
18
|
-
this.privateKey = new Uint8Array(privateKey);
|
|
19
|
-
}
|
|
20
|
-
this.ethAddress = this.deriveEthAddress();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Generate a random key pair.
|
|
25
|
-
*/
|
|
26
|
-
static generate(): Secp256k1KeyPair {
|
|
27
|
-
const privateKey = secp.utils.randomPrivateKey();
|
|
28
|
-
return new Secp256k1KeyPair(privateKey);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Derive Ethereum-style address from the public key.
|
|
33
|
-
* Address = last 20 bytes of keccak256(uncompressed_pubkey[1:65])
|
|
34
|
-
*/
|
|
35
|
-
private deriveEthAddress(): Buffer {
|
|
36
|
-
const publicKey = secp.getPublicKey(this.privateKey, false); // uncompressed
|
|
37
|
-
const pubkeyWithoutPrefix = publicKey.slice(1); // remove 0x04 prefix
|
|
38
|
-
const hash = keccak_256(pubkeyWithoutPrefix);
|
|
39
|
-
return Buffer.from(hash.slice(12)); // last 20 bytes
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Sign a 32-byte digest and return a 65-byte signature (r || s || v).
|
|
44
|
-
*/
|
|
45
|
-
async sign(digest: Uint8Array): Promise<Buffer> {
|
|
46
|
-
const [signature, recoveryId] = await secp.sign(digest, this.privateKey, {
|
|
47
|
-
canonical: true,
|
|
48
|
-
recovered: true,
|
|
49
|
-
der: false,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const v = 27 + recoveryId;
|
|
53
|
-
const result = Buffer.alloc(65);
|
|
54
|
-
result.set(signature, 0); // r (32 bytes) + s (32 bytes)
|
|
55
|
-
result[64] = v;
|
|
56
|
-
|
|
57
|
-
return result;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import type { Option, u32 } from '@stellar/stellar-sdk/contract';
|
|
2
|
-
import {
|
|
3
|
-
AssembledTransaction,
|
|
4
|
-
Client as ContractClient,
|
|
5
|
-
ClientOptions as ContractClientOptions,
|
|
6
|
-
MethodOptions,
|
|
7
|
-
Spec as ContractSpec,
|
|
8
|
-
} from '@stellar/stellar-sdk/contract';
|
|
9
|
-
import { Buffer } from 'buffer';
|
|
10
|
-
export * from '@stellar/stellar-sdk';
|
|
11
|
-
export * as contract from '@stellar/stellar-sdk/contract';
|
|
12
|
-
export * as rpc from '@stellar/stellar-sdk/rpc';
|
|
13
|
-
|
|
14
|
-
const globalWithBuffer = globalThis as typeof globalThis & { Buffer?: typeof Buffer };
|
|
15
|
-
//@ts-ignore Buffer exists
|
|
16
|
-
globalWithBuffer.Buffer ??= Buffer;
|
|
17
|
-
|
|
18
|
-
export const BufferReaderError = {
|
|
19
|
-
1000: { message: 'InvalidLength' },
|
|
20
|
-
1001: { message: 'InvalidAddressPayload' },
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export const BufferWriterError = {
|
|
24
|
-
1100: { message: 'InvalidAddressPayload' },
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const TtlError = {
|
|
28
|
-
1200: { message: 'InvalidTtlConfig' },
|
|
29
|
-
1201: { message: 'TtlConfigFrozen' },
|
|
30
|
-
1202: { message: 'TtlConfigAlreadyFrozen' },
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export const OwnableError = {
|
|
34
|
-
1300: { message: 'OwnerAlreadySet' },
|
|
35
|
-
1301: { message: 'OwnerNotSet' },
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const BytesExtError = {
|
|
39
|
-
1400: { message: 'LengthMismatch' },
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const UpgradeableError = {
|
|
43
|
-
1500: { message: 'MigrationNotAllowed' },
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export type DefaultOwnableStorage = { tag: 'Owner'; values: void };
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* A pair of TTL values: threshold (when to trigger extension) and extend_to (target TTL).
|
|
50
|
-
*/
|
|
51
|
-
export interface TtlConfig {
|
|
52
|
-
/**
|
|
53
|
-
* Target TTL after extension (in ledgers).
|
|
54
|
-
*/
|
|
55
|
-
extend_to: u32;
|
|
56
|
-
/**
|
|
57
|
-
* TTL threshold that triggers extension (in ledgers).
|
|
58
|
-
*/
|
|
59
|
-
threshold: u32;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export type TtlConfigStorage =
|
|
63
|
-
| { tag: 'Frozen'; values: void }
|
|
64
|
-
| { tag: 'Instance'; values: void }
|
|
65
|
-
| { tag: 'Persistent'; values: void };
|
|
66
|
-
|
|
67
|
-
export type UpgradeableStorage = { tag: 'Migrating'; values: void };
|
|
68
|
-
|
|
69
|
-
export interface Client {
|
|
70
|
-
/**
|
|
71
|
-
* Construct and simulate a owner transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
72
|
-
*/
|
|
73
|
-
owner: (options?: MethodOptions) => Promise<AssembledTransaction<Option<string>>>;
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Construct and simulate a transfer_ownership transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
77
|
-
*/
|
|
78
|
-
transfer_ownership: (
|
|
79
|
-
{ new_owner }: { new_owner: string },
|
|
80
|
-
options?: MethodOptions,
|
|
81
|
-
) => Promise<AssembledTransaction<null>>;
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Construct and simulate a renounce_ownership transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
85
|
-
*/
|
|
86
|
-
renounce_ownership: (options?: MethodOptions) => Promise<AssembledTransaction<null>>;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Construct and simulate a upgrade transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
90
|
-
*/
|
|
91
|
-
upgrade: (
|
|
92
|
-
{ new_wasm_hash }: { new_wasm_hash: Buffer },
|
|
93
|
-
options?: MethodOptions,
|
|
94
|
-
) => Promise<AssembledTransaction<null>>;
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Construct and simulate a migrate transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
98
|
-
*/
|
|
99
|
-
migrate: (
|
|
100
|
-
{ migration_data }: { migration_data: MigrationData },
|
|
101
|
-
options?: MethodOptions,
|
|
102
|
-
) => Promise<AssembledTransaction<null>>;
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Construct and simulate a counter transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
106
|
-
*/
|
|
107
|
-
counter: (options?: MethodOptions) => Promise<AssembledTransaction<u32>>;
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Construct and simulate a counter2 transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
111
|
-
*/
|
|
112
|
-
counter2: (options?: MethodOptions) => Promise<AssembledTransaction<u32>>;
|
|
113
|
-
}
|
|
114
|
-
export class Client extends ContractClient {
|
|
115
|
-
static async deploy<T = Client>(
|
|
116
|
-
/** Options for initializing a Client as well as for calling a method, with extras specific to deploying. */
|
|
117
|
-
options: MethodOptions &
|
|
118
|
-
Omit<ContractClientOptions, 'contractId'> & {
|
|
119
|
-
/** The hash of the Wasm blob, which must already be installed on-chain. */
|
|
120
|
-
wasmHash: Buffer | string;
|
|
121
|
-
/** Salt used to generate the contract's ID. Passed through to {@link Operation.createCustomContract}. Default: random. */
|
|
122
|
-
salt?: Buffer | Uint8Array;
|
|
123
|
-
/** The format used to decode `wasmHash`, if it's provided as a string. */
|
|
124
|
-
format?: 'hex' | 'base64';
|
|
125
|
-
},
|
|
126
|
-
): Promise<AssembledTransaction<T>> {
|
|
127
|
-
return ContractClient.deploy(null, options);
|
|
128
|
-
}
|
|
129
|
-
constructor(public readonly options: ContractClientOptions) {
|
|
130
|
-
super(
|
|
131
|
-
new ContractSpec([
|
|
132
|
-
'AAAAAAAAAAAAAAAFb3duZXIAAAAAAAAAAAAAAQAAA+gAAAAT',
|
|
133
|
-
'AAAAAAAAAAAAAAASdHJhbnNmZXJfb3duZXJzaGlwAAAAAAABAAAAAAAAAAluZXdfb3duZXIAAAAAAAATAAAAAA==',
|
|
134
|
-
'AAAAAAAAAAAAAAAScmVub3VuY2Vfb3duZXJzaGlwAAAAAAAAAAAAAA==',
|
|
135
|
-
'AAAAAAAAAAAAAAAHdXBncmFkZQAAAAABAAAAAAAAAA1uZXdfd2FzbV9oYXNoAAAAAAAD7gAAACAAAAAA',
|
|
136
|
-
'AAAAAAAAAAAAAAAHbWlncmF0ZQAAAAABAAAAAAAAAA5taWdyYXRpb25fZGF0YQAAAAAH0AAAAA1NaWdyYXRpb25EYXRhAAAAAAAAAA==',
|
|
137
|
-
'AAAAAAAAAAAAAAAHY291bnRlcgAAAAAAAAAAAQAAAAQ=',
|
|
138
|
-
'AAAAAAAAAAAAAAAIY291bnRlcjIAAAAAAAAAAQAAAAQ=',
|
|
139
|
-
'AAAABAAAAAAAAAAAAAAAEUJ1ZmZlclJlYWRlckVycm9yAAAAAAAAAgAAAAAAAAANSW52YWxpZExlbmd0aAAAAAAAA+gAAAAAAAAAFUludmFsaWRBZGRyZXNzUGF5bG9hZAAAAAAAA+k=',
|
|
140
|
-
'AAAABAAAAAAAAAAAAAAAEUJ1ZmZlcldyaXRlckVycm9yAAAAAAAAAQAAAAAAAAAVSW52YWxpZEFkZHJlc3NQYXlsb2FkAAAAAAAETA==',
|
|
141
|
-
'AAAABAAAAAAAAAAAAAAACFR0bEVycm9yAAAAAwAAAAAAAAAQSW52YWxpZFR0bENvbmZpZwAABLAAAAAAAAAAD1R0bENvbmZpZ0Zyb3plbgAAAASxAAAAAAAAABZUdGxDb25maWdBbHJlYWR5RnJvemVuAAAAAASy',
|
|
142
|
-
'AAAABAAAAAAAAAAAAAAADE93bmFibGVFcnJvcgAAAAIAAAAAAAAAD093bmVyQWxyZWFkeVNldAAAAAUUAAAAAAAAAAtPd25lck5vdFNldAAAAAUV',
|
|
143
|
-
'AAAABAAAAAAAAAAAAAAADUJ5dGVzRXh0RXJyb3IAAAAAAAABAAAAAAAAAA5MZW5ndGhNaXNtYXRjaAAAAAAFeA==',
|
|
144
|
-
'AAAABAAAAAAAAAAAAAAAEFVwZ3JhZGVhYmxlRXJyb3IAAAABAAAAAAAAABNNaWdyYXRpb25Ob3RBbGxvd2VkAAAABdw=',
|
|
145
|
-
'AAAABQAAACxFdmVudCBlbWl0dGVkIHdoZW4gb3duZXJzaGlwIGlzIHRyYW5zZmVycmVkLgAAAAAAAAAUT3duZXJzaGlwVHJhbnNmZXJyZWQAAAABAAAAFE93bmVyc2hpcFRyYW5zZmVycmVkAAAAAgAAAAAAAAAJb2xkX293bmVyAAAAAAAAEwAAAAAAAAAAAAAACW5ld19vd25lcgAAAAAAABMAAAAAAAAAAg==',
|
|
146
|
-
'AAAABQAAACpFdmVudCBlbWl0dGVkIHdoZW4gb3duZXJzaGlwIGlzIHJlbm91bmNlZC4AAAAAAAAAAAAST3duZXJzaGlwUmVub3VuY2VkAAAAAAABAAAAEk93bmVyc2hpcFJlbm91bmNlZAAAAAAAAQAAAAAAAAAJb2xkX293bmVyAAAAAAAAEwAAAAAAAAAC',
|
|
147
|
-
'AAAAAgAAAAAAAAAAAAAAFURlZmF1bHRPd25hYmxlU3RvcmFnZQAAAAAAAAEAAAAAAAAAAAAAAAVPd25lcgAAAA==',
|
|
148
|
-
'AAAAAQAAAFdBIHBhaXIgb2YgVFRMIHZhbHVlczogdGhyZXNob2xkICh3aGVuIHRvIHRyaWdnZXIgZXh0ZW5zaW9uKSBhbmQgZXh0ZW5kX3RvICh0YXJnZXQgVFRMKS4AAAAAAAAAAAlUdGxDb25maWcAAAAAAAACAAAAKFRhcmdldCBUVEwgYWZ0ZXIgZXh0ZW5zaW9uIChpbiBsZWRnZXJzKS4AAAAJZXh0ZW5kX3RvAAAAAAAABAAAADNUVEwgdGhyZXNob2xkIHRoYXQgdHJpZ2dlcnMgZXh0ZW5zaW9uIChpbiBsZWRnZXJzKS4AAAAACXRocmVzaG9sZAAAAAAAAAQ=',
|
|
149
|
-
'AAAAAgAAAAAAAAAAAAAAEFR0bENvbmZpZ1N0b3JhZ2UAAAADAAAAAAAAAAAAAAAGRnJvemVuAAAAAAAAAAAAAAAAAAhJbnN0YW5jZQAAAAAAAAAAAAAAClBlcnNpc3RlbnQAAA==',
|
|
150
|
-
'AAAABQAAACdFdmVudCBlbWl0dGVkIHdoZW4gVFRMIGNvbmZpZ3MgYXJlIHNldC4AAAAAAAAAAA1UdGxDb25maWdzU2V0AAAAAAAAAQAAAA1UdGxDb25maWdzU2V0AAAAAAAAAgAAAAAAAAAIaW5zdGFuY2UAAAPoAAAH0AAAAAlUdGxDb25maWcAAAAAAAAAAAAAAAAAAApwZXJzaXN0ZW50AAAAAAPoAAAH0AAAAAlUdGxDb25maWcAAAAAAAAAAAAAAg==',
|
|
151
|
-
'AAAABQAAACpFdmVudCBlbWl0dGVkIHdoZW4gVFRMIGNvbmZpZ3MgYXJlIGZyb3plbi4AAAAAAAAAAAAQVHRsQ29uZmlnc0Zyb3plbgAAAAEAAAAQVHRsQ29uZmlnc0Zyb3plbgAAAAAAAAAC',
|
|
152
|
-
'AAAAAgAAAAAAAAAAAAAAElVwZ3JhZGVhYmxlU3RvcmFnZQAAAAAAAQAAAAAAAAAAAAAACU1pZ3JhdGluZwAAAA==',
|
|
153
|
-
]),
|
|
154
|
-
options,
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
public readonly fromJSON = {
|
|
158
|
-
owner: this.txFromJSON<Option<string>>,
|
|
159
|
-
transfer_ownership: this.txFromJSON<null>,
|
|
160
|
-
renounce_ownership: this.txFromJSON<null>,
|
|
161
|
-
upgrade: this.txFromJSON<null>,
|
|
162
|
-
migrate: this.txFromJSON<null>,
|
|
163
|
-
counter: this.txFromJSON<u32>,
|
|
164
|
-
counter2: this.txFromJSON<u32>,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export type MigrationData = void;
|