@openzeppelin/wizard-stellar 0.2.2 → 0.3.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.map +1 -1
- package/dist/add-pausable.js +9 -4
- package/dist/add-pausable.js.map +1 -1
- package/dist/add-upgradeable.d.ts.map +1 -1
- package/dist/add-upgradeable.js +6 -2
- package/dist/add-upgradeable.js.map +1 -1
- package/dist/api.d.ts +5 -2
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +9 -1
- package/dist/api.js.map +1 -1
- package/dist/build-generic.d.ts +5 -1
- package/dist/build-generic.d.ts.map +1 -1
- package/dist/build-generic.js +3 -0
- package/dist/build-generic.js.map +1 -1
- package/dist/contract.d.ts +7 -1
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +17 -1
- package/dist/contract.js.map +1 -1
- package/dist/fungible.d.ts +5 -2
- package/dist/fungible.d.ts.map +1 -1
- package/dist/fungible.js +80 -50
- package/dist/fungible.js.map +1 -1
- package/dist/generate/sources.d.ts.map +1 -1
- package/dist/generate/sources.js +6 -0
- package/dist/generate/sources.js.map +1 -1
- package/dist/generate/stablecoin.d.ts +3 -0
- package/dist/generate/stablecoin.d.ts.map +1 -0
- package/dist/generate/stablecoin.js +24 -0
- package/dist/generate/stablecoin.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/kind.js +1 -0
- package/dist/kind.js.map +1 -1
- package/dist/non-fungible.d.ts +1 -0
- package/dist/non-fungible.d.ts.map +1 -1
- package/dist/non-fungible.js +91 -71
- package/dist/non-fungible.js.map +1 -1
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +13 -5
- package/dist/print.js.map +1 -1
- package/dist/set-access-control.d.ts +7 -4
- package/dist/set-access-control.d.ts.map +1 -1
- package/dist/set-access-control.js +57 -15
- package/dist/set-access-control.js.map +1 -1
- package/dist/set-info.d.ts +2 -0
- package/dist/set-info.d.ts.map +1 -1
- package/dist/set-info.js +6 -2
- package/dist/set-info.js.map +1 -1
- package/dist/stablecoin.d.ts +11 -0
- package/dist/stablecoin.d.ts.map +1 -0
- package/dist/stablecoin.js +103 -0
- package/dist/stablecoin.js.map +1 -0
- package/dist/utils/define-functions.d.ts +4 -2
- package/dist/utils/define-functions.d.ts.map +1 -1
- package/dist/utils/define-functions.js +7 -1
- package/dist/utils/define-functions.js.map +1 -1
- package/dist/utils/version.d.ts +3 -3
- package/dist/utils/version.js +2 -2
- package/dist/zip-rust.d.ts +5 -0
- package/dist/zip-rust.d.ts.map +1 -0
- package/dist/zip-rust.js +49 -0
- package/dist/zip-rust.js.map +1 -0
- package/dist/zip-scaffold.d.ts +0 -3
- package/dist/zip-scaffold.d.ts.map +1 -1
- package/dist/zip-scaffold.js +9 -85
- package/dist/zip-scaffold.js.map +1 -1
- package/dist/zip-shared.d.ts +26 -0
- package/dist/zip-shared.d.ts.map +1 -0
- package/dist/zip-shared.js +79 -0
- package/dist/zip-shared.js.map +1 -0
- package/package.json +1 -1
- package/src/add-pausable.ts +9 -4
- package/src/add-upgradeable.ts +6 -2
- package/src/api.ts +27 -4
- package/src/build-generic.ts +6 -0
- package/src/contract.ts +22 -2
- package/src/fungible.ts +84 -56
- package/src/generate/sources.ts +7 -0
- package/src/generate/stablecoin.ts +23 -0
- package/src/index.ts +2 -0
- package/src/kind.ts +1 -0
- package/src/non-fungible.ts +98 -77
- package/src/print.ts +15 -5
- package/src/set-access-control.ts +72 -19
- package/src/set-info.ts +8 -1
- package/src/stablecoin.ts +124 -0
- package/src/utils/define-functions.ts +11 -4
- package/src/utils/version.ts +2 -2
- package/src/zip-rust.ts +57 -0
- package/src/zip-scaffold.ts +16 -91
- package/src/zip-shared.ts +85 -0
package/src/fungible.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Contract } from './contract';
|
|
2
1
|
import { ContractBuilder } from './contract';
|
|
3
2
|
import type { Access } from './set-access-control';
|
|
4
3
|
import { requireAccessControl, setAccessControl } from './set-access-control';
|
|
@@ -21,7 +20,7 @@ export const defaults: Required<FungibleOptions> = {
|
|
|
21
20
|
upgradeable: false,
|
|
22
21
|
premint: '0',
|
|
23
22
|
mintable: false,
|
|
24
|
-
access: commonDefaults.access,
|
|
23
|
+
access: commonDefaults.access,
|
|
25
24
|
info: commonDefaults.info,
|
|
26
25
|
} as const;
|
|
27
26
|
|
|
@@ -39,7 +38,7 @@ export interface FungibleOptions extends CommonContractOptions {
|
|
|
39
38
|
mintable?: boolean;
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
function withDefaults(opts: FungibleOptions): Required<FungibleOptions> {
|
|
41
|
+
export function withDefaults(opts: FungibleOptions): Required<FungibleOptions> {
|
|
43
42
|
return {
|
|
44
43
|
...opts,
|
|
45
44
|
...withCommonContractDefaults(opts),
|
|
@@ -51,7 +50,11 @@ function withDefaults(opts: FungibleOptions): Required<FungibleOptions> {
|
|
|
51
50
|
};
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
export function
|
|
53
|
+
export function isAccessControlRequired(opts: Partial<FungibleOptions>): boolean {
|
|
54
|
+
return opts.mintable === true || opts.pausable === true || opts.upgradeable === true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function buildFungible(opts: FungibleOptions): ContractBuilder {
|
|
55
58
|
const c = new ContractBuilder(opts.name);
|
|
56
59
|
|
|
57
60
|
const allOpts = withDefaults(opts);
|
|
@@ -86,43 +89,73 @@ export function buildFungible(opts: FungibleOptions): Contract {
|
|
|
86
89
|
|
|
87
90
|
function addBase(c: ContractBuilder, name: string, symbol: string, pausable: boolean) {
|
|
88
91
|
// Set metadata
|
|
89
|
-
c.addConstructorCode(
|
|
90
|
-
`fungible::metadata::set_metadata(e, 18, String::from_str(e, "${name}"), String::from_str(e, "${symbol}"));`,
|
|
91
|
-
);
|
|
92
|
+
c.addConstructorCode(`Base::set_metadata(e, 18, String::from_str(e, "${name}"), String::from_str(e, "${symbol}"));`);
|
|
92
93
|
|
|
93
94
|
// Set token functions
|
|
94
|
-
c.addUseClause('stellar_fungible', '
|
|
95
|
+
c.addUseClause('stellar_fungible', 'Base');
|
|
95
96
|
c.addUseClause('stellar_fungible', 'FungibleToken');
|
|
97
|
+
c.addUseClause('stellar_default_impl_macro', 'default_impl');
|
|
96
98
|
c.addUseClause('soroban_sdk', 'contract');
|
|
97
99
|
c.addUseClause('soroban_sdk', 'contractimpl');
|
|
98
100
|
c.addUseClause('soroban_sdk', 'Address');
|
|
99
101
|
c.addUseClause('soroban_sdk', 'String');
|
|
100
102
|
c.addUseClause('soroban_sdk', 'Env');
|
|
101
|
-
c.addUseClause('soroban_sdk', 'Symbol');
|
|
102
103
|
|
|
103
104
|
const fungibleTokenTrait = {
|
|
104
105
|
traitName: 'FungibleToken',
|
|
105
106
|
structName: c.name,
|
|
106
|
-
tags: ['contractimpl'],
|
|
107
|
+
tags: ['default_impl', 'contractimpl'],
|
|
108
|
+
assocType: 'type ContractType = Base;',
|
|
107
109
|
};
|
|
108
110
|
|
|
109
|
-
c.
|
|
110
|
-
c.addTraitFunction(fungibleTokenTrait, functions.balance);
|
|
111
|
-
c.addTraitFunction(fungibleTokenTrait, functions.allowance);
|
|
112
|
-
c.addTraitFunction(fungibleTokenTrait, functions.transfer);
|
|
113
|
-
c.addTraitFunction(fungibleTokenTrait, functions.transfer_from);
|
|
114
|
-
c.addTraitFunction(fungibleTokenTrait, functions.approve);
|
|
115
|
-
c.addTraitFunction(fungibleTokenTrait, functions.decimals);
|
|
116
|
-
c.addTraitFunction(fungibleTokenTrait, functions.name);
|
|
117
|
-
c.addTraitFunction(fungibleTokenTrait, functions.symbol);
|
|
111
|
+
c.addTraitImplBlock(fungibleTokenTrait);
|
|
118
112
|
|
|
119
113
|
if (pausable) {
|
|
120
114
|
c.addUseClause('stellar_pausable_macros', 'when_not_paused');
|
|
115
|
+
|
|
116
|
+
c.addTraitFunction(fungibleTokenTrait, functions.transfer);
|
|
121
117
|
c.addFunctionTag(functions.transfer, 'when_not_paused', fungibleTokenTrait);
|
|
118
|
+
|
|
119
|
+
c.addTraitFunction(fungibleTokenTrait, functions.transfer_from);
|
|
122
120
|
c.addFunctionTag(functions.transfer_from, 'when_not_paused', fungibleTokenTrait);
|
|
123
121
|
}
|
|
124
122
|
}
|
|
125
123
|
|
|
124
|
+
function addMintable(c: ContractBuilder, access: Access, pausable: boolean) {
|
|
125
|
+
switch (access) {
|
|
126
|
+
case false:
|
|
127
|
+
break;
|
|
128
|
+
case 'ownable': {
|
|
129
|
+
c.addFreeFunction(functions.mint);
|
|
130
|
+
|
|
131
|
+
requireAccessControl(c, undefined, functions.mint, access);
|
|
132
|
+
|
|
133
|
+
if (pausable) {
|
|
134
|
+
c.addFunctionTag(functions.mint, 'when_not_paused');
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
case 'roles': {
|
|
139
|
+
c.addFreeFunction(functions.mint_with_caller);
|
|
140
|
+
|
|
141
|
+
requireAccessControl(c, undefined, functions.mint_with_caller, access, {
|
|
142
|
+
useMacro: true,
|
|
143
|
+
caller: 'caller',
|
|
144
|
+
role: 'minter',
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
if (pausable) {
|
|
148
|
+
c.addFunctionTag(functions.mint_with_caller, 'when_not_paused');
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
default: {
|
|
153
|
+
const _: never = access;
|
|
154
|
+
throw new Error('Unknown value for `access`');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
126
159
|
function addBurnable(c: ContractBuilder, pausable: boolean) {
|
|
127
160
|
c.addUseClause('stellar_fungible', 'burnable::FungibleBurnable');
|
|
128
161
|
c.addUseClause('soroban_sdk', 'Address');
|
|
@@ -134,13 +167,18 @@ function addBurnable(c: ContractBuilder, pausable: boolean) {
|
|
|
134
167
|
section: 'Extensions',
|
|
135
168
|
};
|
|
136
169
|
|
|
137
|
-
c.addTraitFunction(fungibleBurnableTrait, functions.burn);
|
|
138
|
-
c.addTraitFunction(fungibleBurnableTrait, functions.burn_from);
|
|
139
|
-
|
|
140
170
|
if (pausable) {
|
|
141
171
|
c.addUseClause('stellar_pausable_macros', 'when_not_paused');
|
|
172
|
+
|
|
173
|
+
c.addTraitFunction(fungibleBurnableTrait, functions.burn);
|
|
142
174
|
c.addFunctionTag(functions.burn, 'when_not_paused', fungibleBurnableTrait);
|
|
175
|
+
|
|
176
|
+
c.addTraitFunction(fungibleBurnableTrait, functions.burn_from);
|
|
143
177
|
c.addFunctionTag(functions.burn_from, 'when_not_paused', fungibleBurnableTrait);
|
|
178
|
+
} else {
|
|
179
|
+
// prepend '#[default_impl]'
|
|
180
|
+
fungibleBurnableTrait.tags.unshift('default_impl');
|
|
181
|
+
c.addTraitImplBlock(fungibleBurnableTrait);
|
|
144
182
|
}
|
|
145
183
|
}
|
|
146
184
|
|
|
@@ -157,11 +195,10 @@ function addPremint(c: ContractBuilder, amount: string) {
|
|
|
157
195
|
// TODO: handle signed int?
|
|
158
196
|
const premintAbsolute = toUint(getInitialSupply(amount, 18), 'premint', 'u128');
|
|
159
197
|
|
|
160
|
-
c.addUseClause('stellar_fungible', 'mintable::FungibleMintable');
|
|
161
198
|
c.addUseClause('soroban_sdk', 'Address');
|
|
162
199
|
|
|
163
200
|
c.addConstructorArgument({ name: 'recipient', type: 'Address' });
|
|
164
|
-
c.addConstructorCode(`
|
|
201
|
+
c.addConstructorCode(`Base::mint(e, &recipient, ${premintAbsolute});`);
|
|
165
202
|
}
|
|
166
203
|
}
|
|
167
204
|
|
|
@@ -206,41 +243,22 @@ export function getInitialSupply(premint: string, decimals: number): string {
|
|
|
206
243
|
return result;
|
|
207
244
|
}
|
|
208
245
|
|
|
209
|
-
|
|
210
|
-
c.addUseClause('stellar_fungible', 'mintable::FungibleMintable');
|
|
211
|
-
|
|
212
|
-
const fungibleMintableTrait = {
|
|
213
|
-
traitName: 'FungibleMintable',
|
|
214
|
-
structName: c.name,
|
|
215
|
-
tags: ['contractimpl'],
|
|
216
|
-
section: 'Extensions',
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
c.addTraitFunction(fungibleMintableTrait, functions.mint);
|
|
220
|
-
|
|
221
|
-
requireAccessControl(c, fungibleMintableTrait, functions.mint, access);
|
|
222
|
-
|
|
223
|
-
if (pausable) {
|
|
224
|
-
c.addFunctionTag(functions.mint, 'when_not_paused', fungibleMintableTrait);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const functions = defineFunctions({
|
|
246
|
+
export const functions = defineFunctions({
|
|
229
247
|
// Token Functions
|
|
230
248
|
total_supply: {
|
|
231
249
|
args: [getSelfArg()],
|
|
232
250
|
returns: 'i128',
|
|
233
|
-
code: ['
|
|
251
|
+
code: ['Self::ContractType::total_supply(e)'],
|
|
234
252
|
},
|
|
235
253
|
balance: {
|
|
236
254
|
args: [getSelfArg(), { name: 'account', type: 'Address' }],
|
|
237
255
|
returns: 'i128',
|
|
238
|
-
code: ['
|
|
256
|
+
code: ['Self::ContractType::balance(e, &account)'],
|
|
239
257
|
},
|
|
240
258
|
allowance: {
|
|
241
259
|
args: [getSelfArg(), { name: 'owner', type: 'Address' }, { name: 'spender', type: 'Address' }],
|
|
242
260
|
returns: 'i128',
|
|
243
|
-
code: ['
|
|
261
|
+
code: ['Self::ContractType::allowance(e, &owner, &spender)'],
|
|
244
262
|
},
|
|
245
263
|
transfer: {
|
|
246
264
|
args: [
|
|
@@ -249,7 +267,7 @@ const functions = defineFunctions({
|
|
|
249
267
|
{ name: 'to', type: 'Address' },
|
|
250
268
|
{ name: 'amount', type: 'i128' },
|
|
251
269
|
],
|
|
252
|
-
code: ['
|
|
270
|
+
code: ['Self::ContractType::transfer(e, &from, &to, amount)'],
|
|
253
271
|
},
|
|
254
272
|
transfer_from: {
|
|
255
273
|
args: [
|
|
@@ -259,7 +277,7 @@ const functions = defineFunctions({
|
|
|
259
277
|
{ name: 'to', type: 'Address' },
|
|
260
278
|
{ name: 'amount', type: 'i128' },
|
|
261
279
|
],
|
|
262
|
-
code: ['
|
|
280
|
+
code: ['Self::ContractType::transfer_from(e, &spender, &from, &to, amount)'],
|
|
263
281
|
},
|
|
264
282
|
approve: {
|
|
265
283
|
args: [
|
|
@@ -269,28 +287,28 @@ const functions = defineFunctions({
|
|
|
269
287
|
{ name: 'amount', type: 'i128' },
|
|
270
288
|
{ name: 'live_until_ledger', type: 'u32' },
|
|
271
289
|
],
|
|
272
|
-
code: ['
|
|
290
|
+
code: ['Self::ContractType::approve(e, &owner, &spender, amount, live_until_ledger)'],
|
|
273
291
|
},
|
|
274
292
|
decimals: {
|
|
275
293
|
args: [getSelfArg()],
|
|
276
294
|
returns: 'u32',
|
|
277
|
-
code: ['
|
|
295
|
+
code: ['Self::ContractType::decimals(e)'],
|
|
278
296
|
},
|
|
279
297
|
name: {
|
|
280
298
|
args: [getSelfArg()],
|
|
281
299
|
returns: 'String',
|
|
282
|
-
code: ['
|
|
300
|
+
code: ['Self::ContractType::name(e)'],
|
|
283
301
|
},
|
|
284
302
|
symbol: {
|
|
285
303
|
args: [getSelfArg()],
|
|
286
304
|
returns: 'String',
|
|
287
|
-
code: ['
|
|
305
|
+
code: ['Self::ContractType::symbol(e)'],
|
|
288
306
|
},
|
|
289
307
|
|
|
290
308
|
// Extensions
|
|
291
309
|
burn: {
|
|
292
310
|
args: [getSelfArg(), { name: 'from', type: 'Address' }, { name: 'amount', type: 'i128' }],
|
|
293
|
-
code: ['
|
|
311
|
+
code: ['Base::burn(e, &from, amount)'],
|
|
294
312
|
},
|
|
295
313
|
burn_from: {
|
|
296
314
|
args: [
|
|
@@ -299,10 +317,20 @@ const functions = defineFunctions({
|
|
|
299
317
|
{ name: 'from', type: 'Address' },
|
|
300
318
|
{ name: 'amount', type: 'i128' },
|
|
301
319
|
],
|
|
302
|
-
code: ['
|
|
320
|
+
code: ['Base::burn_from(e, &spender, &from, amount)'],
|
|
303
321
|
},
|
|
304
322
|
mint: {
|
|
305
323
|
args: [getSelfArg(), { name: 'account', type: 'Address' }, { name: 'amount', type: 'i128' }],
|
|
306
|
-
code: ['
|
|
324
|
+
code: ['Base::mint(e, &account, amount);'],
|
|
325
|
+
},
|
|
326
|
+
mint_with_caller: {
|
|
327
|
+
name: 'mint',
|
|
328
|
+
args: [
|
|
329
|
+
getSelfArg(),
|
|
330
|
+
{ name: 'account', type: 'Address' },
|
|
331
|
+
{ name: 'amount', type: 'i128' },
|
|
332
|
+
{ name: 'caller', type: 'Address' },
|
|
333
|
+
],
|
|
334
|
+
code: ['Base::mint(e, &account, amount);'],
|
|
307
335
|
},
|
|
308
336
|
});
|
package/src/generate/sources.ts
CHANGED
|
@@ -4,6 +4,7 @@ import crypto from 'crypto';
|
|
|
4
4
|
|
|
5
5
|
import { generateFungibleOptions } from './fungible';
|
|
6
6
|
import { generateNonFungibleOptions } from './non-fungible';
|
|
7
|
+
import { generateStablecoinOptions } from './stablecoin';
|
|
7
8
|
import type { GenericOptions, KindedOptions } from '../build-generic';
|
|
8
9
|
import { buildGeneric } from '../build-generic';
|
|
9
10
|
import { printContract } from '../print';
|
|
@@ -24,6 +25,12 @@ export function* generateOptions(kind?: Kind): Generator<GenericOptions> {
|
|
|
24
25
|
yield { kind: 'NonFungible', ...kindOpts };
|
|
25
26
|
}
|
|
26
27
|
}
|
|
28
|
+
|
|
29
|
+
if (!kind || kind === 'Stablecoin') {
|
|
30
|
+
for (const kindOpts of generateStablecoinOptions()) {
|
|
31
|
+
yield { kind: 'Stablecoin', ...kindOpts };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
interface GeneratedContract {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { limitationsOptions, type StablecoinOptions } from '../stablecoin';
|
|
2
|
+
import { accessOptions } from '../set-access-control';
|
|
3
|
+
import { infoOptions } from '../set-info';
|
|
4
|
+
import { generateAlternatives } from './alternatives';
|
|
5
|
+
|
|
6
|
+
const booleans = [true, false];
|
|
7
|
+
|
|
8
|
+
const blueprint = {
|
|
9
|
+
name: ['MyStablecoin'],
|
|
10
|
+
symbol: ['MST'],
|
|
11
|
+
burnable: booleans,
|
|
12
|
+
pausable: booleans,
|
|
13
|
+
upgradeable: booleans,
|
|
14
|
+
mintable: booleans,
|
|
15
|
+
premint: ['1'],
|
|
16
|
+
access: accessOptions,
|
|
17
|
+
limitations: limitationsOptions,
|
|
18
|
+
info: infoOptions,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function* generateStablecoinOptions(): Generator<Required<StablecoinOptions>> {
|
|
22
|
+
yield* generateAlternatives(blueprint);
|
|
23
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -23,6 +23,8 @@ export { contractsVersion, contractsVersionTag, compatibleContractsSemver } from
|
|
|
23
23
|
|
|
24
24
|
export { fungible } from './api';
|
|
25
25
|
export { nonFungible } from './api';
|
|
26
|
+
export { stablecoin } from './api';
|
|
26
27
|
|
|
27
28
|
export type { FungibleOptions } from './fungible';
|
|
28
29
|
export type { NonFungibleOptions } from './non-fungible';
|
|
30
|
+
export type { StablecoinOptions } from './stablecoin';
|
package/src/kind.ts
CHANGED
package/src/non-fungible.ts
CHANGED
|
@@ -57,6 +57,10 @@ function withDefaults(opts: NonFungibleOptions): Required<NonFungibleOptions> {
|
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
export function isAccessControlRequired(opts: Partial<NonFungibleOptions>): boolean {
|
|
61
|
+
return opts.mintable === true || opts.pausable === true || opts.upgradeable === true || opts.consecutive === true;
|
|
62
|
+
}
|
|
63
|
+
|
|
60
64
|
export function buildNonFungible(opts: NonFungibleOptions): Contract {
|
|
61
65
|
const c = new ContractBuilder(opts.name);
|
|
62
66
|
|
|
@@ -117,13 +121,15 @@ export function buildNonFungible(opts: NonFungibleOptions): Contract {
|
|
|
117
121
|
|
|
118
122
|
function addBase(c: ContractBuilder, name: string, symbol: string, pausable: boolean) {
|
|
119
123
|
// Set metadata
|
|
120
|
-
c.addConstructorCode(
|
|
121
|
-
|
|
122
|
-
);
|
|
124
|
+
c.addConstructorCode('let uri = String::from_str(e, "www.mytoken.com");');
|
|
125
|
+
c.addConstructorCode(`let name = String::from_str(e, "${name}");`);
|
|
126
|
+
c.addConstructorCode(`let symbol = String::from_str(e, "${symbol}");`);
|
|
127
|
+
c.addConstructorCode(`Base::set_metadata(e, uri, name, symbol);`);
|
|
123
128
|
|
|
124
129
|
// Set token functions
|
|
125
130
|
c.addUseClause('stellar_non_fungible', 'Base');
|
|
126
131
|
c.addUseClause('stellar_non_fungible', 'NonFungibleToken');
|
|
132
|
+
c.addUseClause('stellar_default_impl_macro', 'default_impl');
|
|
127
133
|
c.addUseClause('soroban_sdk', 'contract');
|
|
128
134
|
c.addUseClause('soroban_sdk', 'contractimpl');
|
|
129
135
|
c.addUseClause('soroban_sdk', 'Address');
|
|
@@ -133,28 +139,20 @@ function addBase(c: ContractBuilder, name: string, symbol: string, pausable: boo
|
|
|
133
139
|
const nonFungibleTokenTrait = {
|
|
134
140
|
traitName: 'NonFungibleToken',
|
|
135
141
|
structName: c.name,
|
|
136
|
-
tags: ['contractimpl'],
|
|
142
|
+
tags: ['default_impl', 'contractimpl'],
|
|
137
143
|
assocType: 'type ContractType = Base;',
|
|
138
144
|
};
|
|
139
145
|
|
|
140
|
-
|
|
141
|
-
// but we lose the customization for `pausable`, and so on...
|
|
142
|
-
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.owner_of);
|
|
143
|
-
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.transfer);
|
|
144
|
-
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.transfer_from);
|
|
145
|
-
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.balance);
|
|
146
|
-
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.approve);
|
|
147
|
-
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.approve_for_all);
|
|
148
|
-
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.get_approved);
|
|
149
|
-
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.is_approved_for_all);
|
|
150
|
-
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.name);
|
|
151
|
-
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.symbol);
|
|
152
|
-
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.token_uri);
|
|
146
|
+
c.addTraitImplBlock(nonFungibleTokenTrait);
|
|
153
147
|
|
|
154
148
|
if (pausable) {
|
|
155
149
|
c.addUseClause('stellar_pausable_macros', 'when_not_paused');
|
|
150
|
+
|
|
151
|
+
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.transfer);
|
|
156
152
|
c.addFunctionTag(baseFunctions.transfer, 'when_not_paused', nonFungibleTokenTrait);
|
|
153
|
+
|
|
157
154
|
c.addFunctionTag(baseFunctions.transfer_from, 'when_not_paused', nonFungibleTokenTrait);
|
|
155
|
+
c.addTraitFunction(nonFungibleTokenTrait, baseFunctions.transfer_from);
|
|
158
156
|
}
|
|
159
157
|
}
|
|
160
158
|
|
|
@@ -169,20 +167,24 @@ function addBurnable(c: ContractBuilder, pausable: boolean) {
|
|
|
169
167
|
section: 'Extensions',
|
|
170
168
|
};
|
|
171
169
|
|
|
172
|
-
c.addTraitFunction(nonFungibleBurnableTrait, burnableFunctions.burn);
|
|
173
|
-
c.addTraitFunction(nonFungibleBurnableTrait, burnableFunctions.burn_from);
|
|
174
|
-
|
|
175
170
|
if (pausable) {
|
|
176
171
|
c.addUseClause('stellar_pausable_macros', 'when_not_paused');
|
|
172
|
+
|
|
173
|
+
c.addTraitFunction(nonFungibleBurnableTrait, burnableFunctions.burn);
|
|
177
174
|
c.addFunctionTag(burnableFunctions.burn, 'when_not_paused', nonFungibleBurnableTrait);
|
|
175
|
+
|
|
176
|
+
c.addTraitFunction(nonFungibleBurnableTrait, burnableFunctions.burn_from);
|
|
178
177
|
c.addFunctionTag(burnableFunctions.burn_from, 'when_not_paused', nonFungibleBurnableTrait);
|
|
178
|
+
} else {
|
|
179
|
+
// prepend '#[default_impl]'
|
|
180
|
+
nonFungibleBurnableTrait.tags.unshift('default_impl');
|
|
181
|
+
c.addTraitImplBlock(nonFungibleBurnableTrait);
|
|
179
182
|
}
|
|
180
183
|
}
|
|
181
184
|
|
|
182
185
|
function addEnumerable(c: ContractBuilder) {
|
|
183
186
|
c.addUseClause('stellar_non_fungible', 'enumerable::{NonFungibleEnumerable, Enumerable}');
|
|
184
187
|
c.addUseClause('stellar_default_impl_macro', 'default_impl');
|
|
185
|
-
c.addUseClause('stellar_non_fungible', 'ContractOverrides');
|
|
186
188
|
|
|
187
189
|
const nonFungibleEnumerableTrait = {
|
|
188
190
|
traitName: 'NonFungibleEnumerable',
|
|
@@ -193,23 +195,10 @@ function addEnumerable(c: ContractBuilder) {
|
|
|
193
195
|
c.addTraitImplBlock(nonFungibleEnumerableTrait);
|
|
194
196
|
|
|
195
197
|
c.overrideAssocType('NonFungibleToken', 'type ContractType = Enumerable;');
|
|
196
|
-
|
|
197
|
-
// Below is not required due to `defaultimpl` macro. If we require to customize the functions,
|
|
198
|
-
// then we should:
|
|
199
|
-
// 1. get rid of the `defaultimpl` macro form `tags` above,
|
|
200
|
-
// 2. get rid of `c.addImplementedTrait(nonFungibleEnumerableTrait);` line,
|
|
201
|
-
// 3. uncomment the section below:
|
|
202
|
-
// 4. uncomment `get_owner_token_id` and `get_token_id` from `enumerableFunctions` definition
|
|
203
|
-
/*
|
|
204
|
-
c.addFunction(nonFungibleEnumerableTrait, enumerableFunctions.total_supply);
|
|
205
|
-
c.addFunction(nonFungibleEnumerableTrait, enumerableFunctions.get_owner_token_id);
|
|
206
|
-
c.addFunction(nonFungibleEnumerableTrait, enumerableFunctions.get_token_id);
|
|
207
|
-
*/
|
|
208
198
|
}
|
|
209
199
|
|
|
210
200
|
function addConsecutive(c: ContractBuilder, pausable: boolean, access: Access) {
|
|
211
201
|
c.addUseClause('stellar_non_fungible', 'consecutive::{NonFungibleConsecutive, Consecutive}');
|
|
212
|
-
c.addUseClause('stellar_non_fungible', 'ContractOverrides');
|
|
213
202
|
|
|
214
203
|
const nonFungibleConsecutiveTrait = {
|
|
215
204
|
traitName: 'NonFungibleConsecutive',
|
|
@@ -222,48 +211,48 @@ function addConsecutive(c: ContractBuilder, pausable: boolean, access: Access) {
|
|
|
222
211
|
|
|
223
212
|
c.overrideAssocType('NonFungibleToken', 'type ContractType = Consecutive;');
|
|
224
213
|
|
|
225
|
-
|
|
214
|
+
const mintFn = access === 'ownable' ? consecutiveFunctions.batch_mint : consecutiveFunctions.batch_mint_with_caller;
|
|
215
|
+
c.addFreeFunction(mintFn);
|
|
226
216
|
if (pausable) {
|
|
227
|
-
c.addFunctionTag(
|
|
217
|
+
c.addFunctionTag(mintFn, 'when_not_paused');
|
|
228
218
|
}
|
|
229
219
|
|
|
230
|
-
requireAccessControl(c, undefined,
|
|
220
|
+
requireAccessControl(c, undefined, mintFn, access, {
|
|
221
|
+
useMacro: true,
|
|
222
|
+
role: 'minter',
|
|
223
|
+
caller: 'caller',
|
|
224
|
+
});
|
|
231
225
|
}
|
|
232
226
|
|
|
233
227
|
function addMintable(c: ContractBuilder, enumerable: boolean, pausable: boolean, sequential: boolean, access: Access) {
|
|
234
|
-
|
|
228
|
+
const accessProps = { useMacro: true, role: 'minter', caller: 'caller' };
|
|
229
|
+
|
|
230
|
+
let mintFn;
|
|
231
|
+
|
|
232
|
+
if (enumerable) {
|
|
235
233
|
if (sequential) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
requireAccessControl(c, undefined, baseFunctions.sequential_mint, access);
|
|
239
|
-
if (pausable) {
|
|
240
|
-
c.addFunctionTag(baseFunctions.sequential_mint, 'when_not_paused');
|
|
241
|
-
}
|
|
234
|
+
mintFn =
|
|
235
|
+
access === 'ownable' ? enumerableFunctions.sequential_mint : enumerableFunctions.sequential_mint_with_caller;
|
|
242
236
|
} else {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
c.addFunctionTag(baseFunctions.mint, 'when_not_paused');
|
|
248
|
-
}
|
|
237
|
+
mintFn =
|
|
238
|
+
access === 'ownable'
|
|
239
|
+
? enumerableFunctions.non_sequential_mint
|
|
240
|
+
: enumerableFunctions.non_sequential_mint_with_caller;
|
|
249
241
|
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
if (enumerable) {
|
|
242
|
+
} else {
|
|
253
243
|
if (sequential) {
|
|
254
|
-
|
|
255
|
-
requireAccessControl(c, undefined, enumerableFunctions.sequential_mint, access);
|
|
256
|
-
if (pausable) {
|
|
257
|
-
c.addFunctionTag(enumerableFunctions.sequential_mint, 'when_not_paused');
|
|
258
|
-
}
|
|
244
|
+
mintFn = access === 'ownable' ? baseFunctions.sequential_mint : baseFunctions.sequential_mint_with_caller;
|
|
259
245
|
} else {
|
|
260
|
-
|
|
261
|
-
requireAccessControl(c, undefined, enumerableFunctions.non_sequential_mint, access);
|
|
262
|
-
if (pausable) {
|
|
263
|
-
c.addFunctionTag(enumerableFunctions.non_sequential_mint, 'when_not_paused');
|
|
264
|
-
}
|
|
246
|
+
mintFn = access === 'ownable' ? baseFunctions.mint : baseFunctions.mint_with_caller;
|
|
265
247
|
}
|
|
266
248
|
}
|
|
249
|
+
|
|
250
|
+
c.addFreeFunction(mintFn);
|
|
251
|
+
requireAccessControl(c, undefined, mintFn, access, accessProps);
|
|
252
|
+
|
|
253
|
+
if (pausable) {
|
|
254
|
+
c.addFunctionTag(mintFn, 'when_not_paused');
|
|
255
|
+
}
|
|
267
256
|
}
|
|
268
257
|
|
|
269
258
|
const baseFunctions = defineFunctions({
|
|
@@ -347,10 +336,26 @@ const baseFunctions = defineFunctions({
|
|
|
347
336
|
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'token_id', type: 'u32' }],
|
|
348
337
|
code: ['Base::mint(e, &to, token_id);'],
|
|
349
338
|
},
|
|
339
|
+
mint_with_caller: {
|
|
340
|
+
name: 'mint',
|
|
341
|
+
args: [
|
|
342
|
+
getSelfArg(),
|
|
343
|
+
{ name: 'to', type: 'Address' },
|
|
344
|
+
{ name: 'token_id', type: 'u32' },
|
|
345
|
+
{ name: 'caller', type: 'Address' },
|
|
346
|
+
],
|
|
347
|
+
code: ['Base::mint(e, &to, token_id);'],
|
|
348
|
+
},
|
|
350
349
|
sequential_mint: {
|
|
350
|
+
name: 'mint',
|
|
351
351
|
args: [getSelfArg(), { name: 'to', type: 'Address' }],
|
|
352
352
|
code: ['Base::sequential_mint(e, &to);'],
|
|
353
353
|
},
|
|
354
|
+
sequential_mint_with_caller: {
|
|
355
|
+
name: 'mint',
|
|
356
|
+
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'caller', type: 'Address' }],
|
|
357
|
+
code: ['Base::sequential_mint(e, &to);'],
|
|
358
|
+
},
|
|
354
359
|
});
|
|
355
360
|
|
|
356
361
|
const burnableFunctions = defineFunctions({
|
|
@@ -375,33 +380,49 @@ const enumerableFunctions = defineFunctions({
|
|
|
375
380
|
returns: 'u32',
|
|
376
381
|
code: ['non_fungible::enumerable::Enumerable::total_supply(e)'],
|
|
377
382
|
},
|
|
378
|
-
// These are not currently used, see addEnumerable() above
|
|
379
|
-
/*
|
|
380
|
-
get_owner_token_id: {
|
|
381
|
-
args: [getSelfArg(), { name: 'owner', type: 'Address' }, { name: 'index', type: 'u32' }],
|
|
382
|
-
returns: 'u32',
|
|
383
|
-
code: ['Enumerable::get_owner_token_id(e, &owner, index)'],
|
|
384
|
-
},
|
|
385
|
-
get_token_id: {
|
|
386
|
-
args: [getSelfArg(), { name: 'index', type: 'u32' }],
|
|
387
|
-
returns: 'u32',
|
|
388
|
-
code: ['Enumerable::get_token_id(e, index)'],
|
|
389
|
-
},
|
|
390
|
-
*/
|
|
391
383
|
non_sequential_mint: {
|
|
384
|
+
name: 'mint',
|
|
392
385
|
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'token_id', type: 'u32' }],
|
|
393
|
-
code: ['Enumerable::non_sequential_mint(e, &to, token_id);'],
|
|
386
|
+
code: ['Enumerable::non_sequential_mint(e, &to, token_id);'],
|
|
387
|
+
},
|
|
388
|
+
non_sequential_mint_with_caller: {
|
|
389
|
+
name: 'mint',
|
|
390
|
+
args: [
|
|
391
|
+
getSelfArg(),
|
|
392
|
+
{ name: 'to', type: 'Address' },
|
|
393
|
+
{ name: 'token_id', type: 'u32' },
|
|
394
|
+
{ name: 'caller', type: 'Address' },
|
|
395
|
+
],
|
|
396
|
+
code: ['Enumerable::non_sequential_mint(e, &to, token_id);'],
|
|
394
397
|
},
|
|
395
398
|
sequential_mint: {
|
|
399
|
+
name: 'mint',
|
|
396
400
|
args: [getSelfArg(), { name: 'to', type: 'Address' }],
|
|
397
401
|
code: ['Enumerable::sequential_mint(e, &to);'],
|
|
398
402
|
},
|
|
403
|
+
sequential_mint_with_caller: {
|
|
404
|
+
name: 'mint',
|
|
405
|
+
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'caller', type: 'Address' }],
|
|
406
|
+
code: ['Enumerable::sequential_mint(e, &to);'],
|
|
407
|
+
},
|
|
399
408
|
});
|
|
400
409
|
|
|
401
410
|
const consecutiveFunctions = defineFunctions({
|
|
402
411
|
batch_mint: {
|
|
412
|
+
name: 'batch_mint',
|
|
403
413
|
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'amount', type: 'u32' }],
|
|
404
414
|
returns: 'u32',
|
|
405
415
|
code: ['Consecutive::batch_mint(e, &to, amount);'],
|
|
406
416
|
},
|
|
417
|
+
batch_mint_with_caller: {
|
|
418
|
+
name: 'batch_mint',
|
|
419
|
+
args: [
|
|
420
|
+
getSelfArg(),
|
|
421
|
+
{ name: 'to', type: 'Address' },
|
|
422
|
+
{ name: 'amount', type: 'u32' },
|
|
423
|
+
{ name: 'caller', type: 'Address' },
|
|
424
|
+
],
|
|
425
|
+
returns: 'u32',
|
|
426
|
+
code: ['Consecutive::batch_mint(e, &to, amount);'],
|
|
427
|
+
},
|
|
407
428
|
});
|
package/src/print.ts
CHANGED
|
@@ -23,6 +23,8 @@ export function printContract(contract: Contract): string {
|
|
|
23
23
|
[
|
|
24
24
|
`// SPDX-License-Identifier: ${contract.license}`,
|
|
25
25
|
`// Compatible with OpenZeppelin Stellar Soroban Contracts ${compatibleContractsSemver}`,
|
|
26
|
+
...(contract.documentations.length ? ['', ...printDocumentations(contract.documentations)] : []),
|
|
27
|
+
...(contract.securityContact ? ['', ...printSecurityTag(contract.securityContact)] : []),
|
|
26
28
|
...createLevelAttributes,
|
|
27
29
|
],
|
|
28
30
|
spaceBetween(
|
|
@@ -246,7 +248,7 @@ function printFunction(fn: ContractFunction): Lines[] {
|
|
|
246
248
|
}
|
|
247
249
|
}
|
|
248
250
|
|
|
249
|
-
return printFunction2(fn.pub, head, args, fn.
|
|
251
|
+
return printFunction2(fn.pub, head, args, fn.tags, fn.returns, undefined, codeLines);
|
|
250
252
|
}
|
|
251
253
|
|
|
252
254
|
function printContractFunctions(contract: Contract): Lines[] {
|
|
@@ -287,7 +289,7 @@ function printConstructor(contract: Contract): Lines[] {
|
|
|
287
289
|
true,
|
|
288
290
|
head,
|
|
289
291
|
args.map(a => printArgument(a)),
|
|
290
|
-
|
|
292
|
+
[],
|
|
291
293
|
undefined,
|
|
292
294
|
undefined,
|
|
293
295
|
body,
|
|
@@ -304,15 +306,15 @@ function printFunction2(
|
|
|
304
306
|
pub: boolean | undefined,
|
|
305
307
|
kindedName: string,
|
|
306
308
|
args: string[],
|
|
307
|
-
|
|
309
|
+
tags: string[],
|
|
308
310
|
returns: string | undefined,
|
|
309
311
|
returnLine: string | undefined,
|
|
310
312
|
code: Lines[],
|
|
311
313
|
): Lines[] {
|
|
312
314
|
const fn = [];
|
|
313
315
|
|
|
314
|
-
|
|
315
|
-
fn.push(`#[${
|
|
316
|
+
for (let i = 0; i < tags.length; i++) {
|
|
317
|
+
fn.push(`#[${tags[i]}]`);
|
|
316
318
|
}
|
|
317
319
|
|
|
318
320
|
let accum = '';
|
|
@@ -360,3 +362,11 @@ function printArgument(arg: Argument): string {
|
|
|
360
362
|
return `${arg.name}`;
|
|
361
363
|
}
|
|
362
364
|
}
|
|
365
|
+
|
|
366
|
+
function printDocumentations(documentations: string[]): string[] {
|
|
367
|
+
return documentations.map(documentation => `//! ${documentation}`);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function printSecurityTag(securityContact: string) {
|
|
371
|
+
return ['//! # Security', '//!', `//! For security issues, please contact: ${securityContact}`];
|
|
372
|
+
}
|