@openzeppelin/wizard-stellar 0.4.4 → 0.5.0
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/dist/add-pausable.d.ts +1 -1
- package/dist/add-pausable.d.ts.map +1 -1
- package/dist/add-pausable.js +8 -8
- package/dist/add-pausable.js.map +1 -1
- package/dist/add-upgradeable.d.ts +1 -1
- package/dist/add-upgradeable.d.ts.map +1 -1
- package/dist/add-upgradeable.js +2 -2
- package/dist/add-upgradeable.js.map +1 -1
- package/dist/common-options.d.ts +1 -0
- package/dist/common-options.d.ts.map +1 -1
- package/dist/common-options.js +2 -0
- package/dist/common-options.js.map +1 -1
- package/dist/contract.d.ts +2 -0
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +7 -0
- package/dist/contract.js.map +1 -1
- package/dist/fungible.d.ts.map +1 -1
- package/dist/fungible.js +38 -23
- package/dist/fungible.js.map +1 -1
- package/dist/generate/fungible.d.ts.map +1 -1
- package/dist/generate/fungible.js +1 -0
- package/dist/generate/fungible.js.map +1 -1
- package/dist/generate/non-fungible.d.ts.map +1 -1
- package/dist/generate/non-fungible.js +1 -0
- package/dist/generate/non-fungible.js.map +1 -1
- package/dist/generate/stablecoin.d.ts.map +1 -1
- package/dist/generate/stablecoin.js +1 -0
- package/dist/generate/stablecoin.js.map +1 -1
- package/dist/non-fungible.d.ts +1 -1
- package/dist/non-fungible.d.ts.map +1 -1
- package/dist/non-fungible.js +80 -41
- package/dist/non-fungible.js.map +1 -1
- package/dist/set-access-control.d.ts +2 -2
- package/dist/set-access-control.d.ts.map +1 -1
- package/dist/set-access-control.js +113 -10
- package/dist/set-access-control.js.map +1 -1
- package/dist/stablecoin.d.ts +2 -1
- package/dist/stablecoin.d.ts.map +1 -1
- package/dist/stablecoin.js +27 -6
- package/dist/stablecoin.js.map +1 -1
- package/dist/utils/compile-test.d.ts +1 -0
- package/dist/utils/compile-test.d.ts.map +1 -1
- package/dist/utils/compile-test.js +19 -5
- package/dist/utils/compile-test.js.map +1 -1
- package/dist/utils/version.d.ts +4 -4
- package/dist/utils/version.js +3 -3
- package/dist/zip-rust.d.ts.map +1 -1
- package/dist/zip-rust.js +4 -0
- package/dist/zip-rust.js.map +1 -1
- package/package.json +3 -3
- package/src/add-pausable.ts +29 -15
- package/src/add-upgradeable.ts +13 -6
- package/src/common-options.ts +3 -0
- package/src/contract.ts +9 -0
- package/src/fungible.ts +57 -29
- package/src/generate/fungible.ts +1 -0
- package/src/generate/non-fungible.ts +1 -0
- package/src/generate/stablecoin.ts +1 -0
- package/src/non-fungible.ts +121 -45
- package/src/set-access-control.ts +113 -9
- package/src/stablecoin.ts +39 -9
- package/src/utils/compile-test.ts +52 -25
- package/src/utils/version.ts +3 -3
- package/src/zip-rust.ts +5 -0
package/src/non-fungible.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { ContractBuilder } from './contract';
|
|
3
|
-
import { type Access, requireAccessControl, setAccessControl } from './set-access-control';
|
|
1
|
+
import { pickKeys } from '@openzeppelin/wizard-common';
|
|
4
2
|
import { addPausable } from './add-pausable';
|
|
5
3
|
import { addUpgradeable } from './add-upgradeable';
|
|
6
|
-
import { defineFunctions } from './utils/define-functions';
|
|
7
4
|
import type { CommonContractOptions } from './common-options';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
5
|
+
import { contractDefaults as commonDefaults, getSelfArg, withCommonContractDefaults } from './common-options';
|
|
6
|
+
import type { Contract } from './contract';
|
|
7
|
+
import { ContractBuilder } from './contract';
|
|
10
8
|
import type { OptionsErrorMessages } from './error';
|
|
11
9
|
import { OptionsError } from './error';
|
|
12
|
-
import { contractDefaults as commonDefaults } from './common-options';
|
|
13
10
|
import { printContract } from './print';
|
|
11
|
+
import { type Access, DEFAULT_ACCESS_CONTROL, requireAccessControl, setAccessControl } from './set-access-control';
|
|
12
|
+
import { setInfo } from './set-info';
|
|
14
13
|
import { toByteArray } from './utils/convert-strings';
|
|
14
|
+
import { defineFunctions } from './utils/define-functions';
|
|
15
15
|
|
|
16
16
|
export const defaults: Required<NonFungibleOptions> = {
|
|
17
17
|
name: 'MyToken',
|
|
@@ -26,6 +26,7 @@ export const defaults: Required<NonFungibleOptions> = {
|
|
|
26
26
|
sequential: false,
|
|
27
27
|
access: commonDefaults.access, // TODO: Determine whether Access Control options should be visible in the UI before they are implemented as modules
|
|
28
28
|
info: commonDefaults.info,
|
|
29
|
+
explicitImplementations: commonDefaults.explicitImplementations,
|
|
29
30
|
} as const;
|
|
30
31
|
|
|
31
32
|
export function printNonFungible(opts: NonFungibleOptions = defaults): string {
|
|
@@ -90,39 +91,60 @@ export function buildNonFungible(opts: NonFungibleOptions): Contract {
|
|
|
90
91
|
throw new OptionsError(errors);
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
addBase(
|
|
94
|
+
addBase(
|
|
95
|
+
c,
|
|
96
|
+
toByteArray(allOpts.name),
|
|
97
|
+
toByteArray(allOpts.symbol),
|
|
98
|
+
toByteArray(allOpts.tokenUri),
|
|
99
|
+
allOpts.pausable,
|
|
100
|
+
allOpts.explicitImplementations,
|
|
101
|
+
);
|
|
94
102
|
|
|
95
103
|
if (allOpts.pausable) {
|
|
96
|
-
addPausable(c, allOpts.access);
|
|
104
|
+
addPausable(c, allOpts.access, allOpts.explicitImplementations);
|
|
97
105
|
}
|
|
98
106
|
|
|
99
107
|
if (allOpts.upgradeable) {
|
|
100
|
-
addUpgradeable(c, allOpts.access);
|
|
108
|
+
addUpgradeable(c, allOpts.access, allOpts.explicitImplementations);
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
if (allOpts.burnable) {
|
|
104
|
-
addBurnable(c, allOpts.pausable);
|
|
112
|
+
addBurnable(c, allOpts.pausable, allOpts.explicitImplementations);
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
if (allOpts.enumerable) {
|
|
108
|
-
addEnumerable(c);
|
|
116
|
+
addEnumerable(c, allOpts.explicitImplementations);
|
|
109
117
|
}
|
|
110
118
|
|
|
111
119
|
if (allOpts.consecutive) {
|
|
112
|
-
addConsecutive(c, allOpts.pausable, allOpts.access);
|
|
120
|
+
addConsecutive(c, allOpts.pausable, allOpts.access, allOpts.explicitImplementations);
|
|
113
121
|
}
|
|
114
122
|
|
|
115
123
|
if (allOpts.mintable) {
|
|
116
|
-
addMintable(
|
|
124
|
+
addMintable(
|
|
125
|
+
c,
|
|
126
|
+
allOpts.enumerable,
|
|
127
|
+
allOpts.pausable,
|
|
128
|
+
allOpts.sequential,
|
|
129
|
+
allOpts.access,
|
|
130
|
+
allOpts.explicitImplementations,
|
|
131
|
+
);
|
|
117
132
|
}
|
|
118
133
|
|
|
119
|
-
setAccessControl(c, allOpts.access);
|
|
134
|
+
setAccessControl(c, allOpts.access, allOpts.explicitImplementations);
|
|
120
135
|
setInfo(c, allOpts.info);
|
|
121
136
|
|
|
122
137
|
return c;
|
|
123
138
|
}
|
|
124
139
|
|
|
125
|
-
function addBase(
|
|
140
|
+
function addBase(
|
|
141
|
+
c: ContractBuilder,
|
|
142
|
+
name: string,
|
|
143
|
+
symbol: string,
|
|
144
|
+
tokenUri: string,
|
|
145
|
+
pausable: boolean,
|
|
146
|
+
explicitImplementations: boolean,
|
|
147
|
+
) {
|
|
126
148
|
// Set metadata
|
|
127
149
|
c.addConstructorCode(`let uri = String::from_str(e, "${tokenUri}");`);
|
|
128
150
|
c.addConstructorCode(`let name = String::from_str(e, "${name}");`);
|
|
@@ -132,21 +154,24 @@ function addBase(c: ContractBuilder, name: string, symbol: string, tokenUri: str
|
|
|
132
154
|
// Set token functions
|
|
133
155
|
c.addUseClause('stellar_tokens::non_fungible', 'Base');
|
|
134
156
|
c.addUseClause('stellar_tokens::non_fungible', 'NonFungibleToken');
|
|
135
|
-
c.addUseClause('
|
|
157
|
+
if (explicitImplementations) c.addUseClause('stellar_tokens::non_fungible', 'ContractOverrides');
|
|
136
158
|
c.addUseClause('soroban_sdk', 'contract');
|
|
137
159
|
c.addUseClause('soroban_sdk', 'contractimpl');
|
|
138
160
|
c.addUseClause('soroban_sdk', 'String');
|
|
139
161
|
c.addUseClause('soroban_sdk', 'Env');
|
|
162
|
+
c.addUseClause('soroban_sdk', 'Address');
|
|
140
163
|
|
|
141
164
|
const nonFungibleTokenTrait = {
|
|
142
165
|
traitName: 'NonFungibleToken',
|
|
143
166
|
structName: c.name,
|
|
144
|
-
tags: ['
|
|
167
|
+
tags: explicitImplementations ? ['contractimpl'] : ['contractimpl(contracttrait)'],
|
|
145
168
|
assocType: 'type ContractType = Base;',
|
|
146
169
|
};
|
|
147
170
|
|
|
148
171
|
c.addTraitImplBlock(nonFungibleTokenTrait);
|
|
149
172
|
|
|
173
|
+
if (explicitImplementations) c.addTraitForEachFunctions(nonFungibleTokenTrait, nonFungibleTokenTraitFunctions);
|
|
174
|
+
|
|
150
175
|
if (pausable) {
|
|
151
176
|
c.addUseClause('stellar_macros', 'when_not_paused');
|
|
152
177
|
|
|
@@ -158,13 +183,13 @@ function addBase(c: ContractBuilder, name: string, symbol: string, tokenUri: str
|
|
|
158
183
|
}
|
|
159
184
|
}
|
|
160
185
|
|
|
161
|
-
function addBurnable(c: ContractBuilder, pausable: boolean) {
|
|
186
|
+
function addBurnable(c: ContractBuilder, pausable: boolean, explicitImplementations: boolean) {
|
|
162
187
|
c.addUseClause('stellar_tokens::non_fungible', 'burnable::NonFungibleBurnable');
|
|
163
188
|
|
|
164
189
|
const nonFungibleBurnableTrait = {
|
|
165
190
|
traitName: 'NonFungibleBurnable',
|
|
166
191
|
structName: c.name,
|
|
167
|
-
tags: ['contractimpl'],
|
|
192
|
+
tags: explicitImplementations ? ['contractimpl'] : ['contractimpl(contracttrait)'],
|
|
168
193
|
section: 'Extensions',
|
|
169
194
|
};
|
|
170
195
|
|
|
@@ -176,32 +201,33 @@ function addBurnable(c: ContractBuilder, pausable: boolean) {
|
|
|
176
201
|
|
|
177
202
|
c.addTraitFunction(nonFungibleBurnableTrait, burnableFunctions.burn_from);
|
|
178
203
|
c.addFunctionTag(burnableFunctions.burn_from, 'when_not_paused', nonFungibleBurnableTrait);
|
|
179
|
-
} else
|
|
180
|
-
|
|
181
|
-
|
|
204
|
+
} else if (explicitImplementations)
|
|
205
|
+
c.addTraitForEachFunctions(nonFungibleBurnableTrait, nonFungibleBurnableFunctions);
|
|
206
|
+
else {
|
|
182
207
|
c.addTraitImplBlock(nonFungibleBurnableTrait);
|
|
183
208
|
}
|
|
184
209
|
}
|
|
185
210
|
|
|
186
|
-
function addEnumerable(c: ContractBuilder) {
|
|
211
|
+
function addEnumerable(c: ContractBuilder, explicitImplementations: boolean) {
|
|
187
212
|
c.addUseClause('stellar_tokens::non_fungible', 'enumerable::{NonFungibleEnumerable, Enumerable}');
|
|
188
|
-
c.addUseClause('stellar_macros', 'default_impl');
|
|
189
213
|
|
|
190
214
|
const nonFungibleEnumerableTrait = {
|
|
191
215
|
traitName: 'NonFungibleEnumerable',
|
|
192
216
|
structName: c.name,
|
|
193
|
-
tags: ['
|
|
217
|
+
tags: explicitImplementations ? ['contractimpl'] : ['contractimpl(contracttrait)'],
|
|
194
218
|
section: 'Extensions',
|
|
195
219
|
};
|
|
196
|
-
|
|
220
|
+
if (explicitImplementations)
|
|
221
|
+
c.addTraitForEachFunctions(nonFungibleEnumerableTrait, nonFungibleEnumerableTraitFunctions);
|
|
222
|
+
else c.addTraitImplBlock(nonFungibleEnumerableTrait);
|
|
197
223
|
|
|
198
224
|
c.overrideAssocType('NonFungibleToken', 'type ContractType = Enumerable;');
|
|
199
225
|
}
|
|
200
226
|
|
|
201
|
-
function addConsecutive(c: ContractBuilder, pausable: boolean, access: Access) {
|
|
227
|
+
function addConsecutive(c: ContractBuilder, pausable: boolean, access: Access, explicitImplementations: boolean) {
|
|
202
228
|
c.addUseClause('stellar_tokens::non_fungible', 'consecutive::{NonFungibleConsecutive, Consecutive}');
|
|
203
|
-
c.addUseClause('soroban_sdk', 'Address');
|
|
204
229
|
|
|
230
|
+
const effectiveAccess = access === false ? DEFAULT_ACCESS_CONTROL : access;
|
|
205
231
|
const nonFungibleConsecutiveTrait = {
|
|
206
232
|
traitName: 'NonFungibleConsecutive',
|
|
207
233
|
structName: c.name,
|
|
@@ -213,45 +239,63 @@ function addConsecutive(c: ContractBuilder, pausable: boolean, access: Access) {
|
|
|
213
239
|
|
|
214
240
|
c.overrideAssocType('NonFungibleToken', 'type ContractType = Consecutive;');
|
|
215
241
|
|
|
216
|
-
const mintFn =
|
|
242
|
+
const mintFn =
|
|
243
|
+
effectiveAccess === 'ownable' ? consecutiveFunctions.batch_mint : consecutiveFunctions.batch_mint_with_caller;
|
|
217
244
|
c.addFreeFunction(mintFn);
|
|
218
245
|
if (pausable) {
|
|
219
246
|
c.addFunctionTag(mintFn, 'when_not_paused');
|
|
220
247
|
}
|
|
221
248
|
|
|
222
|
-
requireAccessControl(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
249
|
+
requireAccessControl(
|
|
250
|
+
c,
|
|
251
|
+
undefined,
|
|
252
|
+
mintFn,
|
|
253
|
+
effectiveAccess,
|
|
254
|
+
{
|
|
255
|
+
useMacro: true,
|
|
256
|
+
role: 'minter',
|
|
257
|
+
caller: 'caller',
|
|
258
|
+
},
|
|
259
|
+
explicitImplementations,
|
|
260
|
+
);
|
|
227
261
|
}
|
|
228
262
|
|
|
229
|
-
function addMintable(
|
|
230
|
-
c
|
|
263
|
+
function addMintable(
|
|
264
|
+
c: ContractBuilder,
|
|
265
|
+
enumerable: boolean,
|
|
266
|
+
pausable: boolean,
|
|
267
|
+
sequential: boolean,
|
|
268
|
+
access: Access,
|
|
269
|
+
explicitImplementations: boolean,
|
|
270
|
+
) {
|
|
231
271
|
const accessProps = { useMacro: true, role: 'minter', caller: 'caller' };
|
|
272
|
+
const effectiveAccess = access === false ? DEFAULT_ACCESS_CONTROL : access;
|
|
232
273
|
|
|
233
274
|
let mintFn;
|
|
234
275
|
|
|
235
276
|
if (enumerable) {
|
|
236
277
|
if (sequential) {
|
|
237
278
|
mintFn =
|
|
238
|
-
|
|
279
|
+
effectiveAccess === 'ownable'
|
|
280
|
+
? enumerableFunctions.sequential_mint
|
|
281
|
+
: enumerableFunctions.sequential_mint_with_caller;
|
|
239
282
|
} else {
|
|
240
283
|
mintFn =
|
|
241
|
-
|
|
284
|
+
effectiveAccess === 'ownable'
|
|
242
285
|
? enumerableFunctions.non_sequential_mint
|
|
243
286
|
: enumerableFunctions.non_sequential_mint_with_caller;
|
|
244
287
|
}
|
|
245
288
|
} else {
|
|
246
289
|
if (sequential) {
|
|
247
|
-
mintFn =
|
|
290
|
+
mintFn =
|
|
291
|
+
effectiveAccess === 'ownable' ? baseFunctions.sequential_mint : baseFunctions.sequential_mint_with_caller;
|
|
248
292
|
} else {
|
|
249
|
-
mintFn =
|
|
293
|
+
mintFn = effectiveAccess === 'ownable' ? baseFunctions.mint : baseFunctions.mint_with_caller;
|
|
250
294
|
}
|
|
251
295
|
}
|
|
252
296
|
|
|
253
297
|
c.addFreeFunction(mintFn);
|
|
254
|
-
requireAccessControl(c, undefined, mintFn,
|
|
298
|
+
requireAccessControl(c, undefined, mintFn, effectiveAccess, accessProps, explicitImplementations);
|
|
255
299
|
|
|
256
300
|
if (pausable) {
|
|
257
301
|
c.addFunctionTag(mintFn, 'when_not_paused');
|
|
@@ -361,6 +405,20 @@ const baseFunctions = defineFunctions({
|
|
|
361
405
|
},
|
|
362
406
|
});
|
|
363
407
|
|
|
408
|
+
const nonFungibleTokenTraitFunctions = pickKeys(baseFunctions, [
|
|
409
|
+
'balance',
|
|
410
|
+
'owner_of',
|
|
411
|
+
'transfer',
|
|
412
|
+
'transfer_from',
|
|
413
|
+
'approve',
|
|
414
|
+
'approve_for_all',
|
|
415
|
+
'get_approved',
|
|
416
|
+
'is_approved_for_all',
|
|
417
|
+
'name',
|
|
418
|
+
'symbol',
|
|
419
|
+
'token_uri',
|
|
420
|
+
]);
|
|
421
|
+
|
|
364
422
|
const burnableFunctions = defineFunctions({
|
|
365
423
|
burn: {
|
|
366
424
|
args: [getSelfArg(), { name: 'from', type: 'Address' }, { name: 'token_id', type: 'u32' }],
|
|
@@ -377,11 +435,23 @@ const burnableFunctions = defineFunctions({
|
|
|
377
435
|
},
|
|
378
436
|
});
|
|
379
437
|
|
|
438
|
+
const nonFungibleBurnableFunctions = pickKeys(burnableFunctions, ['burn', 'burn_from']);
|
|
439
|
+
|
|
380
440
|
const enumerableFunctions = defineFunctions({
|
|
381
441
|
total_supply: {
|
|
382
442
|
args: [getSelfArg()],
|
|
383
443
|
returns: 'u32',
|
|
384
|
-
code: ['
|
|
444
|
+
code: ['Enumerable::total_supply(e)'],
|
|
445
|
+
},
|
|
446
|
+
get_owner_token_id: {
|
|
447
|
+
args: [getSelfArg(), { name: 'owner', type: 'Address' }, { name: 'index', type: 'u32' }],
|
|
448
|
+
returns: 'u32',
|
|
449
|
+
code: ['Enumerable::get_owner_token_id(e, &owner, index)'],
|
|
450
|
+
},
|
|
451
|
+
get_token_id: {
|
|
452
|
+
args: [getSelfArg(), { name: 'index', type: 'u32' }],
|
|
453
|
+
returns: 'u32',
|
|
454
|
+
code: ['Enumerable::get_token_id(e, index)'],
|
|
385
455
|
},
|
|
386
456
|
non_sequential_mint: {
|
|
387
457
|
name: 'mint',
|
|
@@ -410,12 +480,18 @@ const enumerableFunctions = defineFunctions({
|
|
|
410
480
|
},
|
|
411
481
|
});
|
|
412
482
|
|
|
483
|
+
const nonFungibleEnumerableTraitFunctions = pickKeys(enumerableFunctions, [
|
|
484
|
+
'total_supply',
|
|
485
|
+
'get_owner_token_id',
|
|
486
|
+
'get_token_id',
|
|
487
|
+
]);
|
|
488
|
+
|
|
413
489
|
const consecutiveFunctions = defineFunctions({
|
|
414
490
|
batch_mint: {
|
|
415
491
|
name: 'batch_mint',
|
|
416
492
|
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'amount', type: 'u32' }],
|
|
417
493
|
returns: 'u32',
|
|
418
|
-
code: ['Consecutive::batch_mint(e, &to, amount)
|
|
494
|
+
code: ['Consecutive::batch_mint(e, &to, amount)'],
|
|
419
495
|
},
|
|
420
496
|
batch_mint_with_caller: {
|
|
421
497
|
name: 'batch_mint',
|
|
@@ -426,6 +502,6 @@ const consecutiveFunctions = defineFunctions({
|
|
|
426
502
|
{ name: 'caller', type: 'Address' },
|
|
427
503
|
],
|
|
428
504
|
returns: 'u32',
|
|
429
|
-
code: ['Consecutive::batch_mint(e, &to, amount)
|
|
505
|
+
code: ['Consecutive::batch_mint(e, &to, amount)'],
|
|
430
506
|
},
|
|
431
507
|
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { getSelfArg } from './common-options';
|
|
1
2
|
import type { BaseFunction, BaseTraitImplBlock, ContractBuilder } from './contract';
|
|
3
|
+
import { defineFunctions } from './utils/define-functions';
|
|
2
4
|
|
|
3
5
|
export const accessOptions = [false, 'ownable', 'roles'] as const;
|
|
4
6
|
export const DEFAULT_ACCESS_CONTROL = 'ownable';
|
|
@@ -13,7 +15,7 @@ export type AccessProps = {
|
|
|
13
15
|
/**
|
|
14
16
|
* Sets access control for the contract via constructor args.
|
|
15
17
|
*/
|
|
16
|
-
export function setAccessControl(c: ContractBuilder, access: Access): void {
|
|
18
|
+
export function setAccessControl(c: ContractBuilder, access: Access, explicitImplementations = false): void {
|
|
17
19
|
switch (access) {
|
|
18
20
|
case false:
|
|
19
21
|
break;
|
|
@@ -27,10 +29,14 @@ export function setAccessControl(c: ContractBuilder, access: Access): void {
|
|
|
27
29
|
const ownableTrait = {
|
|
28
30
|
traitName: 'Ownable',
|
|
29
31
|
structName: c.name,
|
|
30
|
-
tags: ['
|
|
32
|
+
tags: explicitImplementations ? ['contractimpl'] : ['contractimpl(contracttrait)'],
|
|
31
33
|
section: 'Utils',
|
|
32
34
|
};
|
|
33
|
-
|
|
35
|
+
if (explicitImplementations) {
|
|
36
|
+
c.addTraitForEachFunctions(ownableTrait, ownableFunctions);
|
|
37
|
+
} else {
|
|
38
|
+
c.addTraitImplBlock(ownableTrait);
|
|
39
|
+
}
|
|
34
40
|
|
|
35
41
|
c.addConstructorArgument({ name: 'owner', type: 'Address' });
|
|
36
42
|
c.addConstructorCode('ownable::set_owner(e, &owner);');
|
|
@@ -42,13 +48,18 @@ export function setAccessControl(c: ContractBuilder, access: Access): void {
|
|
|
42
48
|
c.addUseClause('stellar_access::access_control', 'self', { alias: 'access_control' });
|
|
43
49
|
c.addUseClause('stellar_access::access_control', 'AccessControl');
|
|
44
50
|
|
|
45
|
-
const
|
|
51
|
+
const accessControlTrait = {
|
|
46
52
|
traitName: 'AccessControl',
|
|
47
53
|
structName: c.name,
|
|
48
|
-
tags: ['
|
|
54
|
+
tags: explicitImplementations ? ['contractimpl'] : ['contractimpl(contracttrait)'],
|
|
49
55
|
section: 'Utils',
|
|
50
56
|
};
|
|
51
|
-
|
|
57
|
+
if (explicitImplementations) {
|
|
58
|
+
c.addUseClause('soroban_sdk', 'Symbol');
|
|
59
|
+
c.addTraitForEachFunctions(accessControlTrait, accessControlFunctions);
|
|
60
|
+
} else {
|
|
61
|
+
c.addTraitImplBlock(accessControlTrait);
|
|
62
|
+
}
|
|
52
63
|
|
|
53
64
|
c.addConstructorArgument({ name: 'admin', type: 'Address' });
|
|
54
65
|
c.addConstructorCode('access_control::set_admin(e, &admin);');
|
|
@@ -70,11 +81,12 @@ export function requireAccessControl(
|
|
|
70
81
|
fn: BaseFunction,
|
|
71
82
|
access: Access,
|
|
72
83
|
accessProps: AccessProps = { useMacro: true },
|
|
84
|
+
explicitImplementations = false,
|
|
73
85
|
): void {
|
|
74
86
|
if (access === false) {
|
|
75
87
|
access = DEFAULT_ACCESS_CONTROL;
|
|
76
88
|
}
|
|
77
|
-
setAccessControl(c, access);
|
|
89
|
+
setAccessControl(c, access, explicitImplementations);
|
|
78
90
|
|
|
79
91
|
switch (access) {
|
|
80
92
|
case 'ownable': {
|
|
@@ -93,8 +105,9 @@ export function requireAccessControl(
|
|
|
93
105
|
|
|
94
106
|
if (caller && role) {
|
|
95
107
|
c.addUseClause('soroban_sdk', 'Symbol');
|
|
108
|
+
c.addUseClause('soroban_sdk', 'Vec');
|
|
96
109
|
c.addConstructorArgument({ name: role, type: 'Address' });
|
|
97
|
-
c.addConstructorCode(`access_control::grant_role_no_auth(e,
|
|
110
|
+
c.addConstructorCode(`access_control::grant_role_no_auth(e, &${role}, &Symbol::new(e, "${role}"), &admin);`);
|
|
98
111
|
|
|
99
112
|
if (useMacro) {
|
|
100
113
|
c.addUseClause('stellar_macros', 'only_role');
|
|
@@ -102,7 +115,7 @@ export function requireAccessControl(
|
|
|
102
115
|
} else {
|
|
103
116
|
c.addFunctionCodeBefore(
|
|
104
117
|
fn,
|
|
105
|
-
[`access_control::ensure_role(e,
|
|
118
|
+
[`access_control::ensure_role(e, &Symbol::new(e, "${role}"), ${caller});`],
|
|
106
119
|
trait,
|
|
107
120
|
);
|
|
108
121
|
}
|
|
@@ -123,3 +136,94 @@ export function requireAccessControl(
|
|
|
123
136
|
}
|
|
124
137
|
}
|
|
125
138
|
}
|
|
139
|
+
|
|
140
|
+
const ownableFunctions = defineFunctions({
|
|
141
|
+
get_owner: {
|
|
142
|
+
args: [getSelfArg()],
|
|
143
|
+
returns: 'Option<Address>',
|
|
144
|
+
code: ['ownable::get_owner(e)'],
|
|
145
|
+
},
|
|
146
|
+
transfer_ownership: {
|
|
147
|
+
args: [getSelfArg(), { name: 'new_owner', type: 'Address' }, { name: 'live_until_ledger', type: 'u32' }],
|
|
148
|
+
code: ['ownable::transfer_ownership(e, &new_owner, live_until_ledger);'],
|
|
149
|
+
},
|
|
150
|
+
accept_ownership: {
|
|
151
|
+
args: [getSelfArg()],
|
|
152
|
+
code: ['ownable::accept_ownership(e);'],
|
|
153
|
+
},
|
|
154
|
+
renounce_ownership: {
|
|
155
|
+
args: [getSelfArg()],
|
|
156
|
+
code: ['ownable::renounce_ownership(e);'],
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const accessControlFunctions = defineFunctions({
|
|
161
|
+
has_role: {
|
|
162
|
+
args: [getSelfArg(), { name: 'account', type: 'Address' }, { name: 'role', type: 'Symbol' }],
|
|
163
|
+
returns: 'Option<u32>',
|
|
164
|
+
code: ['access_control::has_role(e, &account, &role)'],
|
|
165
|
+
},
|
|
166
|
+
get_existing_roles: {
|
|
167
|
+
args: [getSelfArg()],
|
|
168
|
+
returns: 'Vec<Symbol>',
|
|
169
|
+
code: ['access_control::get_existing_roles(e)'],
|
|
170
|
+
},
|
|
171
|
+
get_role_member_count: {
|
|
172
|
+
args: [getSelfArg(), { name: 'role', type: 'Symbol' }],
|
|
173
|
+
returns: 'u32',
|
|
174
|
+
code: ['access_control::get_role_member_count(e, &role)'],
|
|
175
|
+
},
|
|
176
|
+
get_role_member: {
|
|
177
|
+
args: [getSelfArg(), { name: 'role', type: 'Symbol' }, { name: 'index', type: 'u32' }],
|
|
178
|
+
returns: 'Address',
|
|
179
|
+
code: ['access_control::get_role_member(e, &role, index)'],
|
|
180
|
+
},
|
|
181
|
+
get_role_admin: {
|
|
182
|
+
args: [getSelfArg(), { name: 'role', type: 'Symbol' }],
|
|
183
|
+
returns: 'Option<Symbol>',
|
|
184
|
+
code: ['access_control::get_role_admin(e, &role)'],
|
|
185
|
+
},
|
|
186
|
+
get_admin: {
|
|
187
|
+
args: [getSelfArg()],
|
|
188
|
+
returns: 'Option<Address>',
|
|
189
|
+
code: ['access_control::get_admin(e)'],
|
|
190
|
+
},
|
|
191
|
+
grant_role: {
|
|
192
|
+
args: [
|
|
193
|
+
getSelfArg(),
|
|
194
|
+
{ name: 'account', type: 'Address' },
|
|
195
|
+
{ name: 'role', type: 'Symbol' },
|
|
196
|
+
{ name: 'caller', type: 'Address' },
|
|
197
|
+
],
|
|
198
|
+
code: ['access_control::grant_role(e, &account, &role, &caller);'],
|
|
199
|
+
},
|
|
200
|
+
revoke_role: {
|
|
201
|
+
args: [
|
|
202
|
+
getSelfArg(),
|
|
203
|
+
{ name: 'account', type: 'Address' },
|
|
204
|
+
{ name: 'role', type: 'Symbol' },
|
|
205
|
+
{ name: 'caller', type: 'Address' },
|
|
206
|
+
],
|
|
207
|
+
code: ['access_control::revoke_role(e, &account, &role, &caller);'],
|
|
208
|
+
},
|
|
209
|
+
renounce_role: {
|
|
210
|
+
args: [getSelfArg(), { name: 'role', type: 'Symbol' }, { name: 'caller', type: 'Address' }],
|
|
211
|
+
code: ['access_control::renounce_role(e, &role, &caller);'],
|
|
212
|
+
},
|
|
213
|
+
transfer_admin_role: {
|
|
214
|
+
args: [getSelfArg(), { name: 'new_admin', type: 'Address' }, { name: 'live_until_ledger', type: 'u32' }],
|
|
215
|
+
code: ['access_control::transfer_admin_role(e, &new_admin, live_until_ledger);'],
|
|
216
|
+
},
|
|
217
|
+
accept_admin_transfer: {
|
|
218
|
+
args: [getSelfArg()],
|
|
219
|
+
code: ['access_control::accept_admin_transfer(e);'],
|
|
220
|
+
},
|
|
221
|
+
set_role_admin: {
|
|
222
|
+
args: [getSelfArg(), { name: 'role', type: 'Symbol' }, { name: 'admin_role', type: 'Symbol' }],
|
|
223
|
+
code: ['access_control::set_role_admin(e, &role, &admin_role);'],
|
|
224
|
+
},
|
|
225
|
+
renounce_admin: {
|
|
226
|
+
args: [getSelfArg()],
|
|
227
|
+
code: ['access_control::renounce_admin(e);'],
|
|
228
|
+
},
|
|
229
|
+
});
|
package/src/stablecoin.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import type { Contract, ContractBuilder } from './contract';
|
|
2
|
-
import { defineFunctions } from './utils/define-functions';
|
|
3
1
|
import { getSelfArg } from './common-options';
|
|
4
|
-
import {
|
|
2
|
+
import type { Contract, ContractBuilder } from './contract';
|
|
5
3
|
import type { FungibleOptions } from './fungible';
|
|
6
4
|
import {
|
|
7
5
|
buildFungible,
|
|
8
6
|
defaults as fungibleDefaults,
|
|
9
|
-
withDefaults as withFungibleDefaults,
|
|
10
7
|
functions as fungibleFunctions,
|
|
11
8
|
isAccessControlRequired as fungibleIsAccessControlRequired,
|
|
9
|
+
withDefaults as withFungibleDefaults,
|
|
12
10
|
} from './fungible';
|
|
11
|
+
import { printContract } from './print';
|
|
13
12
|
import { requireAccessControl, type Access } from './set-access-control';
|
|
13
|
+
import { defineFunctions } from './utils/define-functions';
|
|
14
14
|
|
|
15
15
|
export const defaults: Required<StablecoinOptions> = {
|
|
16
16
|
...fungibleDefaults,
|
|
@@ -20,13 +20,14 @@ export const defaults: Required<StablecoinOptions> = {
|
|
|
20
20
|
} as const;
|
|
21
21
|
|
|
22
22
|
export const limitationsOptions = [false, 'allowlist', 'blocklist'] as const;
|
|
23
|
+
export type Limitations = (typeof limitationsOptions)[number];
|
|
23
24
|
|
|
24
25
|
export function printStablecoin(opts: StablecoinOptions = defaults): string {
|
|
25
26
|
return printContract(buildStablecoin(opts));
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export interface StablecoinOptions extends FungibleOptions {
|
|
29
|
-
limitations?:
|
|
30
|
+
limitations?: Limitations;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
function withDefaults(opts: StablecoinOptions): Required<StablecoinOptions> {
|
|
@@ -48,13 +49,18 @@ export function buildStablecoin(opts: StablecoinOptions): Contract {
|
|
|
48
49
|
const c = buildFungible(allOpts);
|
|
49
50
|
|
|
50
51
|
if (allOpts.limitations) {
|
|
51
|
-
addLimitations(c, allOpts.access, allOpts.limitations);
|
|
52
|
+
addLimitations(c, allOpts.access, allOpts.limitations, allOpts.explicitImplementations);
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
return c;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
function addLimitations(
|
|
58
|
+
function addLimitations(
|
|
59
|
+
c: ContractBuilder,
|
|
60
|
+
access: Access,
|
|
61
|
+
mode: 'allowlist' | 'blocklist',
|
|
62
|
+
explicitImplementations: boolean,
|
|
63
|
+
) {
|
|
58
64
|
const type = mode === 'allowlist';
|
|
59
65
|
|
|
60
66
|
const limitationsTrait = {
|
|
@@ -72,6 +78,8 @@ function addLimitations(c: ContractBuilder, access: Access, mode: 'allowlist' |
|
|
|
72
78
|
c.overrideAssocType('FungibleToken', 'type ContractType = BlockList;');
|
|
73
79
|
}
|
|
74
80
|
|
|
81
|
+
if (explicitImplementations) overrideFungibleReadonlyFunctionsWithBase(c);
|
|
82
|
+
|
|
75
83
|
const [getterFn, addFn, removeFn] = type
|
|
76
84
|
? [functions.allowed, functions.allow_user, functions.disallow_user]
|
|
77
85
|
: [functions.blocked, functions.block_user, functions.unblock_user];
|
|
@@ -85,10 +93,32 @@ function addLimitations(c: ContractBuilder, access: Access, mode: 'allowlist' |
|
|
|
85
93
|
};
|
|
86
94
|
|
|
87
95
|
c.addTraitFunction(limitationsTrait, addFn);
|
|
88
|
-
requireAccessControl(c, limitationsTrait, addFn, access, accessProps);
|
|
96
|
+
requireAccessControl(c, limitationsTrait, addFn, access, accessProps, explicitImplementations);
|
|
89
97
|
|
|
90
98
|
c.addTraitFunction(limitationsTrait, removeFn);
|
|
91
|
-
requireAccessControl(c, limitationsTrait, removeFn, access, accessProps);
|
|
99
|
+
requireAccessControl(c, limitationsTrait, removeFn, access, accessProps, explicitImplementations);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function overrideFungibleReadonlyFunctionsWithBase(c: ContractBuilder) {
|
|
103
|
+
c.addUseClause('stellar_tokens::fungible', 'ContractOverrides');
|
|
104
|
+
const fungibleTokenTrait = {
|
|
105
|
+
traitName: 'FungibleToken',
|
|
106
|
+
structName: c.name,
|
|
107
|
+
tags: [],
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const overrides: Array<[(typeof fungibleFunctions)[keyof typeof fungibleFunctions], string[]]> = [
|
|
111
|
+
[fungibleFunctions.total_supply, ['Self::ContractType::total_supply(e)']],
|
|
112
|
+
[fungibleFunctions.balance, ['Self::ContractType::balance(e, &account)']],
|
|
113
|
+
[fungibleFunctions.allowance, ['Self::ContractType::allowance(e, &owner, &spender)']],
|
|
114
|
+
[fungibleFunctions.decimals, ['Self::ContractType::decimals(e)']],
|
|
115
|
+
[fungibleFunctions.name, ['Self::ContractType::name(e)']],
|
|
116
|
+
[fungibleFunctions.symbol, ['Self::ContractType::symbol(e)']],
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
for (const [fn, code] of overrides) {
|
|
120
|
+
c.setFunctionCode(fn, code, fungibleTokenTrait);
|
|
121
|
+
}
|
|
92
122
|
}
|
|
93
123
|
|
|
94
124
|
const functions = {
|