@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.
Files changed (93) hide show
  1. package/dist/add-pausable.d.ts.map +1 -1
  2. package/dist/add-pausable.js +9 -4
  3. package/dist/add-pausable.js.map +1 -1
  4. package/dist/add-upgradeable.d.ts.map +1 -1
  5. package/dist/add-upgradeable.js +6 -2
  6. package/dist/add-upgradeable.js.map +1 -1
  7. package/dist/api.d.ts +5 -2
  8. package/dist/api.d.ts.map +1 -1
  9. package/dist/api.js +9 -1
  10. package/dist/api.js.map +1 -1
  11. package/dist/build-generic.d.ts +5 -1
  12. package/dist/build-generic.d.ts.map +1 -1
  13. package/dist/build-generic.js +3 -0
  14. package/dist/build-generic.js.map +1 -1
  15. package/dist/contract.d.ts +7 -1
  16. package/dist/contract.d.ts.map +1 -1
  17. package/dist/contract.js +17 -1
  18. package/dist/contract.js.map +1 -1
  19. package/dist/fungible.d.ts +5 -2
  20. package/dist/fungible.d.ts.map +1 -1
  21. package/dist/fungible.js +80 -50
  22. package/dist/fungible.js.map +1 -1
  23. package/dist/generate/sources.d.ts.map +1 -1
  24. package/dist/generate/sources.js +6 -0
  25. package/dist/generate/sources.js.map +1 -1
  26. package/dist/generate/stablecoin.d.ts +3 -0
  27. package/dist/generate/stablecoin.d.ts.map +1 -0
  28. package/dist/generate/stablecoin.js +24 -0
  29. package/dist/generate/stablecoin.js.map +1 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +3 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/kind.js +1 -0
  35. package/dist/kind.js.map +1 -1
  36. package/dist/non-fungible.d.ts +1 -0
  37. package/dist/non-fungible.d.ts.map +1 -1
  38. package/dist/non-fungible.js +91 -71
  39. package/dist/non-fungible.js.map +1 -1
  40. package/dist/print.d.ts.map +1 -1
  41. package/dist/print.js +13 -5
  42. package/dist/print.js.map +1 -1
  43. package/dist/set-access-control.d.ts +7 -4
  44. package/dist/set-access-control.d.ts.map +1 -1
  45. package/dist/set-access-control.js +57 -15
  46. package/dist/set-access-control.js.map +1 -1
  47. package/dist/set-info.d.ts +2 -0
  48. package/dist/set-info.d.ts.map +1 -1
  49. package/dist/set-info.js +6 -2
  50. package/dist/set-info.js.map +1 -1
  51. package/dist/stablecoin.d.ts +11 -0
  52. package/dist/stablecoin.d.ts.map +1 -0
  53. package/dist/stablecoin.js +103 -0
  54. package/dist/stablecoin.js.map +1 -0
  55. package/dist/utils/define-functions.d.ts +4 -2
  56. package/dist/utils/define-functions.d.ts.map +1 -1
  57. package/dist/utils/define-functions.js +7 -1
  58. package/dist/utils/define-functions.js.map +1 -1
  59. package/dist/utils/version.d.ts +3 -3
  60. package/dist/utils/version.js +2 -2
  61. package/dist/zip-rust.d.ts +5 -0
  62. package/dist/zip-rust.d.ts.map +1 -0
  63. package/dist/zip-rust.js +49 -0
  64. package/dist/zip-rust.js.map +1 -0
  65. package/dist/zip-scaffold.d.ts +0 -3
  66. package/dist/zip-scaffold.d.ts.map +1 -1
  67. package/dist/zip-scaffold.js +9 -85
  68. package/dist/zip-scaffold.js.map +1 -1
  69. package/dist/zip-shared.d.ts +26 -0
  70. package/dist/zip-shared.d.ts.map +1 -0
  71. package/dist/zip-shared.js +79 -0
  72. package/dist/zip-shared.js.map +1 -0
  73. package/package.json +1 -1
  74. package/src/add-pausable.ts +9 -4
  75. package/src/add-upgradeable.ts +6 -2
  76. package/src/api.ts +27 -4
  77. package/src/build-generic.ts +6 -0
  78. package/src/contract.ts +22 -2
  79. package/src/fungible.ts +84 -56
  80. package/src/generate/sources.ts +7 -0
  81. package/src/generate/stablecoin.ts +23 -0
  82. package/src/index.ts +2 -0
  83. package/src/kind.ts +1 -0
  84. package/src/non-fungible.ts +98 -77
  85. package/src/print.ts +15 -5
  86. package/src/set-access-control.ts +72 -19
  87. package/src/set-info.ts +8 -1
  88. package/src/stablecoin.ts +124 -0
  89. package/src/utils/define-functions.ts +11 -4
  90. package/src/utils/version.ts +2 -2
  91. package/src/zip-rust.ts +57 -0
  92. package/src/zip-scaffold.ts +16 -91
  93. 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, // TODO: Determine whether Access Control options should be visible in the UI before they are implemented as modules
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 buildFungible(opts: FungibleOptions): Contract {
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', 'self', { alias: '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.addTraitFunction(fungibleTokenTrait, functions.total_supply);
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(`fungible::mintable::mint(e, &recipient, ${premintAbsolute});`);
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
- function addMintable(c: ContractBuilder, access: Access, pausable: boolean) {
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: ['fungible::total_supply(e)'],
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: ['fungible::balance(e, &account)'],
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: ['fungible::allowance(e, &owner, &spender)'],
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: ['fungible::transfer(e, &from, &to, amount)'],
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: ['fungible::transfer_from(e, &spender, &from, &to, amount)'],
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: ['fungible::approve(e, &owner, &spender, amount, live_until_ledger)'],
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: ['fungible::metadata::decimals(e)'],
295
+ code: ['Self::ContractType::decimals(e)'],
278
296
  },
279
297
  name: {
280
298
  args: [getSelfArg()],
281
299
  returns: 'String',
282
- code: ['fungible::metadata::name(e)'],
300
+ code: ['Self::ContractType::name(e)'],
283
301
  },
284
302
  symbol: {
285
303
  args: [getSelfArg()],
286
304
  returns: 'String',
287
- code: ['fungible::metadata::symbol(e)'],
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: ['fungible::burnable::burn(e, &from, amount)'],
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: ['fungible::burnable::burn_from(e, &spender, &from, amount)'],
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: ['fungible::mintable::mint(e, &account, amount);'],
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
  });
