@openzeppelin/wizard-stellar 0.1.1 → 0.2.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/README.md +1 -0
- package/dist/add-pausable.js +7 -7
- package/dist/add-pausable.js.map +1 -1
- package/dist/add-upgradeable.d.ts +4 -0
- package/dist/add-upgradeable.d.ts.map +1 -0
- package/dist/add-upgradeable.js +26 -0
- package/dist/add-upgradeable.js.map +1 -0
- package/dist/api.d.ts +3 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +6 -1
- package/dist/api.js.map +1 -1
- package/dist/build-generic.d.ts +4 -0
- package/dist/build-generic.d.ts.map +1 -1
- package/dist/build-generic.js +5 -2
- package/dist/build-generic.js.map +1 -1
- package/dist/contract.d.ts +22 -11
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +58 -12
- package/dist/contract.js.map +1 -1
- package/dist/fungible.d.ts +1 -0
- package/dist/fungible.d.ts.map +1 -1
- package/dist/fungible.js +38 -32
- package/dist/fungible.js.map +1 -1
- package/dist/generate/fungible.d.ts.map +1 -1
- package/dist/generate/fungible.js +1 -0
- package/dist/generate/fungible.js.map +1 -1
- package/dist/generate/non-fungible.d.ts +3 -0
- package/dist/generate/non-fungible.d.ts.map +1 -0
- package/dist/generate/non-fungible.js +24 -0
- package/dist/generate/non-fungible.js.map +1 -0
- 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/index.d.ts +1 -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 +2 -1
- package/dist/kind.js.map +1 -1
- package/dist/non-fungible.d.ts +17 -0
- package/dist/non-fungible.d.ts.map +1 -0
- package/dist/non-fungible.js +356 -0
- package/dist/non-fungible.js.map +1 -0
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +53 -17
- package/dist/print.js.map +1 -1
- package/dist/set-access-control.d.ts +2 -2
- package/dist/set-access-control.d.ts.map +1 -1
- package/dist/set-access-control.js +2 -7
- package/dist/set-access-control.js.map +1 -1
- package/dist/test.js +3 -0
- package/dist/test.js.map +1 -1
- package/dist/utils/version.d.ts +3 -3
- package/dist/utils/version.js +2 -2
- package/package.json +3 -4
- package/src/add-pausable.ts +7 -7
- package/src/add-upgradeable.ts +30 -0
- package/src/api.ts +8 -0
- package/src/build-generic.ts +9 -2
- package/src/contract.ts +73 -21
- package/src/fungible.ts +38 -30
- package/src/generate/fungible.ts +1 -0
- package/src/generate/non-fungible.ts +24 -0
- package/src/generate/sources.ts +7 -0
- package/src/index.ts +1 -0
- package/src/kind.ts +2 -1
- package/src/non-fungible.ts +410 -0
- package/src/print.ts +77 -28
- package/src/set-access-control.ts +8 -9
- package/src/test.ts +4 -0
- package/src/utils/version.ts +2 -2
package/src/fungible.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { ContractBuilder } from './contract';
|
|
|
3
3
|
import type { Access } from './set-access-control';
|
|
4
4
|
import { requireAccessControl, setAccessControl } from './set-access-control';
|
|
5
5
|
import { addPausable } from './add-pausable';
|
|
6
|
+
import { addUpgradeable } from './add-upgradeable';
|
|
6
7
|
import { defineFunctions } from './utils/define-functions';
|
|
7
8
|
import type { CommonContractOptions } from './common-options';
|
|
8
9
|
import { withCommonContractDefaults, getSelfArg } from './common-options';
|
|
@@ -17,6 +18,7 @@ export const defaults: Required<FungibleOptions> = {
|
|
|
17
18
|
symbol: 'MTK',
|
|
18
19
|
burnable: false,
|
|
19
20
|
pausable: false,
|
|
21
|
+
upgradeable: false,
|
|
20
22
|
premint: '0',
|
|
21
23
|
mintable: false,
|
|
22
24
|
access: commonDefaults.access, // TODO: Determine whether Access Control options should be visible in the UI before they are implemented as modules
|
|
@@ -32,6 +34,7 @@ export interface FungibleOptions extends CommonContractOptions {
|
|
|
32
34
|
symbol: string;
|
|
33
35
|
burnable?: boolean;
|
|
34
36
|
pausable?: boolean;
|
|
37
|
+
upgradeable?: boolean;
|
|
35
38
|
premint?: string;
|
|
36
39
|
mintable?: boolean;
|
|
37
40
|
}
|
|
@@ -42,6 +45,7 @@ function withDefaults(opts: FungibleOptions): Required<FungibleOptions> {
|
|
|
42
45
|
...withCommonContractDefaults(opts),
|
|
43
46
|
burnable: opts.burnable ?? defaults.burnable,
|
|
44
47
|
pausable: opts.pausable ?? defaults.pausable,
|
|
48
|
+
upgradeable: opts.upgradeable ?? defaults.upgradeable,
|
|
45
49
|
premint: opts.premint || defaults.premint,
|
|
46
50
|
mintable: opts.mintable ?? defaults.mintable,
|
|
47
51
|
};
|
|
@@ -62,6 +66,10 @@ export function buildFungible(opts: FungibleOptions): Contract {
|
|
|
62
66
|
addPausable(c, allOpts.access);
|
|
63
67
|
}
|
|
64
68
|
|
|
69
|
+
if (allOpts.upgradeable) {
|
|
70
|
+
addUpgradeable(c, allOpts.access);
|
|
71
|
+
}
|
|
72
|
+
|
|
65
73
|
if (allOpts.burnable) {
|
|
66
74
|
addBurnable(c, allOpts.pausable);
|
|
67
75
|
}
|
|
@@ -83,8 +91,8 @@ function addBase(c: ContractBuilder, name: string, symbol: string, pausable: boo
|
|
|
83
91
|
);
|
|
84
92
|
|
|
85
93
|
// Set token functions
|
|
86
|
-
c.addUseClause('
|
|
87
|
-
c.addUseClause('
|
|
94
|
+
c.addUseClause('stellar_fungible', 'self', { alias: 'fungible' });
|
|
95
|
+
c.addUseClause('stellar_fungible', 'FungibleToken');
|
|
88
96
|
c.addUseClause('soroban_sdk', 'contract');
|
|
89
97
|
c.addUseClause('soroban_sdk', 'contractimpl');
|
|
90
98
|
c.addUseClause('soroban_sdk', 'Address');
|
|
@@ -93,46 +101,46 @@ function addBase(c: ContractBuilder, name: string, symbol: string, pausable: boo
|
|
|
93
101
|
c.addUseClause('soroban_sdk', 'Symbol');
|
|
94
102
|
|
|
95
103
|
const fungibleTokenTrait = {
|
|
96
|
-
|
|
97
|
-
|
|
104
|
+
traitName: 'FungibleToken',
|
|
105
|
+
structName: c.name,
|
|
98
106
|
tags: ['contractimpl'],
|
|
99
107
|
};
|
|
100
108
|
|
|
101
|
-
c.
|
|
102
|
-
c.
|
|
103
|
-
c.
|
|
104
|
-
c.
|
|
105
|
-
c.
|
|
106
|
-
c.
|
|
107
|
-
c.
|
|
108
|
-
c.
|
|
109
|
-
c.
|
|
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);
|
|
110
118
|
|
|
111
119
|
if (pausable) {
|
|
112
|
-
c.addUseClause('
|
|
113
|
-
c.addFunctionTag(
|
|
114
|
-
c.addFunctionTag(
|
|
120
|
+
c.addUseClause('stellar_pausable_macros', 'when_not_paused');
|
|
121
|
+
c.addFunctionTag(functions.transfer, 'when_not_paused', fungibleTokenTrait);
|
|
122
|
+
c.addFunctionTag(functions.transfer_from, 'when_not_paused', fungibleTokenTrait);
|
|
115
123
|
}
|
|
116
124
|
}
|
|
117
125
|
|
|
118
126
|
function addBurnable(c: ContractBuilder, pausable: boolean) {
|
|
119
|
-
c.addUseClause('
|
|
127
|
+
c.addUseClause('stellar_fungible', 'burnable::FungibleBurnable');
|
|
120
128
|
c.addUseClause('soroban_sdk', 'Address');
|
|
121
129
|
|
|
122
130
|
const fungibleBurnableTrait = {
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
traitName: 'FungibleBurnable',
|
|
132
|
+
structName: c.name,
|
|
125
133
|
tags: ['contractimpl'],
|
|
126
134
|
section: 'Extensions',
|
|
127
135
|
};
|
|
128
136
|
|
|
129
|
-
c.
|
|
130
|
-
c.
|
|
137
|
+
c.addTraitFunction(fungibleBurnableTrait, functions.burn);
|
|
138
|
+
c.addTraitFunction(fungibleBurnableTrait, functions.burn_from);
|
|
131
139
|
|
|
132
140
|
if (pausable) {
|
|
133
|
-
c.addUseClause('
|
|
134
|
-
c.addFunctionTag(
|
|
135
|
-
c.addFunctionTag(
|
|
141
|
+
c.addUseClause('stellar_pausable_macros', 'when_not_paused');
|
|
142
|
+
c.addFunctionTag(functions.burn, 'when_not_paused', fungibleBurnableTrait);
|
|
143
|
+
c.addFunctionTag(functions.burn_from, 'when_not_paused', fungibleBurnableTrait);
|
|
136
144
|
}
|
|
137
145
|
}
|
|
138
146
|
|
|
@@ -149,7 +157,7 @@ function addPremint(c: ContractBuilder, amount: string) {
|
|
|
149
157
|
// TODO: handle signed int?
|
|
150
158
|
const premintAbsolute = toUint(getInitialSupply(amount, 18), 'premint', 'u128');
|
|
151
159
|
|
|
152
|
-
c.addUseClause('
|
|
160
|
+
c.addUseClause('stellar_fungible', 'mintable::FungibleMintable');
|
|
153
161
|
c.addUseClause('soroban_sdk', 'Address');
|
|
154
162
|
|
|
155
163
|
c.addConstructorArgument({ name: 'recipient', type: 'Address' });
|
|
@@ -199,21 +207,21 @@ export function getInitialSupply(premint: string, decimals: number): string {
|
|
|
199
207
|
}
|
|
200
208
|
|
|
201
209
|
function addMintable(c: ContractBuilder, access: Access, pausable: boolean) {
|
|
202
|
-
c.addUseClause('
|
|
210
|
+
c.addUseClause('stellar_fungible', 'mintable::FungibleMintable');
|
|
203
211
|
|
|
204
212
|
const fungibleMintableTrait = {
|
|
205
|
-
|
|
206
|
-
|
|
213
|
+
traitName: 'FungibleMintable',
|
|
214
|
+
structName: c.name,
|
|
207
215
|
tags: ['contractimpl'],
|
|
208
216
|
section: 'Extensions',
|
|
209
217
|
};
|
|
210
218
|
|
|
211
|
-
c.
|
|
219
|
+
c.addTraitFunction(fungibleMintableTrait, functions.mint);
|
|
212
220
|
|
|
213
221
|
requireAccessControl(c, fungibleMintableTrait, functions.mint, access);
|
|
214
222
|
|
|
215
223
|
if (pausable) {
|
|
216
|
-
c.addFunctionTag(
|
|
224
|
+
c.addFunctionTag(functions.mint, 'when_not_paused', fungibleMintableTrait);
|
|
217
225
|
}
|
|
218
226
|
}
|
|
219
227
|
|
package/src/generate/fungible.ts
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { NonFungibleOptions } from '../non-fungible';
|
|
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: ['MyToken'],
|
|
10
|
+
symbol: ['MTK'],
|
|
11
|
+
burnable: booleans,
|
|
12
|
+
pausable: booleans,
|
|
13
|
+
upgradeable: booleans,
|
|
14
|
+
enumerable: booleans,
|
|
15
|
+
consecutive: booleans,
|
|
16
|
+
sequential: booleans,
|
|
17
|
+
mintable: booleans,
|
|
18
|
+
access: accessOptions,
|
|
19
|
+
info: infoOptions,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function* generateNonFungibleOptions(): Generator<Required<NonFungibleOptions>> {
|
|
23
|
+
yield* generateAlternatives(blueprint);
|
|
24
|
+
}
|
package/src/generate/sources.ts
CHANGED
|
@@ -3,6 +3,7 @@ import path from 'path';
|
|
|
3
3
|
import crypto from 'crypto';
|
|
4
4
|
|
|
5
5
|
import { generateFungibleOptions } from './fungible';
|
|
6
|
+
import { generateNonFungibleOptions } from './non-fungible';
|
|
6
7
|
import type { GenericOptions, KindedOptions } from '../build-generic';
|
|
7
8
|
import { buildGeneric } from '../build-generic';
|
|
8
9
|
import { printContract } from '../print';
|
|
@@ -17,6 +18,12 @@ export function* generateOptions(kind?: Kind): Generator<GenericOptions> {
|
|
|
17
18
|
yield { kind: 'Fungible', ...kindOpts };
|
|
18
19
|
}
|
|
19
20
|
}
|
|
21
|
+
|
|
22
|
+
if (!kind || kind === 'NonFungible') {
|
|
23
|
+
for (const kindOpts of generateNonFungibleOptions()) {
|
|
24
|
+
yield { kind: 'NonFungible', ...kindOpts };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
20
27
|
}
|
|
21
28
|
|
|
22
29
|
interface GeneratedContract {
|
package/src/index.ts
CHANGED
package/src/kind.ts
CHANGED
|
@@ -4,7 +4,7 @@ export type Kind = GenericOptions['kind'];
|
|
|
4
4
|
|
|
5
5
|
export function sanitizeKind(kind: unknown): Kind {
|
|
6
6
|
if (typeof kind === 'string') {
|
|
7
|
-
const sanitized = kind.replace(/^(ERC|.)/i, c => c.toUpperCase());
|
|
7
|
+
const sanitized = kind.replace(/^(ERC|.)/i, c => c.toUpperCase()).replace(/^(NonFungible)$/i, 'NonFungible');
|
|
8
8
|
if (isKind(sanitized)) {
|
|
9
9
|
return sanitized;
|
|
10
10
|
}
|
|
@@ -15,6 +15,7 @@ export function sanitizeKind(kind: unknown): Kind {
|
|
|
15
15
|
function isKind<T>(value: Kind | T): value is Kind {
|
|
16
16
|
switch (value) {
|
|
17
17
|
case 'Fungible':
|
|
18
|
+
case 'NonFungible':
|
|
18
19
|
return true;
|
|
19
20
|
|
|
20
21
|
default: {
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import type { Contract } from './contract';
|
|
2
|
+
import { ContractBuilder } from './contract';
|
|
3
|
+
import { type Access, requireAccessControl, setAccessControl } from './set-access-control';
|
|
4
|
+
import { addPausable } from './add-pausable';
|
|
5
|
+
import { addUpgradeable } from './add-upgradeable';
|
|
6
|
+
import { defineFunctions } from './utils/define-functions';
|
|
7
|
+
import type { CommonContractOptions } from './common-options';
|
|
8
|
+
import { withCommonContractDefaults, getSelfArg } from './common-options';
|
|
9
|
+
import { setInfo } from './set-info';
|
|
10
|
+
import type { OptionsErrorMessages } from './error';
|
|
11
|
+
import { OptionsError } from './error';
|
|
12
|
+
import { contractDefaults as commonDefaults } from './common-options';
|
|
13
|
+
import { printContract } from './print';
|
|
14
|
+
import { toByteArray } from './utils/convert-strings';
|
|
15
|
+
|
|
16
|
+
export const defaults: Required<NonFungibleOptions> = {
|
|
17
|
+
name: 'MyToken',
|
|
18
|
+
symbol: 'MTK',
|
|
19
|
+
burnable: false,
|
|
20
|
+
enumerable: false,
|
|
21
|
+
consecutive: false,
|
|
22
|
+
pausable: false,
|
|
23
|
+
upgradeable: false,
|
|
24
|
+
mintable: false,
|
|
25
|
+
sequential: false,
|
|
26
|
+
access: commonDefaults.access, // TODO: Determine whether Access Control options should be visible in the UI before they are implemented as modules
|
|
27
|
+
info: commonDefaults.info,
|
|
28
|
+
} as const;
|
|
29
|
+
|
|
30
|
+
export function printNonFungible(opts: NonFungibleOptions = defaults): string {
|
|
31
|
+
return printContract(buildNonFungible(opts));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface NonFungibleOptions extends CommonContractOptions {
|
|
35
|
+
name: string;
|
|
36
|
+
symbol: string;
|
|
37
|
+
burnable?: boolean;
|
|
38
|
+
enumerable?: boolean;
|
|
39
|
+
consecutive?: boolean;
|
|
40
|
+
pausable?: boolean;
|
|
41
|
+
upgradeable?: boolean;
|
|
42
|
+
mintable?: boolean;
|
|
43
|
+
sequential?: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function withDefaults(opts: NonFungibleOptions): Required<NonFungibleOptions> {
|
|
47
|
+
return {
|
|
48
|
+
...opts,
|
|
49
|
+
...withCommonContractDefaults(opts),
|
|
50
|
+
burnable: opts.burnable ?? defaults.burnable,
|
|
51
|
+
consecutive: opts.consecutive ?? defaults.consecutive,
|
|
52
|
+
enumerable: opts.enumerable ?? defaults.enumerable,
|
|
53
|
+
pausable: opts.pausable ?? defaults.pausable,
|
|
54
|
+
upgradeable: opts.upgradeable ?? defaults.upgradeable,
|
|
55
|
+
mintable: opts.mintable ?? defaults.mintable,
|
|
56
|
+
sequential: opts.sequential ?? defaults.sequential,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function buildNonFungible(opts: NonFungibleOptions): Contract {
|
|
61
|
+
const c = new ContractBuilder(opts.name);
|
|
62
|
+
|
|
63
|
+
const allOpts = withDefaults(opts);
|
|
64
|
+
|
|
65
|
+
const errors: OptionsErrorMessages = {};
|
|
66
|
+
|
|
67
|
+
if (allOpts.enumerable && allOpts.consecutive) {
|
|
68
|
+
errors.enumerable = 'Enumerable cannot be used with Consecutive extension';
|
|
69
|
+
errors.consecutive = 'Consecutive cannot be used with Enumerable extension';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (allOpts.consecutive && allOpts.mintable) {
|
|
73
|
+
errors.consecutive = 'Consecutive cannot be used with Mintable extension';
|
|
74
|
+
errors.mintable = 'Mintable cannot be used with Consecutive extension';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (allOpts.consecutive && allOpts.sequential) {
|
|
78
|
+
errors.consecutive = 'Consecutive cannot be used with Sequential minting';
|
|
79
|
+
errors.sequential = 'Sequential minting cannot be used with Consecutive extension';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (Object.keys(errors).length > 0) {
|
|
83
|
+
throw new OptionsError(errors);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
addBase(c, toByteArray(allOpts.name), toByteArray(allOpts.symbol), allOpts.pausable);
|
|
87
|
+
|
|
88
|
+
if (allOpts.pausable) {
|
|
89
|
+
addPausable(c, allOpts.access);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (allOpts.upgradeable) {
|
|
93
|
+
addUpgradeable(c, allOpts.access);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (allOpts.burnable) {
|
|
97
|
+
addBurnable(c, allOpts.pausable);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (allOpts.enumerable) {
|
|
101
|
+
addEnumerable(c, allOpts.burnable);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (allOpts.consecutive) {
|
|
105
|
+
addConsecutive(c, allOpts.pausable, allOpts.access);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (allOpts.mintable) {
|
|
109
|
+
addMintable(c, allOpts.enumerable, allOpts.pausable, allOpts.sequential, allOpts.access);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
setAccessControl(c, allOpts.access);
|
|
113
|
+
setInfo(c, allOpts.info);
|
|
114
|
+
|
|
115
|
+
return c;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function addBase(c: ContractBuilder, name: string, symbol: string, pausable: boolean) {
|
|
119
|
+
// 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
|
+
);
|
|
123
|
+
|
|
124
|
+
// Set token functions
|
|
125
|
+
c.addUseClause('stellar_non_fungible', 'Base');
|
|
126
|
+
c.addUseClause('stellar_non_fungible', 'NonFungibleToken');
|
|
127
|
+
c.addUseClause('soroban_sdk', 'contract');
|
|
128
|
+
c.addUseClause('soroban_sdk', 'contractimpl');
|
|
129
|
+
c.addUseClause('soroban_sdk', 'Address');
|
|
130
|
+
c.addUseClause('soroban_sdk', 'String');
|
|
131
|
+
c.addUseClause('soroban_sdk', 'Env');
|
|
132
|
+
|
|
133
|
+
const nonFungibleTokenTrait = {
|
|
134
|
+
traitName: 'NonFungibleToken',
|
|
135
|
+
structName: c.name,
|
|
136
|
+
tags: ['contractimpl'],
|
|
137
|
+
assocType: 'type ContractType = Base;',
|
|
138
|
+
};
|
|
139
|
+
|
|
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);
|
|
153
|
+
|
|
154
|
+
if (pausable) {
|
|
155
|
+
c.addUseClause('stellar_pausable_macros', 'when_not_paused');
|
|
156
|
+
c.addFunctionTag(baseFunctions.transfer, 'when_not_paused', nonFungibleTokenTrait);
|
|
157
|
+
c.addFunctionTag(baseFunctions.transfer_from, 'when_not_paused', nonFungibleTokenTrait);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function addBurnable(c: ContractBuilder, pausable: boolean) {
|
|
162
|
+
c.addUseClause('stellar_non_fungible', 'burnable::NonFungibleBurnable');
|
|
163
|
+
c.addUseClause('soroban_sdk', 'Address');
|
|
164
|
+
|
|
165
|
+
const nonFungibleBurnableTrait = {
|
|
166
|
+
traitName: 'NonFungibleBurnable',
|
|
167
|
+
structName: c.name,
|
|
168
|
+
tags: ['contractimpl'],
|
|
169
|
+
section: 'Extensions',
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
c.addTraitFunction(nonFungibleBurnableTrait, burnableFunctions.burn);
|
|
173
|
+
c.addTraitFunction(nonFungibleBurnableTrait, burnableFunctions.burn_from);
|
|
174
|
+
|
|
175
|
+
if (pausable) {
|
|
176
|
+
c.addUseClause('stellar_pausable_macros', 'when_not_paused');
|
|
177
|
+
c.addFunctionTag(burnableFunctions.burn, 'when_not_paused', nonFungibleBurnableTrait);
|
|
178
|
+
c.addFunctionTag(burnableFunctions.burn_from, 'when_not_paused', nonFungibleBurnableTrait);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function addEnumerable(c: ContractBuilder, burnable: boolean) {
|
|
183
|
+
c.addUseClause('stellar_non_fungible', 'enumerable::{NonFungibleEnumerable, Enumerable}');
|
|
184
|
+
//c.addUseClause('stellar_default_impl_macro', 'default_impl');
|
|
185
|
+
|
|
186
|
+
const nonFungibleEnumerableTrait = {
|
|
187
|
+
traitName: 'NonFungibleEnumerable',
|
|
188
|
+
structName: c.name,
|
|
189
|
+
tags: ['defaultimpl', 'contractimpl'],
|
|
190
|
+
section: 'Extensions',
|
|
191
|
+
};
|
|
192
|
+
c.addTraitImplBlock(nonFungibleEnumerableTrait);
|
|
193
|
+
|
|
194
|
+
c.overrideAssocType('NonFungibleToken', 'type ContractType = Enumerable;');
|
|
195
|
+
|
|
196
|
+
if (burnable) {
|
|
197
|
+
c.overrideAssocType('NonFungibleBurnable', 'type ContractType = Enumerable;');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Below is not required due to `defaultimpl` macro. If we require to customize the functions,
|
|
201
|
+
// then we should:
|
|
202
|
+
// 1. get rid of the `defaultimpl` macro form `tags` above,
|
|
203
|
+
// 2. get rid of `c.addImplementedTrait(nonFungibleEnumerableTrait);` line,
|
|
204
|
+
// 3. uncomment the section below:
|
|
205
|
+
// 4. uncomment `get_owner_token_id` and `get_token_id` from `enumerableFunctions` definition
|
|
206
|
+
/*
|
|
207
|
+
c.addFunction(nonFungibleEnumerableTrait, enumerableFunctions.total_supply);
|
|
208
|
+
c.addFunction(nonFungibleEnumerableTrait, enumerableFunctions.get_owner_token_id);
|
|
209
|
+
c.addFunction(nonFungibleEnumerableTrait, enumerableFunctions.get_token_id);
|
|
210
|
+
*/
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function addConsecutive(c: ContractBuilder, pausable: boolean, access: Access) {
|
|
214
|
+
c.addUseClause('stellar_non_fungible', 'consecutive::{NonFungibleConsecutive, Consecutive}');
|
|
215
|
+
c.addUseClause('stellar_non_fungible', 'ContractOverrides');
|
|
216
|
+
|
|
217
|
+
const nonFungibleConsecutiveTrait = {
|
|
218
|
+
traitName: 'NonFungibleConsecutive',
|
|
219
|
+
structName: c.name,
|
|
220
|
+
tags: ['contractimpl'],
|
|
221
|
+
section: 'Extensions',
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
c.addTraitImplBlock(nonFungibleConsecutiveTrait);
|
|
225
|
+
|
|
226
|
+
c.overrideAssocType('NonFungibleToken', 'type ContractType = Consecutive;');
|
|
227
|
+
|
|
228
|
+
c.addFreeFunction(consecutiveFunctions.batch_mint);
|
|
229
|
+
if (pausable) {
|
|
230
|
+
c.addFunctionTag(consecutiveFunctions.batch_mint, 'when_not_paused');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
requireAccessControl(c, undefined, consecutiveFunctions.batch_mint, access);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function addMintable(c: ContractBuilder, enumerable: boolean, pausable: boolean, sequential: boolean, access: Access) {
|
|
237
|
+
if (!enumerable) {
|
|
238
|
+
if (sequential) {
|
|
239
|
+
c.addUseClause('stellar_non_fungible', 'Base::sequential_mint');
|
|
240
|
+
c.addFreeFunction(baseFunctions.sequential_mint);
|
|
241
|
+
requireAccessControl(c, undefined, baseFunctions.sequential_mint, access);
|
|
242
|
+
if (pausable) {
|
|
243
|
+
c.addFunctionTag(baseFunctions.sequential_mint, 'when_not_paused');
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
c.addUseClause('stellar_non_fungible', 'Base::mint');
|
|
247
|
+
c.addFreeFunction(baseFunctions.mint);
|
|
248
|
+
requireAccessControl(c, undefined, baseFunctions.mint, access);
|
|
249
|
+
if (pausable) {
|
|
250
|
+
c.addFunctionTag(baseFunctions.mint, 'when_not_paused');
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (enumerable) {
|
|
256
|
+
if (sequential) {
|
|
257
|
+
c.addFreeFunction(enumerableFunctions.sequential_mint);
|
|
258
|
+
requireAccessControl(c, undefined, enumerableFunctions.sequential_mint, access);
|
|
259
|
+
if (pausable) {
|
|
260
|
+
c.addFunctionTag(enumerableFunctions.sequential_mint, 'when_not_paused');
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
c.addFreeFunction(enumerableFunctions.non_sequential_mint);
|
|
264
|
+
requireAccessControl(c, undefined, enumerableFunctions.non_sequential_mint, access);
|
|
265
|
+
if (pausable) {
|
|
266
|
+
c.addFunctionTag(enumerableFunctions.non_sequential_mint, 'when_not_paused');
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const baseFunctions = defineFunctions({
|
|
273
|
+
// NonFungible Trait
|
|
274
|
+
balance: {
|
|
275
|
+
args: [getSelfArg(), { name: 'owner', type: 'Address' }],
|
|
276
|
+
returns: 'u32',
|
|
277
|
+
code: ['Self::ContractType::balance(e, &owner)'],
|
|
278
|
+
},
|
|
279
|
+
owner_of: {
|
|
280
|
+
args: [getSelfArg(), { name: 'token_id', type: 'u32' }],
|
|
281
|
+
returns: 'Address',
|
|
282
|
+
code: ['Self::ContractType::owner_of(e, token_id)'],
|
|
283
|
+
},
|
|
284
|
+
transfer: {
|
|
285
|
+
args: [
|
|
286
|
+
getSelfArg(),
|
|
287
|
+
{ name: 'from', type: 'Address' },
|
|
288
|
+
{ name: 'to', type: 'Address' },
|
|
289
|
+
{ name: 'token_id', type: 'u32' },
|
|
290
|
+
],
|
|
291
|
+
code: ['Self::ContractType::transfer(e, &from, &to, token_id);'],
|
|
292
|
+
},
|
|
293
|
+
transfer_from: {
|
|
294
|
+
args: [
|
|
295
|
+
getSelfArg(),
|
|
296
|
+
{ name: 'spender', type: 'Address' },
|
|
297
|
+
{ name: 'from', type: 'Address' },
|
|
298
|
+
{ name: 'to', type: 'Address' },
|
|
299
|
+
{ name: 'token_id', type: 'u32' },
|
|
300
|
+
],
|
|
301
|
+
code: ['Self::ContractType::transfer_from(e, &spender, &from, &to, token_id);'],
|
|
302
|
+
},
|
|
303
|
+
approve: {
|
|
304
|
+
args: [
|
|
305
|
+
getSelfArg(),
|
|
306
|
+
{ name: 'approver', type: 'Address' },
|
|
307
|
+
{ name: 'approved', type: 'Address' },
|
|
308
|
+
{ name: 'token_id', type: 'u32' },
|
|
309
|
+
{ name: 'live_until_ledger', type: 'u32' },
|
|
310
|
+
],
|
|
311
|
+
code: ['Self::ContractType::approve(e, &approver, &approved, token_id, live_until_ledger)'],
|
|
312
|
+
},
|
|
313
|
+
approve_for_all: {
|
|
314
|
+
args: [
|
|
315
|
+
getSelfArg(),
|
|
316
|
+
{ name: 'owner', type: 'Address' },
|
|
317
|
+
{ name: 'operator', type: 'Address' },
|
|
318
|
+
{ name: 'live_until_ledger', type: 'u32' },
|
|
319
|
+
],
|
|
320
|
+
code: ['Self::ContractType::approve_for_all(e, &owner, &operator, live_until_ledger)'],
|
|
321
|
+
},
|
|
322
|
+
get_approved: {
|
|
323
|
+
args: [getSelfArg(), { name: 'token_id', type: 'u32' }],
|
|
324
|
+
returns: 'Option<Address>',
|
|
325
|
+
code: ['Self::ContractType::get_approved(e, token_id)'],
|
|
326
|
+
},
|
|
327
|
+
is_approved_for_all: {
|
|
328
|
+
args: [getSelfArg(), { name: 'owner', type: 'Address' }, { name: 'operator', type: 'Address' }],
|
|
329
|
+
returns: 'bool',
|
|
330
|
+
code: ['Self::ContractType::is_approved_for_all(e, &owner, &operator)'],
|
|
331
|
+
},
|
|
332
|
+
name: {
|
|
333
|
+
args: [getSelfArg()],
|
|
334
|
+
returns: 'String',
|
|
335
|
+
code: ['Self::ContractType::name(e)'],
|
|
336
|
+
},
|
|
337
|
+
symbol: {
|
|
338
|
+
args: [getSelfArg()],
|
|
339
|
+
returns: 'String',
|
|
340
|
+
code: ['Self::ContractType::symbol(e)'],
|
|
341
|
+
},
|
|
342
|
+
token_uri: {
|
|
343
|
+
args: [getSelfArg(), { name: 'token_id', type: 'u32' }],
|
|
344
|
+
returns: 'String',
|
|
345
|
+
code: ['Self::ContractType::token_uri(e, token_id)'],
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
// Mint
|
|
349
|
+
mint: {
|
|
350
|
+
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'token_id', type: 'u32' }],
|
|
351
|
+
code: ['Base::mint(e, &to, token_id);'],
|
|
352
|
+
},
|
|
353
|
+
sequential_mint: {
|
|
354
|
+
args: [getSelfArg(), { name: 'to', type: 'Address' }],
|
|
355
|
+
code: ['Base::sequential_mint(e, &to);'],
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
const burnableFunctions = defineFunctions({
|
|
360
|
+
burn: {
|
|
361
|
+
args: [getSelfArg(), { name: 'from', type: 'Address' }, { name: 'token_id', type: 'u32' }],
|
|
362
|
+
code: ['Self::ContractType::burn(e, &from, token_id)'],
|
|
363
|
+
},
|
|
364
|
+
burn_from: {
|
|
365
|
+
args: [
|
|
366
|
+
getSelfArg(),
|
|
367
|
+
{ name: 'spender', type: 'Address' },
|
|
368
|
+
{ name: 'from', type: 'Address' },
|
|
369
|
+
{ name: 'token_id', type: 'u32' },
|
|
370
|
+
],
|
|
371
|
+
code: ['Self::ContractType::burn_from(e, &spender, &from, token_id)'],
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
const enumerableFunctions = defineFunctions({
|
|
376
|
+
total_supply: {
|
|
377
|
+
args: [getSelfArg()],
|
|
378
|
+
returns: 'u32',
|
|
379
|
+
code: ['non_fungible::enumerable::Enumerable::total_supply(e)'],
|
|
380
|
+
},
|
|
381
|
+
// These are not currently used, see addEnumerable() above
|
|
382
|
+
/*
|
|
383
|
+
get_owner_token_id: {
|
|
384
|
+
args: [getSelfArg(), { name: 'owner', type: 'Address' }, { name: 'index', type: 'u32' }],
|
|
385
|
+
returns: 'u32',
|
|
386
|
+
code: ['Enumerable::get_owner_token_id(e, &owner, index)'],
|
|
387
|
+
},
|
|
388
|
+
get_token_id: {
|
|
389
|
+
args: [getSelfArg(), { name: 'index', type: 'u32' }],
|
|
390
|
+
returns: 'u32',
|
|
391
|
+
code: ['Enumerable::get_token_id(e, index)'],
|
|
392
|
+
},
|
|
393
|
+
*/
|
|
394
|
+
non_sequential_mint: {
|
|
395
|
+
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'token_id', type: 'u32' }],
|
|
396
|
+
code: ['Enumerable::non_sequential_mint(e, &to, token_id);'], // TODO: unify `mint` name in Stellar-Contracts across extensions
|
|
397
|
+
},
|
|
398
|
+
sequential_mint: {
|
|
399
|
+
args: [getSelfArg(), { name: 'to', type: 'Address' }],
|
|
400
|
+
code: ['Enumerable::sequential_mint(e, &to);'],
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const consecutiveFunctions = defineFunctions({
|
|
405
|
+
batch_mint: {
|
|
406
|
+
args: [getSelfArg(), { name: 'to', type: 'Address' }, { name: 'amount', type: 'u32' }],
|
|
407
|
+
returns: 'u32',
|
|
408
|
+
code: ['Consecutive::batch_mint(e, &to, amount);'],
|
|
409
|
+
},
|
|
410
|
+
});
|