@openzeppelin/wizard-stellar 0.4.4 → 0.4.5
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 +10 -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 +35 -14
- 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 +86 -36
- 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 +105 -8
- 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/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 +30 -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 +53 -19
- 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 +123 -40
- package/src/set-access-control.ts +105 -7
- package/src/stablecoin.ts +39 -9
- package/src/utils/compile-test.ts +52 -25
- 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,25 @@ 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');
|
|
158
|
+
else c.addUseClause('stellar_macros', 'default_impl');
|
|
136
159
|
c.addUseClause('soroban_sdk', 'contract');
|
|
137
160
|
c.addUseClause('soroban_sdk', 'contractimpl');
|
|
138
161
|
c.addUseClause('soroban_sdk', 'String');
|
|
139
162
|
c.addUseClause('soroban_sdk', 'Env');
|
|
163
|
+
if (explicitImplementations || pausable) c.addUseClause('soroban_sdk', 'Address');
|
|
140
164
|
|
|
141
165
|
const nonFungibleTokenTrait = {
|
|
142
166
|
traitName: 'NonFungibleToken',
|
|
143
167
|
structName: c.name,
|
|
144
|
-
tags: ['default_impl', 'contractimpl'],
|
|
168
|
+
tags: explicitImplementations ? ['contractimpl'] : ['default_impl', 'contractimpl'],
|
|
145
169
|
assocType: 'type ContractType = Base;',
|
|
146
170
|
};
|
|
147
171
|
|
|
148
172
|
c.addTraitImplBlock(nonFungibleTokenTrait);
|
|
149
173
|
|
|
174
|
+
if (explicitImplementations) c.addTraitForEachFunctions(nonFungibleTokenTrait, nonFungibleTokenTraitFunctions);
|
|
175
|
+
|
|
150
176
|
if (pausable) {
|
|
151
177
|
c.addUseClause('stellar_macros', 'when_not_paused');
|
|
152
178
|
|
|
@@ -158,7 +184,7 @@ function addBase(c: ContractBuilder, name: string, symbol: string, tokenUri: str
|
|
|
158
184
|
}
|
|
159
185
|
}
|
|
160
186
|
|
|
161
|
-
function addBurnable(c: ContractBuilder, pausable: boolean) {
|
|
187
|
+
function addBurnable(c: ContractBuilder, pausable: boolean, explicitImplementations: boolean) {
|
|
162
188
|
c.addUseClause('stellar_tokens::non_fungible', 'burnable::NonFungibleBurnable');
|
|
163
189
|
|
|
164
190
|
const nonFungibleBurnableTrait = {
|
|
@@ -176,32 +202,38 @@ function addBurnable(c: ContractBuilder, pausable: boolean) {
|
|
|
176
202
|
|
|
177
203
|
c.addTraitFunction(nonFungibleBurnableTrait, burnableFunctions.burn_from);
|
|
178
204
|
c.addFunctionTag(burnableFunctions.burn_from, 'when_not_paused', nonFungibleBurnableTrait);
|
|
179
|
-
} else
|
|
205
|
+
} else if (explicitImplementations)
|
|
206
|
+
c.addTraitForEachFunctions(nonFungibleBurnableTrait, nonFungibleBurnableFunctions);
|
|
207
|
+
else {
|
|
180
208
|
// prepend '#[default_impl]'
|
|
181
209
|
nonFungibleBurnableTrait.tags.unshift('default_impl');
|
|
182
210
|
c.addTraitImplBlock(nonFungibleBurnableTrait);
|
|
183
211
|
}
|
|
184
212
|
}
|
|
185
213
|
|
|
186
|
-
function addEnumerable(c: ContractBuilder) {
|
|
214
|
+
function addEnumerable(c: ContractBuilder, explicitImplementations: boolean) {
|
|
187
215
|
c.addUseClause('stellar_tokens::non_fungible', 'enumerable::{NonFungibleEnumerable, Enumerable}');
|
|
188
|
-
c.addUseClause('
|
|
216
|
+
if (explicitImplementations) c.addUseClause('soroban_sdk', 'Address');
|
|
217
|
+
else c.addUseClause('stellar_macros', 'default_impl');
|
|
189
218
|
|
|
190
219
|
const nonFungibleEnumerableTrait = {
|
|
191
220
|
traitName: 'NonFungibleEnumerable',
|
|
192
221
|
structName: c.name,
|
|
193
|
-
tags: ['default_impl', 'contractimpl'],
|
|
222
|
+
tags: explicitImplementations ? ['contractimpl'] : ['default_impl', 'contractimpl'],
|
|
194
223
|
section: 'Extensions',
|
|
195
224
|
};
|
|
196
|
-
|
|
225
|
+
if (explicitImplementations)
|
|
226
|
+
c.addTraitForEachFunctions(nonFungibleEnumerableTrait, nonFungibleEnumerableTraitFunctions);
|
|
227
|
+
else c.addTraitImplBlock(nonFungibleEnumerableTrait);
|
|
197
228
|
|
|
198
229
|
c.overrideAssocType('NonFungibleToken', 'type ContractType = Enumerable;');
|
|
199
230
|
}
|
|
200
231
|
|
|
201
|
-
function addConsecutive(c: ContractBuilder, pausable: boolean, access: Access) {
|
|
232
|
+
function addConsecutive(c: ContractBuilder, pausable: boolean, access: Access, explicitImplementations: boolean) {
|
|
202
233
|
c.addUseClause('stellar_tokens::non_fungible', 'consecutive::{NonFungibleConsecutive, Consecutive}');
|
|
203
234
|
c.addUseClause('soroban_sdk', 'Address');
|
|
204
235
|
|
|
236
|
+
const effectiveAccess = access === false ? DEFAULT_ACCESS_CONTROL : access;
|
|
205
237
|
const nonFungibleConsecutiveTrait = {
|
|
206
238
|
traitName: 'NonFungibleConsecutive',
|
|
207
239
|
structName: c.name,
|
|
@@ -213,45 +245,64 @@ function addConsecutive(c: ContractBuilder, pausable: boolean, access: Access) {
|
|
|
213
245
|
|
|
214
246
|
c.overrideAssocType('NonFungibleToken', 'type ContractType = Consecutive;');
|
|
215
247
|
|
|
216
|
-
const mintFn =
|
|
248
|
+
const mintFn =
|
|
249
|
+
effectiveAccess === 'ownable' ? consecutiveFunctions.batch_mint : consecutiveFunctions.batch_mint_with_caller;
|
|
217
250
|
c.addFreeFunction(mintFn);
|
|
218
251
|
if (pausable) {
|
|
219
252
|
c.addFunctionTag(mintFn, 'when_not_paused');
|
|
220
253
|
}
|
|
221
254
|
|
|
222
|
-
requireAccessControl(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
255
|
+
requireAccessControl(
|
|
256
|
+
c,
|
|
257
|
+
undefined,
|
|
258
|
+
mintFn,
|
|
259
|
+
effectiveAccess,
|
|
260
|
+
{
|
|
261
|
+
useMacro: true,
|
|
262
|
+
role: 'minter',
|
|
263
|
+
caller: 'caller',
|
|
264
|
+
},
|
|
265
|
+
explicitImplementations,
|
|
266
|
+
);
|
|
227
267
|
}
|
|
228
268
|
|
|
229
|
-
function addMintable(
|
|
269
|
+
function addMintable(
|
|
270
|
+
c: ContractBuilder,
|
|
271
|
+
enumerable: boolean,
|
|
272
|
+
pausable: boolean,
|
|
273
|
+
sequential: boolean,
|
|
274
|
+
access: Access,
|
|
275
|
+
explicitImplementations: boolean,
|
|
276
|
+
) {
|
|
230
277
|
c.addUseClause('soroban_sdk', 'Address');
|
|
231
278
|
const accessProps = { useMacro: true, role: 'minter', caller: 'caller' };
|
|
279
|
+
const effectiveAccess = access === false ? DEFAULT_ACCESS_CONTROL : access;
|
|
232
280
|
|
|
233
281
|
let mintFn;
|
|
234
282
|
|
|
235
283
|
if (enumerable) {
|
|
236
284
|
if (sequential) {
|
|
237
285
|
mintFn =
|
|
238
|
-
|
|
286
|
+
effectiveAccess === 'ownable'
|
|
287
|
+
? enumerableFunctions.sequential_mint
|
|
288
|
+
: enumerableFunctions.sequential_mint_with_caller;
|
|
239
289
|
} else {
|
|
240
290
|
mintFn =
|
|
241
|
-
|
|
291
|
+
effectiveAccess === 'ownable'
|
|
242
292
|
? enumerableFunctions.non_sequential_mint
|
|
243
293
|
: enumerableFunctions.non_sequential_mint_with_caller;
|
|
244
294
|
}
|
|
245
295
|
} else {
|
|
246
296
|
if (sequential) {
|
|
247
|
-
mintFn =
|
|
297
|
+
mintFn =
|
|
298
|
+
effectiveAccess === 'ownable' ? baseFunctions.sequential_mint : baseFunctions.sequential_mint_with_caller;
|
|
248
299
|
} else {
|
|
249
|
-
mintFn =
|
|
300
|
+
mintFn = effectiveAccess === 'ownable' ? baseFunctions.mint : baseFunctions.mint_with_caller;
|
|
250
301
|
}
|
|
251
302
|
}
|
|
252
303
|
|
|
253
304
|
c.addFreeFunction(mintFn);
|
|
254
|
-
requireAccessControl(c, undefined, mintFn,
|
|
305
|
+
requireAccessControl(c, undefined, mintFn, effectiveAccess, accessProps, explicitImplementations);
|
|
255
306
|
|
|
256
307
|
if (pausable) {
|
|
257
308
|
c.addFunctionTag(mintFn, 'when_not_paused');
|
|
@@ -361,6 +412,20 @@ const baseFunctions = defineFunctions({
|
|
|
361
412
|
},
|
|
362
413
|
});
|
|
363
414
|
|
|
415
|
+
const nonFungibleTokenTraitFunctions = pickKeys(baseFunctions, [
|
|
416
|
+
'balance',
|
|
417
|
+
'owner_of',
|
|
418
|
+
'transfer',
|
|
419
|
+
'transfer_from',
|
|
420
|
+
'approve',
|
|
421
|
+
'approve_for_all',
|
|
422
|
+
'get_approved',
|
|
423
|
+
'is_approved_for_all',
|
|
424
|
+
'name',
|
|
425
|
+
'symbol',
|
|
426
|
+
'token_uri',
|
|
427
|
+
]);
|
|
428
|
+
|
|
364
429
|
const burnableFunctions = defineFunctions({
|
|
365
430
|
burn: {
|
|
366
431
|
args: [getSelfArg(), { name: 'from', type: 'Address' }, { name: 'token_id', type: 'u32' }],
|
|
@@ -377,11 +442,23 @@ const burnableFunctions = defineFunctions({
|
|
|
377
442
|
},
|
|
378
443
|
});
|
|
379
444
|
|
|
445
|
+
const nonFungibleBurnableFunctions = pickKeys(burnableFunctions, ['burn', 'burn_from']);
|
|
446
|
+
|
|
380
447
|
const enumerableFunctions = defineFunctions({
|
|
381
448
|
total_supply: {
|
|
382
449
|
args: [getSelfArg()],
|
|
383
450
|
returns: 'u32',
|
|
384
|
-
code: ['
|
|
451
|
+
code: ['Enumerable::total_supply(e)'],
|
|
452
|
+
},
|
|
453
|
+
get_owner_token_id: {
|
|
454
|
+
args: [getSelfArg(), { name: 'owner', type: 'Address' }, { name: 'index', type: 'u32' }],
|
|
455
|
+
returns: 'u32',
|
|
456
|
+
code: ['Enumerable::get_owner_token_id(e, &owner, index)'],
|
|
457
|
+
},
|
|
458
|
+
get_token_id: {
|
|
459
|
+
args: [getSelfArg(), { name: 'index', type: 'u32' }],
|
|
460
|
+
returns: 'u32',
|
|
461
|
+
code: ['Enumerable::get_token_id(e, index)'],
|
|
385
462
|
},
|
|
386
463
|
non_sequential_mint: {
|
|
387
464
|
name: 'mint',
|
|
@@ -410,12 +487,18 @@ const enumerableFunctions = defineFunctions({
|
|
|
410
487
|
},
|
|
411
488
|
});
|
|
412
489
|
|
|
490
|
+
const nonFungibleEnumerableTraitFunctions = pickKeys(enumerableFunctions, [
|
|
491
|
+
'total_supply',
|
|
492
|
+
'get_owner_token_id',
|
|
493
|
+
'get_token_id',
|
|
494
|
+
]);
|
|
495
|
+
|
|
413
496
|
const consecutiveFunctions = defineFunctions({
|
|
414
497
|
batch_mint: {
|
|
415
498
|
name: 'batch_mint',
|
|
416
499
|
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'amount', type: 'u32' }],
|
|
417
500
|
returns: 'u32',
|
|
418
|
-
code: ['Consecutive::batch_mint(e, &to, amount)
|
|
501
|
+
code: ['Consecutive::batch_mint(e, &to, amount)'],
|
|
419
502
|
},
|
|
420
503
|
batch_mint_with_caller: {
|
|
421
504
|
name: 'batch_mint',
|
|
@@ -426,6 +509,6 @@ const consecutiveFunctions = defineFunctions({
|
|
|
426
509
|
{ name: 'caller', type: 'Address' },
|
|
427
510
|
],
|
|
428
511
|
returns: 'u32',
|
|
429
|
-
code: ['Consecutive::batch_mint(e, &to, amount)
|
|
512
|
+
code: ['Consecutive::batch_mint(e, &to, amount)'],
|
|
430
513
|
},
|
|
431
514
|
});
|
|
@@ -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: ['default_impl', 'contractimpl'],
|
|
32
|
+
tags: explicitImplementations ? ['contractimpl'] : ['default_impl', 'contractimpl'],
|
|
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: ['default_impl', 'contractimpl'],
|
|
54
|
+
tags: explicitImplementations ? ['contractimpl'] : ['default_impl', 'contractimpl'],
|
|
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': {
|
|
@@ -123,3 +135,89 @@ export function requireAccessControl(
|
|
|
123
135
|
}
|
|
124
136
|
}
|
|
125
137
|
}
|
|
138
|
+
|
|
139
|
+
const ownableFunctions = defineFunctions({
|
|
140
|
+
get_owner: {
|
|
141
|
+
args: [getSelfArg()],
|
|
142
|
+
returns: 'Option<Address>',
|
|
143
|
+
code: ['ownable::get_owner(e)'],
|
|
144
|
+
},
|
|
145
|
+
transfer_ownership: {
|
|
146
|
+
args: [getSelfArg(), { name: 'new_owner', type: 'Address' }, { name: 'live_until_ledger', type: 'u32' }],
|
|
147
|
+
code: ['ownable::transfer_ownership(e, &new_owner, live_until_ledger);'],
|
|
148
|
+
},
|
|
149
|
+
accept_ownership: {
|
|
150
|
+
args: [getSelfArg()],
|
|
151
|
+
code: ['ownable::accept_ownership(e);'],
|
|
152
|
+
},
|
|
153
|
+
renounce_ownership: {
|
|
154
|
+
args: [getSelfArg()],
|
|
155
|
+
code: ['ownable::renounce_ownership(e);'],
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const accessControlFunctions = defineFunctions({
|
|
160
|
+
has_role: {
|
|
161
|
+
args: [getSelfArg(), { name: 'account', type: 'Address' }, { name: 'role', type: 'Symbol' }],
|
|
162
|
+
returns: 'Option<u32>',
|
|
163
|
+
code: ['access_control::has_role(e, &account, &role)'],
|
|
164
|
+
},
|
|
165
|
+
get_role_member_count: {
|
|
166
|
+
args: [getSelfArg(), { name: 'role', type: 'Symbol' }],
|
|
167
|
+
returns: 'u32',
|
|
168
|
+
code: ['access_control::get_role_member_count(e, &role)'],
|
|
169
|
+
},
|
|
170
|
+
get_role_member: {
|
|
171
|
+
args: [getSelfArg(), { name: 'role', type: 'Symbol' }, { name: 'index', type: 'u32' }],
|
|
172
|
+
returns: 'Address',
|
|
173
|
+
code: ['access_control::get_role_member(e, &role, index)'],
|
|
174
|
+
},
|
|
175
|
+
get_role_admin: {
|
|
176
|
+
args: [getSelfArg(), { name: 'role', type: 'Symbol' }],
|
|
177
|
+
returns: 'Option<Symbol>',
|
|
178
|
+
code: ['access_control::get_role_admin(e, &role)'],
|
|
179
|
+
},
|
|
180
|
+
get_admin: {
|
|
181
|
+
args: [getSelfArg()],
|
|
182
|
+
returns: 'Option<Address>',
|
|
183
|
+
code: ['access_control::get_admin(e)'],
|
|
184
|
+
},
|
|
185
|
+
grant_role: {
|
|
186
|
+
args: [
|
|
187
|
+
getSelfArg(),
|
|
188
|
+
{ name: 'caller', type: 'Address' },
|
|
189
|
+
{ name: 'account', type: 'Address' },
|
|
190
|
+
{ name: 'role', type: 'Symbol' },
|
|
191
|
+
],
|
|
192
|
+
code: ['access_control::grant_role(e, &caller, &account, &role);'],
|
|
193
|
+
},
|
|
194
|
+
revoke_role: {
|
|
195
|
+
args: [
|
|
196
|
+
getSelfArg(),
|
|
197
|
+
{ name: 'caller', type: 'Address' },
|
|
198
|
+
{ name: 'account', type: 'Address' },
|
|
199
|
+
{ name: 'role', type: 'Symbol' },
|
|
200
|
+
],
|
|
201
|
+
code: ['access_control::revoke_role(e, &caller, &account, &role);'],
|
|
202
|
+
},
|
|
203
|
+
renounce_role: {
|
|
204
|
+
args: [getSelfArg(), { name: 'caller', type: 'Address' }, { name: 'role', type: 'Symbol' }],
|
|
205
|
+
code: ['access_control::renounce_role(e, &caller, &role);'],
|
|
206
|
+
},
|
|
207
|
+
transfer_admin_role: {
|
|
208
|
+
args: [getSelfArg(), { name: 'new_admin', type: 'Address' }, { name: 'live_until_ledger', type: 'u32' }],
|
|
209
|
+
code: ['access_control::transfer_admin_role(e, &new_admin, live_until_ledger);'],
|
|
210
|
+
},
|
|
211
|
+
accept_admin_transfer: {
|
|
212
|
+
args: [getSelfArg()],
|
|
213
|
+
code: ['access_control::accept_admin_transfer(e);'],
|
|
214
|
+
},
|
|
215
|
+
set_role_admin: {
|
|
216
|
+
args: [getSelfArg(), { name: 'role', type: 'Symbol' }, { name: 'admin_role', type: 'Symbol' }],
|
|
217
|
+
code: ['access_control::set_role_admin(e, &role, &admin_role);'],
|
|
218
|
+
},
|
|
219
|
+
renounce_admin: {
|
|
220
|
+
args: [getSelfArg()],
|
|
221
|
+
code: ['access_control::renounce_admin(e);'],
|
|
222
|
+
},
|
|
223
|
+
});
|
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 = {
|