@@ -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
@@ -16,6 +16,7 @@ function isKind<T>(value: Kind | T): value is Kind {
16
16
  switch (value) {
17
17
  case 'Fungible':
18
18
  case 'NonFungible':
19
+ case 'Stablecoin':
19
20
  return true;
20
21
 
21
22
  default: {
@@ -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
- `Base::set_metadata(e, String::from_str(e, "www.mytoken.com"), String::from_str(e, "${name}"), String::from_str(e, "${symbol}"));`,
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
- // all the below may be eliminated by introducing `defaultimpl` macro at `tags` above,
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
- c.addFreeFunction(consecutiveFunctions.batch_mint);
214
+ const mintFn = access === 'ownable' ? consecutiveFunctions.batch_mint : consecutiveFunctions.batch_mint_with_caller;
215
+ c.addFreeFunction(mintFn);
226
216
  if (pausable) {
227
- c.addFunctionTag(consecutiveFunctions.batch_mint, 'when_not_paused');
217
+ c.addFunctionTag(mintFn, 'when_not_paused');
228
218
  }
229
219
 
230
- requireAccessControl(c, undefined, consecutiveFunctions.batch_mint, access);
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
- if (!enumerable) {
228
+ const accessProps = { useMacro: true, role: 'minter', caller: 'caller' };
229
+
230
+ let mintFn;
231
+
232
+ if (enumerable) {
235
233
  if (sequential) {
236
- c.addUseClause('stellar_non_fungible', 'Base::sequential_mint');
237
- c.addFreeFunction(baseFunctions.sequential_mint);
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
- c.addUseClause('stellar_non_fungible', 'Base::mint');
244
- c.addFreeFunction(baseFunctions.mint);
245
- requireAccessControl(c, undefined, baseFunctions.mint, access);
246
- if (pausable) {
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
- c.addFreeFunction(enumerableFunctions.sequential_mint);
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
- c.addFreeFunction(enumerableFunctions.non_sequential_mint);
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);'], // TODO: unify `mint` name in Stellar-Contracts across extensions
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.tag, fn.returns, undefined, codeLines);
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
- undefined,
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
- tag: string | undefined,
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
- if (tag !== undefined) {
315
- fn.push(`#[${tag}]`);
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
+ }