@openzeppelin/wizard-stellar 0.6.5 → 0.7.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/account.d.ts.map +1 -1
- package/dist/account.js +18 -4
- package/dist/account.js.map +1 -1
- package/dist/add-votes.d.ts +3 -0
- package/dist/add-votes.d.ts.map +1 -0
- package/dist/add-votes.js +53 -0
- package/dist/add-votes.js.map +1 -0
- package/dist/fungible.d.ts +13 -2
- package/dist/fungible.d.ts.map +1 -1
- package/dist/fungible.js +146 -76
- package/dist/fungible.js.map +1 -1
- package/dist/generate/fungible.d.ts.map +1 -1
- package/dist/generate/fungible.js +2 -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 +2 -0
- package/dist/generate/non-fungible.js.map +1 -1
- package/dist/generate/stablecoin.d.ts.map +1 -1
- package/dist/generate/stablecoin.js +2 -0
- package/dist/generate/stablecoin.js.map +1 -1
- package/dist/governor.d.ts.map +1 -1
- package/dist/governor.js +9 -1
- package/dist/governor.js.map +1 -1
- package/dist/non-fungible.d.ts +2 -0
- package/dist/non-fungible.d.ts.map +1 -1
- package/dist/non-fungible.js +152 -126
- package/dist/non-fungible.js.map +1 -1
- package/dist/print.js +16 -1
- package/dist/print.js.map +1 -1
- package/dist/stablecoin.d.ts.map +1 -1
- package/dist/stablecoin.js +6 -31
- package/dist/stablecoin.js.map +1 -1
- package/dist/utils/compose.d.ts +6 -0
- package/dist/utils/compose.d.ts.map +1 -0
- package/dist/utils/compose.js +12 -0
- package/dist/utils/compose.js.map +1 -0
- package/dist/utils/version.d.ts +4 -4
- package/dist/utils/version.js +3 -3
- package/dist/vault.d.ts +1 -1
- package/dist/vault.d.ts.map +1 -1
- package/dist/vault.js +27 -7
- package/dist/vault.js.map +1 -1
- package/dist/zip-shared.d.ts.map +1 -1
- package/dist/zip-shared.js +4 -3
- package/dist/zip-shared.js.map +1 -1
- package/package.json +1 -1
- package/src/account.ts +18 -4
- package/src/add-votes.ts +53 -0
- package/src/fungible.ts +170 -85
- package/src/generate/fungible.ts +2 -0
- package/src/generate/non-fungible.ts +2 -0
- package/src/generate/stablecoin.ts +2 -0
- package/src/governor.ts +10 -1
- package/src/non-fungible.ts +182 -143
- package/src/print.ts +14 -1
- package/src/stablecoin.ts +9 -37
- package/src/utils/compose.ts +8 -0
- package/src/utils/version.ts +3 -3
- package/src/vault.ts +32 -7
- package/src/zip-shared.ts +4 -3
package/src/non-fungible.ts
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import { pickKeys } from '@openzeppelin/wizard-common';
|
|
2
2
|
import { addPausable } from './add-pausable';
|
|
3
3
|
import { addUpgradeable } from './add-upgradeable';
|
|
4
|
+
import { addVotes } from './add-votes';
|
|
4
5
|
import type { CommonContractOptions } from './common-options';
|
|
5
6
|
import { contractDefaults as commonDefaults, getSelfArg, withCommonContractDefaults } from './common-options';
|
|
6
|
-
import type { Contract } from './contract';
|
|
7
|
+
import type { BaseFunction, Contract } from './contract';
|
|
7
8
|
import { ContractBuilder } from './contract';
|
|
8
9
|
import type { OptionsErrorMessages } from './error';
|
|
9
10
|
import { OptionsError } from './error';
|
|
10
11
|
import { printContract } from './print';
|
|
11
12
|
import { type Access, DEFAULT_ACCESS_CONTROL, requireAccessControl, setAccessControl } from './set-access-control';
|
|
12
13
|
import { setInfo } from './set-info';
|
|
13
|
-
import {
|
|
14
|
+
import { printComposedContractType } from './utils/compose';
|
|
15
|
+
import { toByteArray, toUint } from './utils/convert-strings';
|
|
14
16
|
import { defineFunctions } from './utils/define-functions';
|
|
15
17
|
|
|
18
|
+
// Upper bound enforced by the library's royalty setters (100% in basis points).
|
|
19
|
+
const MAX_ROYALTY_BASIS_POINTS = 10_000n;
|
|
20
|
+
|
|
16
21
|
export const defaults: Required<NonFungibleOptions> = {
|
|
17
22
|
name: 'MyToken',
|
|
18
23
|
symbol: 'MTK',
|
|
@@ -21,6 +26,8 @@ export const defaults: Required<NonFungibleOptions> = {
|
|
|
21
26
|
votes: false,
|
|
22
27
|
enumerable: false,
|
|
23
28
|
consecutive: false,
|
|
29
|
+
royalties: false,
|
|
30
|
+
defaultRoyaltyBasisPoints: '0',
|
|
24
31
|
pausable: false,
|
|
25
32
|
upgradeable: false,
|
|
26
33
|
mintable: false,
|
|
@@ -42,6 +49,8 @@ export interface NonFungibleOptions extends CommonContractOptions {
|
|
|
42
49
|
votes?: boolean;
|
|
43
50
|
enumerable?: boolean;
|
|
44
51
|
consecutive?: boolean;
|
|
52
|
+
royalties?: boolean;
|
|
53
|
+
defaultRoyaltyBasisPoints?: string;
|
|
45
54
|
pausable?: boolean;
|
|
46
55
|
upgradeable?: boolean;
|
|
47
56
|
mintable?: boolean;
|
|
@@ -57,6 +66,8 @@ function withDefaults(opts: NonFungibleOptions): Required<NonFungibleOptions> {
|
|
|
57
66
|
votes: opts.votes ?? defaults.votes,
|
|
58
67
|
consecutive: opts.consecutive ?? defaults.consecutive,
|
|
59
68
|
enumerable: opts.enumerable ?? defaults.enumerable,
|
|
69
|
+
royalties: opts.royalties ?? defaults.royalties,
|
|
70
|
+
defaultRoyaltyBasisPoints: opts.defaultRoyaltyBasisPoints || defaults.defaultRoyaltyBasisPoints,
|
|
60
71
|
pausable: opts.pausable ?? defaults.pausable,
|
|
61
72
|
upgradeable: opts.upgradeable ?? defaults.upgradeable,
|
|
62
73
|
mintable: opts.mintable ?? defaults.mintable,
|
|
@@ -65,7 +76,13 @@ function withDefaults(opts: NonFungibleOptions): Required<NonFungibleOptions> {
|
|
|
65
76
|
}
|
|
66
77
|
|
|
67
78
|
export function isAccessControlRequired(opts: Partial<NonFungibleOptions>): boolean {
|
|
68
|
-
return
|
|
79
|
+
return (
|
|
80
|
+
opts.mintable === true ||
|
|
81
|
+
opts.pausable === true ||
|
|
82
|
+
opts.upgradeable === true ||
|
|
83
|
+
opts.consecutive === true ||
|
|
84
|
+
opts.royalties === true
|
|
85
|
+
);
|
|
69
86
|
}
|
|
70
87
|
|
|
71
88
|
export function buildNonFungible(opts: NonFungibleOptions): Contract {
|
|
@@ -90,30 +107,35 @@ export function buildNonFungible(opts: NonFungibleOptions): Contract {
|
|
|
90
107
|
errors.sequential = 'Sequential minting cannot be used with Consecutive extension';
|
|
91
108
|
}
|
|
92
109
|
|
|
93
|
-
if (allOpts.votes && allOpts.enumerable) {
|
|
94
|
-
errors.votes = 'Votes extension cannot be used with Enumerable extension';
|
|
95
|
-
errors.enumerable = 'Enumerable extension cannot be used with Votes extension';
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (allOpts.votes && allOpts.consecutive) {
|
|
99
|
-
errors.votes = 'Votes extension cannot be used with Consecutive extension';
|
|
100
|
-
errors.consecutive = 'Consecutive extension cannot be used with Votes extension';
|
|
101
|
-
}
|
|
102
|
-
|
|
103
110
|
if (Object.keys(errors).length > 0) {
|
|
104
111
|
throw new OptionsError(errors);
|
|
105
112
|
}
|
|
106
113
|
|
|
114
|
+
// Order follows the library's documentation, e.g. `Compose<(Enumerable, NonFungibleVotes)>`.
|
|
115
|
+
const contractTypes = [
|
|
116
|
+
...(allOpts.enumerable ? ['Enumerable'] : []),
|
|
117
|
+
...(allOpts.consecutive ? ['Consecutive'] : []),
|
|
118
|
+
...(allOpts.votes ? ['NonFungibleVotes'] : []),
|
|
119
|
+
];
|
|
120
|
+
|
|
107
121
|
addBase(
|
|
108
122
|
c,
|
|
109
123
|
toByteArray(allOpts.name),
|
|
110
124
|
toByteArray(allOpts.symbol),
|
|
111
125
|
toByteArray(allOpts.tokenUri),
|
|
112
|
-
|
|
126
|
+
contractTypes,
|
|
113
127
|
allOpts.pausable,
|
|
114
128
|
allOpts.explicitImplementations,
|
|
115
129
|
);
|
|
116
130
|
|
|
131
|
+
if (allOpts.votes) {
|
|
132
|
+
addVotes(c, allOpts.explicitImplementations);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (allOpts.royalties) {
|
|
136
|
+
addRoyalties(c, allOpts.defaultRoyaltyBasisPoints, allOpts.access, allOpts.explicitImplementations);
|
|
137
|
+
}
|
|
138
|
+
|
|
117
139
|
if (allOpts.pausable) {
|
|
118
140
|
addPausable(c, allOpts.access, allOpts.explicitImplementations);
|
|
119
141
|
}
|
|
@@ -135,15 +157,7 @@ export function buildNonFungible(opts: NonFungibleOptions): Contract {
|
|
|
135
157
|
}
|
|
136
158
|
|
|
137
159
|
if (allOpts.mintable) {
|
|
138
|
-
addMintable(
|
|
139
|
-
c,
|
|
140
|
-
allOpts.enumerable,
|
|
141
|
-
allOpts.votes,
|
|
142
|
-
allOpts.pausable,
|
|
143
|
-
allOpts.sequential,
|
|
144
|
-
allOpts.access,
|
|
145
|
-
allOpts.explicitImplementations,
|
|
146
|
-
);
|
|
160
|
+
addMintable(c, allOpts.pausable, allOpts.sequential, allOpts.access, allOpts.explicitImplementations);
|
|
147
161
|
}
|
|
148
162
|
|
|
149
163
|
setAccessControl(c, allOpts.access, allOpts.explicitImplementations);
|
|
@@ -157,7 +171,7 @@ function addBase(
|
|
|
157
171
|
name: string,
|
|
158
172
|
symbol: string,
|
|
159
173
|
tokenUri: string,
|
|
160
|
-
|
|
174
|
+
contractTypes: string[],
|
|
161
175
|
pausable: boolean,
|
|
162
176
|
explicitImplementations: boolean,
|
|
163
177
|
) {
|
|
@@ -169,9 +183,9 @@ function addBase(
|
|
|
169
183
|
|
|
170
184
|
// Set token functions
|
|
171
185
|
c.addUseClause('stellar_tokens::non_fungible', 'Base');
|
|
186
|
+
c.addUseClause('stellar_tokens::non_fungible', 'Compose');
|
|
172
187
|
c.addUseClause('stellar_tokens::non_fungible', 'NonFungibleToken');
|
|
173
|
-
if (
|
|
174
|
-
c.addUseClause('stellar_governance::votes', 'Votes');
|
|
188
|
+
if (contractTypes.includes('NonFungibleVotes')) {
|
|
175
189
|
c.addUseClause('stellar_tokens::non_fungible', 'votes::NonFungibleVotes');
|
|
176
190
|
}
|
|
177
191
|
if (explicitImplementations) c.addUseClause('stellar_tokens::non_fungible', 'ContractOverrides');
|
|
@@ -185,7 +199,7 @@ function addBase(
|
|
|
185
199
|
traitName: 'NonFungibleToken',
|
|
186
200
|
structName: c.name,
|
|
187
201
|
tags: explicitImplementations ? ['contractimpl'] : ['contractimpl(contracttrait)'],
|
|
188
|
-
assocType:
|
|
202
|
+
assocType: printComposedContractType(contractTypes.length > 0 ? contractTypes : ['Base']),
|
|
189
203
|
};
|
|
190
204
|
|
|
191
205
|
c.addTraitImplBlock(nonFungibleTokenTrait);
|
|
@@ -201,15 +215,6 @@ function addBase(
|
|
|
201
215
|
c.addFunctionTag(baseFunctions.transfer_from, 'when_not_paused', nonFungibleTokenTrait);
|
|
202
216
|
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.transfer_from);
|
|
203
217
|
}
|
|
204
|
-
|
|
205
|
-
if (votes) {
|
|
206
|
-
c.addTraitImplBlock({
|
|
207
|
-
traitName: 'Votes',
|
|
208
|
-
structName: c.name,
|
|
209
|
-
tags: explicitImplementations ? ['contractimpl'] : ['contractimpl(contracttrait)'],
|
|
210
|
-
section: 'Extensions',
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
218
|
}
|
|
214
219
|
|
|
215
220
|
function addBurnable(c: ContractBuilder, pausable: boolean, explicitImplementations: boolean) {
|
|
@@ -249,8 +254,6 @@ function addEnumerable(c: ContractBuilder, explicitImplementations: boolean) {
|
|
|
249
254
|
if (explicitImplementations)
|
|
250
255
|
c.addTraitForEachFunctions(nonFungibleEnumerableTrait, nonFungibleEnumerableTraitFunctions);
|
|
251
256
|
else c.addTraitImplBlock(nonFungibleEnumerableTrait);
|
|
252
|
-
|
|
253
|
-
c.overrideAssocType('NonFungibleToken', 'type ContractType = Enumerable;');
|
|
254
257
|
}
|
|
255
258
|
|
|
256
259
|
function addConsecutive(c: ContractBuilder, pausable: boolean, access: Access, explicitImplementations: boolean) {
|
|
@@ -266,10 +269,8 @@ function addConsecutive(c: ContractBuilder, pausable: boolean, access: Access, e
|
|
|
266
269
|
|
|
267
270
|
c.addTraitImplBlock(nonFungibleConsecutiveTrait);
|
|
268
271
|
|
|
269
|
-
c.overrideAssocType('NonFungibleToken', 'type ContractType = Consecutive;');
|
|
270
|
-
|
|
271
272
|
const mintFn =
|
|
272
|
-
effectiveAccess === 'ownable' ? consecutiveFunctions.
|
|
273
|
+
effectiveAccess === 'ownable' ? consecutiveFunctions.mint_range : consecutiveFunctions.mint_range_with_caller;
|
|
273
274
|
c.addFreeFunction(mintFn);
|
|
274
275
|
if (pausable) {
|
|
275
276
|
c.addFunctionTag(mintFn, 'when_not_paused');
|
|
@@ -291,8 +292,6 @@ function addConsecutive(c: ContractBuilder, pausable: boolean, access: Access, e
|
|
|
291
292
|
|
|
292
293
|
function addMintable(
|
|
293
294
|
c: ContractBuilder,
|
|
294
|
-
enumerable: boolean,
|
|
295
|
-
votes: boolean,
|
|
296
295
|
pausable: boolean,
|
|
297
296
|
sequential: boolean,
|
|
298
297
|
access: Access,
|
|
@@ -301,40 +300,11 @@ function addMintable(
|
|
|
301
300
|
const accessProps = { useMacro: true, role: 'minter', caller: 'caller' };
|
|
302
301
|
const effectiveAccess = access === false ? DEFAULT_ACCESS_CONTROL : access;
|
|
303
302
|
|
|
304
|
-
let mintFn;
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
if (sequential) {
|
|
308
|
-
mintFn =
|
|
309
|
-
effectiveAccess === 'ownable'
|
|
310
|
-
? enumerableFunctions.sequential_mint
|
|
311
|
-
: enumerableFunctions.sequential_mint_with_caller;
|
|
312
|
-
} else {
|
|
313
|
-
mintFn =
|
|
314
|
-
effectiveAccess === 'ownable'
|
|
315
|
-
? enumerableFunctions.non_sequential_mint
|
|
316
|
-
: enumerableFunctions.non_sequential_mint_with_caller;
|
|
317
|
-
}
|
|
303
|
+
let mintFn: BaseFunction;
|
|
304
|
+
if (sequential) {
|
|
305
|
+
mintFn = effectiveAccess === 'ownable' ? mintFunctions.mint : mintFunctions.mint_with_caller;
|
|
318
306
|
} else {
|
|
319
|
-
|
|
320
|
-
mintFn =
|
|
321
|
-
effectiveAccess === 'ownable'
|
|
322
|
-
? votes
|
|
323
|
-
? votesMintFunctions.sequential_mint
|
|
324
|
-
: baseFunctions.sequential_mint
|
|
325
|
-
: votes
|
|
326
|
-
? votesMintFunctions.sequential_mint_with_caller
|
|
327
|
-
: baseFunctions.sequential_mint_with_caller;
|
|
328
|
-
} else {
|
|
329
|
-
mintFn =
|
|
330
|
-
effectiveAccess === 'ownable'
|
|
331
|
-
? votes
|
|
332
|
-
? votesMintFunctions.mint
|
|
333
|
-
: baseFunctions.mint
|
|
334
|
-
: votes
|
|
335
|
-
? votesMintFunctions.mint_with_caller
|
|
336
|
-
: baseFunctions.mint_with_caller;
|
|
337
|
-
}
|
|
307
|
+
mintFn = effectiveAccess === 'ownable' ? mintFunctions.mint_with_id : mintFunctions.mint_with_id_with_caller;
|
|
338
308
|
}
|
|
339
309
|
|
|
340
310
|
c.addFreeFunction(mintFn);
|
|
@@ -345,6 +315,67 @@ function addMintable(
|
|
|
345
315
|
}
|
|
346
316
|
}
|
|
347
317
|
|
|
318
|
+
function addRoyalties(
|
|
319
|
+
c: ContractBuilder,
|
|
320
|
+
defaultRoyaltyBasisPoints: string,
|
|
321
|
+
access: Access,
|
|
322
|
+
explicitImplementations: boolean,
|
|
323
|
+
) {
|
|
324
|
+
const basisPoints = toUint(defaultRoyaltyBasisPoints, 'defaultRoyaltyBasisPoints', 'u32');
|
|
325
|
+
if (basisPoints > MAX_ROYALTY_BASIS_POINTS) {
|
|
326
|
+
throw new OptionsError({
|
|
327
|
+
defaultRoyaltyBasisPoints: `Maximum royalty is ${MAX_ROYALTY_BASIS_POINTS} basis points (100%)`,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
c.addUseClause('stellar_tokens::non_fungible', 'royalties::{NonFungibleRoyalties, RoyaltySupport}');
|
|
332
|
+
|
|
333
|
+
if (basisPoints > 0n) {
|
|
334
|
+
c.addConstructorArgument({ name: 'royalty_receiver', type: 'Address' });
|
|
335
|
+
c.addConstructorCode(`Base::set_default_royalty(e, &royalty_receiver, ${basisPoints});`);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const nonFungibleRoyaltiesTrait = {
|
|
339
|
+
traitName: 'NonFungibleRoyalties',
|
|
340
|
+
structName: c.name,
|
|
341
|
+
tags: explicitImplementations ? ['contractimpl'] : ['contractimpl(contracttrait)'],
|
|
342
|
+
section: 'Extensions',
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
const effectiveAccess = access === false ? DEFAULT_ACCESS_CONTROL : access;
|
|
346
|
+
const settersFns =
|
|
347
|
+
effectiveAccess === 'ownable'
|
|
348
|
+
? [
|
|
349
|
+
royaltiesFunctions.set_default_royalty_unused_operator,
|
|
350
|
+
royaltiesFunctions.set_token_royalty_unused_operator,
|
|
351
|
+
royaltiesFunctions.remove_token_royalty_unused_operator,
|
|
352
|
+
]
|
|
353
|
+
: [
|
|
354
|
+
royaltiesFunctions.set_default_royalty,
|
|
355
|
+
royaltiesFunctions.set_token_royalty,
|
|
356
|
+
royaltiesFunctions.remove_token_royalty,
|
|
357
|
+
];
|
|
358
|
+
|
|
359
|
+
// Setting royalties is privileged, so the library provides no default implementation for the setters.
|
|
360
|
+
for (const fn of settersFns) {
|
|
361
|
+
c.addTraitFunction(nonFungibleRoyaltiesTrait, fn);
|
|
362
|
+
requireAccessControl(
|
|
363
|
+
c,
|
|
364
|
+
nonFungibleRoyaltiesTrait,
|
|
365
|
+
fn,
|
|
366
|
+
effectiveAccess,
|
|
367
|
+
{
|
|
368
|
+
useMacro: true,
|
|
369
|
+
role: 'royalty_admin',
|
|
370
|
+
caller: 'operator',
|
|
371
|
+
},
|
|
372
|
+
explicitImplementations,
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (explicitImplementations) c.addTraitFunction(nonFungibleRoyaltiesTrait, royaltiesFunctions.royalty_info);
|
|
377
|
+
}
|
|
378
|
+
|
|
348
379
|
const baseFunctions = defineFunctions({
|
|
349
380
|
// NonFungible Trait
|
|
350
381
|
balance: {
|
|
@@ -420,40 +451,27 @@ const baseFunctions = defineFunctions({
|
|
|
420
451
|
returns: 'String',
|
|
421
452
|
code: ['Self::ContractType::token_uri(e, token_id)'],
|
|
422
453
|
},
|
|
454
|
+
});
|
|
423
455
|
|
|
424
|
-
|
|
456
|
+
// Minting goes through the contract type, which keeps the enumeration and the voting units up to date.
|
|
457
|
+
const mintFunctions = defineFunctions({
|
|
425
458
|
mint: {
|
|
426
|
-
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'token_id', type: 'u32' }],
|
|
427
|
-
code: ['Base::mint(e, &to, token_id);'],
|
|
428
|
-
},
|
|
429
|
-
mint_with_caller: {
|
|
430
|
-
name: 'mint',
|
|
431
|
-
args: [
|
|
432
|
-
getSelfArg(),
|
|
433
|
-
{ name: 'to', type: 'Address' },
|
|
434
|
-
{ name: 'token_id', type: 'u32' },
|
|
435
|
-
{ name: 'caller', type: 'Address' },
|
|
436
|
-
],
|
|
437
|
-
code: ['Base::mint(e, &to, token_id);'],
|
|
438
|
-
},
|
|
439
|
-
sequential_mint: {
|
|
440
|
-
name: 'mint',
|
|
441
459
|
args: [getSelfArg(), { name: 'to', type: 'Address' }],
|
|
442
|
-
|
|
460
|
+
returns: 'u32',
|
|
461
|
+
code: ['<Self as NonFungibleToken>::ContractType::mint(e, &to)'],
|
|
443
462
|
},
|
|
444
|
-
|
|
463
|
+
mint_with_caller: {
|
|
445
464
|
name: 'mint',
|
|
446
465
|
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'caller', type: 'Address' }],
|
|
447
|
-
|
|
466
|
+
returns: 'u32',
|
|
467
|
+
code: ['<Self as NonFungibleToken>::ContractType::mint(e, &to)'],
|
|
448
468
|
},
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
const votesMintFunctions = defineFunctions({
|
|
452
|
-
mint: {
|
|
469
|
+
mint_with_id: {
|
|
470
|
+
name: 'mint',
|
|
453
471
|
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'token_id', type: 'u32' }],
|
|
454
|
-
code: ['
|
|
472
|
+
code: ['<Self as NonFungibleToken>::ContractType::mint_with_id(e, &to, token_id);'],
|
|
455
473
|
},
|
|
456
|
-
|
|
474
|
+
mint_with_id_with_caller: {
|
|
457
475
|
name: 'mint',
|
|
458
476
|
args: [
|
|
459
477
|
getSelfArg(),
|
|
@@ -461,17 +479,7 @@ const votesMintFunctions = defineFunctions({
|
|
|
461
479
|
{ name: 'token_id', type: 'u32' },
|
|
462
480
|
{ name: 'caller', type: 'Address' },
|
|
463
481
|
],
|
|
464
|
-
code: ['
|
|
465
|
-
},
|
|
466
|
-
sequential_mint: {
|
|
467
|
-
name: 'mint',
|
|
468
|
-
args: [getSelfArg(), { name: 'to', type: 'Address' }],
|
|
469
|
-
code: ['NonFungibleVotes::sequential_mint(e, &to);'],
|
|
470
|
-
},
|
|
471
|
-
sequential_mint_with_caller: {
|
|
472
|
-
name: 'mint',
|
|
473
|
-
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'caller', type: 'Address' }],
|
|
474
|
-
code: ['NonFungibleVotes::sequential_mint(e, &to);'],
|
|
482
|
+
code: ['<Self as NonFungibleToken>::ContractType::mint_with_id(e, &to, token_id);'],
|
|
475
483
|
},
|
|
476
484
|
});
|
|
477
485
|
|
|
@@ -523,31 +531,6 @@ const enumerableFunctions = defineFunctions({
|
|
|
523
531
|
returns: 'u32',
|
|
524
532
|
code: ['Enumerable::get_token_id(e, index)'],
|
|
525
533
|
},
|
|
526
|
-
non_sequential_mint: {
|
|
527
|
-
name: 'mint',
|
|
528
|
-
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'token_id', type: 'u32' }],
|
|
529
|
-
code: ['Enumerable::non_sequential_mint(e, &to, token_id);'],
|
|
530
|
-
},
|
|
531
|
-
non_sequential_mint_with_caller: {
|
|
532
|
-
name: 'mint',
|
|
533
|
-
args: [
|
|
534
|
-
getSelfArg(),
|
|
535
|
-
{ name: 'to', type: 'Address' },
|
|
536
|
-
{ name: 'token_id', type: 'u32' },
|
|
537
|
-
{ name: 'caller', type: 'Address' },
|
|
538
|
-
],
|
|
539
|
-
code: ['Enumerable::non_sequential_mint(e, &to, token_id);'],
|
|
540
|
-
},
|
|
541
|
-
sequential_mint: {
|
|
542
|
-
name: 'mint',
|
|
543
|
-
args: [getSelfArg(), { name: 'to', type: 'Address' }],
|
|
544
|
-
code: ['Enumerable::sequential_mint(e, &to);'],
|
|
545
|
-
},
|
|
546
|
-
sequential_mint_with_caller: {
|
|
547
|
-
name: 'mint',
|
|
548
|
-
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'caller', type: 'Address' }],
|
|
549
|
-
code: ['Enumerable::sequential_mint(e, &to);'],
|
|
550
|
-
},
|
|
551
534
|
});
|
|
552
535
|
|
|
553
536
|
const nonFungibleEnumerableTraitFunctions = pickKeys(enumerableFunctions, [
|
|
@@ -557,14 +540,13 @@ const nonFungibleEnumerableTraitFunctions = pickKeys(enumerableFunctions, [
|
|
|
557
540
|
]);
|
|
558
541
|
|
|
559
542
|
const consecutiveFunctions = defineFunctions({
|
|
560
|
-
|
|
561
|
-
name: 'batch_mint',
|
|
543
|
+
mint_range: {
|
|
562
544
|
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'amount', type: 'u32' }],
|
|
563
545
|
returns: 'u32',
|
|
564
|
-
code: ['
|
|
546
|
+
code: ['<Self as NonFungibleToken>::ContractType::mint_range(e, &to, amount)'],
|
|
565
547
|
},
|
|
566
|
-
|
|
567
|
-
name: '
|
|
548
|
+
mint_range_with_caller: {
|
|
549
|
+
name: 'mint_range',
|
|
568
550
|
args: [
|
|
569
551
|
getSelfArg(),
|
|
570
552
|
{ name: 'to', type: 'Address' },
|
|
@@ -572,6 +554,63 @@ const consecutiveFunctions = defineFunctions({
|
|
|
572
554
|
{ name: 'caller', type: 'Address' },
|
|
573
555
|
],
|
|
574
556
|
returns: 'u32',
|
|
575
|
-
code: ['
|
|
557
|
+
code: ['<Self as NonFungibleToken>::ContractType::mint_range(e, &to, amount)'],
|
|
558
|
+
},
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
const royaltiesFunctions = defineFunctions({
|
|
562
|
+
set_default_royalty: {
|
|
563
|
+
args: [
|
|
564
|
+
getSelfArg(),
|
|
565
|
+
{ name: 'receiver', type: 'Address' },
|
|
566
|
+
{ name: 'basis_points', type: 'u32' },
|
|
567
|
+
{ name: 'operator', type: 'Address' },
|
|
568
|
+
],
|
|
569
|
+
code: ['Base::set_default_royalty(e, &receiver, basis_points)'],
|
|
570
|
+
},
|
|
571
|
+
set_default_royalty_unused_operator: {
|
|
572
|
+
name: 'set_default_royalty',
|
|
573
|
+
args: [
|
|
574
|
+
getSelfArg(),
|
|
575
|
+
{ name: 'receiver', type: 'Address' },
|
|
576
|
+
{ name: 'basis_points', type: 'u32' },
|
|
577
|
+
{ name: '_operator', type: 'Address' },
|
|
578
|
+
],
|
|
579
|
+
code: ['Base::set_default_royalty(e, &receiver, basis_points)'],
|
|
580
|
+
},
|
|
581
|
+
set_token_royalty: {
|
|
582
|
+
args: [
|
|
583
|
+
getSelfArg(),
|
|
584
|
+
{ name: 'token_id', type: 'u32' },
|
|
585
|
+
{ name: 'receiver', type: 'Address' },
|
|
586
|
+
{ name: 'basis_points', type: 'u32' },
|
|
587
|
+
{ name: 'operator', type: 'Address' },
|
|
588
|
+
],
|
|
589
|
+
code: ['Self::ContractType::set_token_royalty(e, token_id, &receiver, basis_points)'],
|
|
590
|
+
},
|
|
591
|
+
set_token_royalty_unused_operator: {
|
|
592
|
+
name: 'set_token_royalty',
|
|
593
|
+
args: [
|
|
594
|
+
getSelfArg(),
|
|
595
|
+
{ name: 'token_id', type: 'u32' },
|
|
596
|
+
{ name: 'receiver', type: 'Address' },
|
|
597
|
+
{ name: 'basis_points', type: 'u32' },
|
|
598
|
+
{ name: '_operator', type: 'Address' },
|
|
599
|
+
],
|
|
600
|
+
code: ['Self::ContractType::set_token_royalty(e, token_id, &receiver, basis_points)'],
|
|
601
|
+
},
|
|
602
|
+
remove_token_royalty: {
|
|
603
|
+
args: [getSelfArg(), { name: 'token_id', type: 'u32' }, { name: 'operator', type: 'Address' }],
|
|
604
|
+
code: ['Self::ContractType::remove_token_royalty(e, token_id)'],
|
|
605
|
+
},
|
|
606
|
+
remove_token_royalty_unused_operator: {
|
|
607
|
+
name: 'remove_token_royalty',
|
|
608
|
+
args: [getSelfArg(), { name: 'token_id', type: 'u32' }, { name: '_operator', type: 'Address' }],
|
|
609
|
+
code: ['Self::ContractType::remove_token_royalty(e, token_id)'],
|
|
610
|
+
},
|
|
611
|
+
royalty_info: {
|
|
612
|
+
args: [getSelfArg(), { name: 'token_id', type: 'u32' }, { name: 'sale_price', type: 'i128' }],
|
|
613
|
+
returns: '(Address, i128)',
|
|
614
|
+
code: ['Self::ContractType::royalty_info(e, token_id, sale_price)'],
|
|
576
615
|
},
|
|
577
616
|
});
|
package/src/print.ts
CHANGED
|
@@ -139,7 +139,7 @@ function splitLongLineInner(line: string): Lines[] {
|
|
|
139
139
|
const lines = [];
|
|
140
140
|
if (line.length > MAX_USE_CLAUSE_LINE_LENGTH) {
|
|
141
141
|
const max_accessible_string = line.slice(0, MAX_USE_CLAUSE_LINE_LENGTH);
|
|
142
|
-
const lastCommaIndex = max_accessible_string
|
|
142
|
+
const lastCommaIndex = lastTopLevelCommaIndex(max_accessible_string);
|
|
143
143
|
if (lastCommaIndex !== -1) {
|
|
144
144
|
lines.push(TAB + max_accessible_string.slice(0, lastCommaIndex + 1));
|
|
145
145
|
lines.push(...splitLongLineInner(line.slice(lastCommaIndex + 2)));
|
|
@@ -152,6 +152,19 @@ function splitLongLineInner(line: string): Lines[] {
|
|
|
152
152
|
return lines;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
// Prefers breaking between imports over breaking inside a nested group like `total_supply::{A, B}`.
|
|
156
|
+
function lastTopLevelCommaIndex(line: string): number {
|
|
157
|
+
let depth = 0;
|
|
158
|
+
let lastIndex = -1;
|
|
159
|
+
for (let i = 0; i < line.length; i++) {
|
|
160
|
+
const char = line[i];
|
|
161
|
+
if (char === '{') depth++;
|
|
162
|
+
else if (char === '}') depth--;
|
|
163
|
+
else if (char === ',' && depth === 0) lastIndex = i;
|
|
164
|
+
}
|
|
165
|
+
return lastIndex !== -1 ? lastIndex : line.lastIndexOf(',');
|
|
166
|
+
}
|
|
167
|
+
|
|
155
168
|
function sortUseClauses(contract: Contract): UseClause[] {
|
|
156
169
|
return contract.useClauses.sort((a, b) => {
|
|
157
170
|
if (a.containerPath === b.containerPath) {
|
package/src/stablecoin.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { getSelfArg } from './common-options';
|
|
2
2
|
import type { Contract, ContractBuilder } from './contract';
|
|
3
|
-
import type { FungibleOptions } from './fungible';
|
|
3
|
+
import type { FungibleOptions, TransferPolicy } from './fungible';
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
buildFungibleWithTransferPolicy,
|
|
6
6
|
defaults as fungibleDefaults,
|
|
7
7
|
functions as fungibleFunctions,
|
|
8
8
|
isAccessControlRequired as fungibleIsAccessControlRequired,
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
import { printContract } from './print';
|
|
12
12
|
import { requireAccessControl, type Access } from './set-access-control';
|
|
13
13
|
import { defineFunctions } from './utils/define-functions';
|
|
14
|
-
import { OptionsError } from './error';
|
|
15
14
|
|
|
16
15
|
export const defaults: Required<StablecoinOptions> = {
|
|
17
16
|
...fungibleDefaults,
|
|
@@ -23,6 +22,11 @@ export const defaults: Required<StablecoinOptions> = {
|
|
|
23
22
|
export const limitationsOptions = [false, 'allowlist', 'blocklist'] as const;
|
|
24
23
|
export type Limitations = (typeof limitationsOptions)[number];
|
|
25
24
|
|
|
25
|
+
const transferPolicies = {
|
|
26
|
+
allowlist: 'AllowList',
|
|
27
|
+
blocklist: 'BlockList',
|
|
28
|
+
} as const satisfies Record<Exclude<Limitations, false>, TransferPolicy>;
|
|
29
|
+
|
|
26
30
|
export function printStablecoin(opts: StablecoinOptions = defaults): string {
|
|
27
31
|
return printContract(buildStablecoin(opts));
|
|
28
32
|
}
|
|
@@ -47,14 +51,8 @@ export function isAccessControlRequired(opts: Partial<StablecoinOptions>): boole
|
|
|
47
51
|
export function buildStablecoin(opts: StablecoinOptions): Contract {
|
|
48
52
|
const allOpts = withDefaults(opts);
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
votes: 'Votes extension cannot be used with stablecoin limitations',
|
|
53
|
-
limitations: 'Stablecoin limitations cannot be used with Votes extension',
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const c = buildFungible(allOpts);
|
|
54
|
+
const transferPolicy = allOpts.limitations ? transferPolicies[allOpts.limitations] : undefined;
|
|
55
|
+
const c = buildFungibleWithTransferPolicy(allOpts, transferPolicy);
|
|
58
56
|
|
|
59
57
|
if (allOpts.limitations) {
|
|
60
58
|
addLimitations(c, allOpts.access, allOpts.limitations, allOpts.explicitImplementations);
|
|
@@ -80,14 +78,10 @@ function addLimitations(
|
|
|
80
78
|
|
|
81
79
|
if (type) {
|
|
82
80
|
c.addUseClause('stellar_tokens::fungible', 'allowlist::{AllowList, FungibleAllowList}');
|
|
83
|
-
c.overrideAssocType('FungibleToken', 'type ContractType = AllowList;');
|
|
84
81
|
} else {
|
|
85
82
|
c.addUseClause('stellar_tokens::fungible', 'blocklist::{BlockList, FungibleBlockList}');
|
|
86
|
-
c.overrideAssocType('FungibleToken', 'type ContractType = BlockList;');
|
|
87
83
|
}
|
|
88
84
|
|
|
89
|
-
if (explicitImplementations) overrideFungibleReadonlyFunctionsWithBase(c);
|
|
90
|
-
|
|
91
85
|
const [getterFn, addFn, removeFn] = type
|
|
92
86
|
? [functions.allowed, functions.allow_user, functions.disallow_user]
|
|
93
87
|
: [functions.blocked, functions.block_user, functions.unblock_user];
|
|
@@ -107,28 +101,6 @@ function addLimitations(
|
|
|
107
101
|
requireAccessControl(c, limitationsTrait, removeFn, access, accessProps, explicitImplementations);
|
|
108
102
|
}
|
|
109
103
|
|
|
110
|
-
function overrideFungibleReadonlyFunctionsWithBase(c: ContractBuilder) {
|
|
111
|
-
c.addUseClause('stellar_tokens::fungible', 'ContractOverrides');
|
|
112
|
-
const fungibleTokenTrait = {
|
|
113
|
-
traitName: 'FungibleToken',
|
|
114
|
-
structName: c.name,
|
|
115
|
-
tags: [],
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const overrides: Array<[(typeof fungibleFunctions)[keyof typeof fungibleFunctions], string[]]> = [
|
|
119
|
-
[fungibleFunctions.total_supply, ['Self::ContractType::total_supply(e)']],
|
|
120
|
-
[fungibleFunctions.balance, ['Self::ContractType::balance(e, &account)']],
|
|
121
|
-
[fungibleFunctions.allowance, ['Self::ContractType::allowance(e, &owner, &spender)']],
|
|
122
|
-
[fungibleFunctions.decimals, ['Self::ContractType::decimals(e)']],
|
|
123
|
-
[fungibleFunctions.name, ['Self::ContractType::name(e)']],
|
|
124
|
-
[fungibleFunctions.symbol, ['Self::ContractType::symbol(e)']],
|
|
125
|
-
];
|
|
126
|
-
|
|
127
|
-
for (const [fn, code] of overrides) {
|
|
128
|
-
c.setFunctionCode(fn, code, fungibleTokenTrait);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
104
|
const functions = {
|
|
133
105
|
...fungibleFunctions,
|
|
134
106
|
...defineFunctions({
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prints the `ContractType` associated type of a token trait, composed from the
|
|
3
|
+
* listed contract types with the library's `Compose` (e.g. `Compose<(AllowList, TotalSupply)>`).
|
|
4
|
+
*/
|
|
5
|
+
export function printComposedContractType(contractTypes: string[]): string {
|
|
6
|
+
const list = contractTypes.length === 1 ? `${contractTypes[0]},` : contractTypes.join(', ');
|
|
7
|
+
return `type ContractType = Compose<(${list})>;`;
|
|
8
|
+
}
|
package/src/utils/version.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The actual latest version to use in links.
|
|
3
3
|
*/
|
|
4
|
-
export const contractsVersion = '0.
|
|
4
|
+
export const contractsVersion = '0.8.0';
|
|
5
5
|
export const contractsVersionTag = `v${contractsVersion}`;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Semantic version string representing of the minimum compatible version of Contracts to display in output.
|
|
9
9
|
*/
|
|
10
|
-
export const compatibleContractsSemver = '^0.
|
|
10
|
+
export const compatibleContractsSemver = '^0.8.0';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* The Soroban version for which compilation and testing have passing tests
|
|
14
14
|
*/
|
|
15
|
-
export const compatibleSorobanVersion = '
|
|
15
|
+
export const compatibleSorobanVersion = '28.0.0';
|