@openzeppelin/wizard-stellar 0.2.3 → 0.4.1
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 +29 -8
- package/dist/add-pausable.js.map +1 -1
- package/dist/add-upgradeable.d.ts.map +1 -1
- package/dist/add-upgradeable.js +14 -4
- 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 +1 -1
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +9 -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 +86 -55
- 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 +101 -81
- package/dist/non-fungible.js.map +1 -1
- package/dist/print.js +5 -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/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 +2 -1
- package/dist/zip-rust.d.ts.map +1 -1
- package/dist/zip-rust.js +8 -5
- package/dist/zip-rust.js.map +1 -1
- package/dist/zip-scaffold.d.ts +2 -2
- package/dist/zip-scaffold.d.ts.map +1 -1
- package/dist/zip-scaffold.js +14 -158
- package/dist/zip-scaffold.js.map +1 -1
- package/dist/zip-shared.d.ts +4 -17
- package/dist/zip-shared.d.ts.map +1 -1
- package/dist/zip-shared.js +25 -19
- package/dist/zip-shared.js.map +1 -1
- package/package.json +1 -1
- package/src/add-pausable.ts +31 -9
- package/src/add-upgradeable.ts +17 -5
- package/src/api.ts +27 -4
- package/src/build-generic.ts +6 -0
- package/src/contract.ts +9 -2
- package/src/fungible.ts +90 -61
- 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 +108 -87
- package/src/print.ts +5 -5
- package/src/set-access-control.ts +72 -19
- 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 +10 -6
- package/src/zip-scaffold.ts +15 -169
- package/src/zip-shared.ts +26 -22
package/src/print.ts
CHANGED
|
@@ -248,7 +248,7 @@ function printFunction(fn: ContractFunction): Lines[] {
|
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
return printFunction2(fn.pub, head, args, fn.
|
|
251
|
+
return printFunction2(fn.pub, head, args, fn.tags, fn.returns, undefined, codeLines);
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
function printContractFunctions(contract: Contract): Lines[] {
|
|
@@ -289,7 +289,7 @@ function printConstructor(contract: Contract): Lines[] {
|
|
|
289
289
|
true,
|
|
290
290
|
head,
|
|
291
291
|
args.map(a => printArgument(a)),
|
|
292
|
-
|
|
292
|
+
[],
|
|
293
293
|
undefined,
|
|
294
294
|
undefined,
|
|
295
295
|
body,
|
|
@@ -306,15 +306,15 @@ function printFunction2(
|
|
|
306
306
|
pub: boolean | undefined,
|
|
307
307
|
kindedName: string,
|
|
308
308
|
args: string[],
|
|
309
|
-
|
|
309
|
+
tags: string[],
|
|
310
310
|
returns: string | undefined,
|
|
311
311
|
returnLine: string | undefined,
|
|
312
312
|
code: Lines[],
|
|
313
313
|
): Lines[] {
|
|
314
314
|
const fn = [];
|
|
315
315
|
|
|
316
|
-
|
|
317
|
-
fn.push(`#[${
|
|
316
|
+
for (let i = 0; i < tags.length; i++) {
|
|
317
|
+
fn.push(`#[${tags[i]}]`);
|
|
318
318
|
}
|
|
319
319
|
|
|
320
320
|
let accum = '';
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { BaseFunction, BaseTraitImplBlock, ContractBuilder } from './contract';
|
|
2
2
|
|
|
3
|
-
export const accessOptions = [false, 'ownable'] as const;
|
|
3
|
+
export const accessOptions = [false, 'ownable', 'roles'] as const;
|
|
4
4
|
export const DEFAULT_ACCESS_CONTROL = 'ownable';
|
|
5
5
|
|
|
6
6
|
export type Access = (typeof accessOptions)[number];
|
|
7
|
+
export type AccessProps = {
|
|
8
|
+
useMacro: boolean;
|
|
9
|
+
caller?: string;
|
|
10
|
+
role?: string;
|
|
11
|
+
};
|
|
7
12
|
|
|
8
13
|
/**
|
|
9
14
|
* Sets access control for the contract via constructor args.
|
|
@@ -15,14 +20,40 @@ export function setAccessControl(c: ContractBuilder, access: Access): void {
|
|
|
15
20
|
case 'ownable': {
|
|
16
21
|
if (!c.ownable) {
|
|
17
22
|
c.ownable = true;
|
|
18
|
-
c.addUseClause('soroban_sdk', '
|
|
19
|
-
c.addUseClause('
|
|
20
|
-
c.
|
|
23
|
+
c.addUseClause('soroban_sdk', 'Address');
|
|
24
|
+
c.addUseClause('stellar_contract_utils::ownable', 'self', { alias: 'ownable' });
|
|
25
|
+
c.addUseClause('stellar_contract_utils::ownable', 'Ownable');
|
|
26
|
+
|
|
27
|
+
const ownableTrait = {
|
|
28
|
+
traitName: 'Ownable',
|
|
29
|
+
structName: c.name,
|
|
30
|
+
tags: ['default_impl', 'contractimpl'],
|
|
31
|
+
section: 'Utils',
|
|
32
|
+
};
|
|
33
|
+
c.addTraitImplBlock(ownableTrait);
|
|
34
|
+
|
|
21
35
|
c.addConstructorArgument({ name: 'owner', type: 'Address' });
|
|
22
|
-
c.addConstructorCode('e
|
|
36
|
+
c.addConstructorCode('ownable::set_owner(e, &owner);');
|
|
23
37
|
}
|
|
24
38
|
break;
|
|
25
39
|
}
|
|
40
|
+
case 'roles': {
|
|
41
|
+
c.addUseClause('soroban_sdk', 'Address');
|
|
42
|
+
c.addUseClause('stellar_contract_utils::access_control', 'self', { alias: 'access_control' });
|
|
43
|
+
c.addUseClause('stellar_contract_utils::access_control', 'AccessControl');
|
|
44
|
+
|
|
45
|
+
const accessControltrait = {
|
|
46
|
+
traitName: 'AccessControl',
|
|
47
|
+
structName: c.name,
|
|
48
|
+
tags: ['default_impl', 'contractimpl'],
|
|
49
|
+
section: 'Utils',
|
|
50
|
+
};
|
|
51
|
+
c.addTraitImplBlock(accessControltrait);
|
|
52
|
+
|
|
53
|
+
c.addConstructorArgument({ name: 'admin', type: 'Address' });
|
|
54
|
+
c.addConstructorCode('access_control::set_admin(e, &admin);');
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
26
57
|
default: {
|
|
27
58
|
const _: never = access;
|
|
28
59
|
throw new Error('Unknown value for `access`');
|
|
@@ -32,15 +63,13 @@ export function setAccessControl(c: ContractBuilder, access: Access): void {
|
|
|
32
63
|
|
|
33
64
|
/**
|
|
34
65
|
* Enables access control for the contract and restricts the given function with access control.
|
|
35
|
-
*
|
|
36
|
-
* If `caller` is provided, requires that the caller is the owner. Otherwise, requires that the owner is authorized.
|
|
37
66
|
*/
|
|
38
67
|
export function requireAccessControl(
|
|
39
68
|
c: ContractBuilder,
|
|
40
69
|
trait: BaseTraitImplBlock | undefined,
|
|
41
70
|
fn: BaseFunction,
|
|
42
71
|
access: Access,
|
|
43
|
-
|
|
72
|
+
accessProps: AccessProps = { useMacro: true },
|
|
44
73
|
): void {
|
|
45
74
|
if (access === false) {
|
|
46
75
|
access = DEFAULT_ACCESS_CONTROL;
|
|
@@ -49,19 +78,43 @@ export function requireAccessControl(
|
|
|
49
78
|
|
|
50
79
|
switch (access) {
|
|
51
80
|
case 'ownable': {
|
|
52
|
-
c.addUseClause('
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
c.
|
|
56
|
-
c.addError('Unauthorized', 1); // TODO: Ensure there are no conflicts in error codes
|
|
57
|
-
c.addFunctionCodeBefore(
|
|
58
|
-
fn,
|
|
59
|
-
[getOwner, `if owner != ${caller} {`, ` panic_with_error!(e, ${c.name}Error::Unauthorized)`, '}'],
|
|
60
|
-
trait,
|
|
61
|
-
);
|
|
81
|
+
c.addUseClause('stellar_macros', 'only_owner');
|
|
82
|
+
|
|
83
|
+
if (accessProps.useMacro) {
|
|
84
|
+
c.addFunctionTag(fn, 'only_owner', trait);
|
|
62
85
|
} else {
|
|
63
|
-
c.addFunctionCodeBefore(fn, [
|
|
86
|
+
c.addFunctionCodeBefore(fn, [`ownable::enforce_owner_auth(e);`], trait);
|
|
64
87
|
}
|
|
88
|
+
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
case 'roles': {
|
|
92
|
+
const { useMacro, caller, role } = accessProps;
|
|
93
|
+
|
|
94
|
+
if (caller && role) {
|
|
95
|
+
c.addUseClause('soroban_sdk', 'Symbol');
|
|
96
|
+
c.addConstructorArgument({ name: role, type: 'Address' });
|
|
97
|
+
c.addConstructorCode(`access_control::grant_role_no_auth(e, &admin, &${role}, &Symbol::new(e, "${role}"));`);
|
|
98
|
+
|
|
99
|
+
if (useMacro) {
|
|
100
|
+
c.addUseClause('stellar_macros', 'only_role');
|
|
101
|
+
c.addFunctionTag(fn, `only_role(${caller}, "${role}")`, trait);
|
|
102
|
+
} else {
|
|
103
|
+
c.addFunctionCodeBefore(
|
|
104
|
+
fn,
|
|
105
|
+
[`access_control::ensure_role(e, ${caller}, &Symbol::new(e, "${role}"));`],
|
|
106
|
+
trait,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
if (useMacro) {
|
|
111
|
+
c.addUseClause('stellar_macros', 'only_admin');
|
|
112
|
+
c.addFunctionTag(fn, 'only_admin', trait);
|
|
113
|
+
} else {
|
|
114
|
+
c.addFunctionCodeBefore(fn, ['access_control::enforce_admin_auth(e);'], trait);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
65
118
|
break;
|
|
66
119
|
}
|
|
67
120
|
default: {
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { Contract, ContractBuilder } from './contract';
|
|
2
|
+
import { defineFunctions } from './utils/define-functions';
|
|
3
|
+
import { getSelfArg } from './common-options';
|
|
4
|
+
import { printContract } from './print';
|
|
5
|
+
import type { FungibleOptions } from './fungible';
|
|
6
|
+
import {
|
|
7
|
+
buildFungible,
|
|
8
|
+
defaults as fungibleDefaults,
|
|
9
|
+
withDefaults as withFungibleDefaults,
|
|
10
|
+
functions as fungibleFunctions,
|
|
11
|
+
isAccessControlRequired as fungibleIsAccessControlRequired,
|
|
12
|
+
} from './fungible';
|
|
13
|
+
import { requireAccessControl, type Access } from './set-access-control';
|
|
14
|
+
|
|
15
|
+
export const defaults: Required<StablecoinOptions> = {
|
|
16
|
+
...fungibleDefaults,
|
|
17
|
+
name: 'MyStablecoin',
|
|
18
|
+
symbol: 'MST',
|
|
19
|
+
limitations: false,
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
export const limitationsOptions = [false, 'allowlist', 'blocklist'] as const;
|
|
23
|
+
|
|
24
|
+
export function printStablecoin(opts: StablecoinOptions = defaults): string {
|
|
25
|
+
return printContract(buildStablecoin(opts));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface StablecoinOptions extends FungibleOptions {
|
|
29
|
+
limitations?: false | 'allowlist' | 'blocklist';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function withDefaults(opts: StablecoinOptions): Required<StablecoinOptions> {
|
|
33
|
+
return {
|
|
34
|
+
...withFungibleDefaults(opts),
|
|
35
|
+
name: opts.name ?? defaults.name,
|
|
36
|
+
symbol: opts.symbol ?? defaults.symbol,
|
|
37
|
+
limitations: opts.limitations ?? defaults.limitations,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function isAccessControlRequired(opts: Partial<StablecoinOptions>): boolean {
|
|
42
|
+
return fungibleIsAccessControlRequired(opts) || opts.limitations !== false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function buildStablecoin(opts: StablecoinOptions): Contract {
|
|
46
|
+
const allOpts = withDefaults(opts);
|
|
47
|
+
|
|
48
|
+
const c = buildFungible(allOpts);
|
|
49
|
+
|
|
50
|
+
if (allOpts.limitations) {
|
|
51
|
+
addLimitations(c, allOpts.access, allOpts.limitations);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return c;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function addLimitations(c: ContractBuilder, access: Access, mode: 'allowlist' | 'blocklist') {
|
|
58
|
+
const type = mode === 'allowlist';
|
|
59
|
+
|
|
60
|
+
const limitationsTrait = {
|
|
61
|
+
traitName: type ? 'FungibleAllowList' : 'FungibleBlockList',
|
|
62
|
+
structName: c.name,
|
|
63
|
+
tags: ['contractimpl'],
|
|
64
|
+
section: 'Extensions',
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
if (type) {
|
|
68
|
+
c.addUseClause('stellar_tokens::fungible', 'allowlist::{AllowList, FungibleAllowList}');
|
|
69
|
+
c.overrideAssocType('FungibleToken', 'type ContractType = AllowList;');
|
|
70
|
+
} else {
|
|
71
|
+
c.addUseClause('stellar_tokens::fungible', 'blocklist::{BlockList, FungibleBlockList}');
|
|
72
|
+
c.overrideAssocType('FungibleToken', 'type ContractType = BlockList;');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const [getterFn, addFn, removeFn] = type
|
|
76
|
+
? [functions.allowed, functions.allow_user, functions.disallow_user]
|
|
77
|
+
: [functions.blocked, functions.block_user, functions.unblock_user];
|
|
78
|
+
|
|
79
|
+
c.addTraitFunction(limitationsTrait, getterFn);
|
|
80
|
+
|
|
81
|
+
const accessProps = {
|
|
82
|
+
useMacro: true,
|
|
83
|
+
role: 'manager',
|
|
84
|
+
caller: 'operator',
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
c.addTraitFunction(limitationsTrait, addFn);
|
|
88
|
+
requireAccessControl(c, limitationsTrait, addFn, access, accessProps);
|
|
89
|
+
|
|
90
|
+
c.addTraitFunction(limitationsTrait, removeFn);
|
|
91
|
+
requireAccessControl(c, limitationsTrait, removeFn, access, accessProps);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const functions = {
|
|
95
|
+
...fungibleFunctions,
|
|
96
|
+
...defineFunctions({
|
|
97
|
+
allowed: {
|
|
98
|
+
args: [getSelfArg(), { name: 'account', type: 'Address' }],
|
|
99
|
+
returns: 'bool',
|
|
100
|
+
code: ['AllowList::allowed(e, &account)'],
|
|
101
|
+
},
|
|
102
|
+
allow_user: {
|
|
103
|
+
args: [getSelfArg(), { name: 'user', type: 'Address' }, { name: 'operator', type: 'Address' }],
|
|
104
|
+
code: ['AllowList::allow_user(e, &user)'],
|
|
105
|
+
},
|
|
106
|
+
disallow_user: {
|
|
107
|
+
args: [getSelfArg(), { name: 'user', type: 'Address' }, { name: 'operator', type: 'Address' }],
|
|
108
|
+
code: ['AllowList::disallow_user(e, &user)'],
|
|
109
|
+
},
|
|
110
|
+
blocked: {
|
|
111
|
+
args: [getSelfArg(), { name: 'account', type: 'Address' }],
|
|
112
|
+
returns: 'bool',
|
|
113
|
+
code: ['BlockList::blocked(e, &account)'],
|
|
114
|
+
},
|
|
115
|
+
block_user: {
|
|
116
|
+
args: [getSelfArg(), { name: 'user', type: 'Address' }, { name: 'operator', type: 'Address' }],
|
|
117
|
+
code: ['BlockList::block_user(e, &user)'],
|
|
118
|
+
},
|
|
119
|
+
unblock_user: {
|
|
120
|
+
args: [getSelfArg(), { name: 'user', type: 'Address' }, { name: 'operator', type: 'Address' }],
|
|
121
|
+
code: ['BlockList::unblock_user(e, &user)'],
|
|
122
|
+
},
|
|
123
|
+
}),
|
|
124
|
+
};
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { BaseFunction } from '../contract';
|
|
2
2
|
|
|
3
|
-
type
|
|
3
|
+
type OverridableImplicitNameFunction = Omit<BaseFunction, 'name'> & { name?: string };
|
|
4
4
|
|
|
5
|
-
export function defineFunctions<F extends string>(
|
|
5
|
+
export function defineFunctions<F extends string>(
|
|
6
|
+
fns: Record<F, OverridableImplicitNameFunction>,
|
|
7
|
+
): Record<F, BaseFunction>;
|
|
6
8
|
|
|
7
|
-
export function defineFunctions(fns: Record<string,
|
|
8
|
-
return Object.fromEntries(
|
|
9
|
+
export function defineFunctions(fns: Record<string, OverridableImplicitNameFunction>): Record<string, BaseFunction> {
|
|
10
|
+
return Object.fromEntries(
|
|
11
|
+
Object.entries(fns).map(([implicitName, fn]) => [
|
|
12
|
+
implicitName,
|
|
13
|
+
Object.assign({ name: fn.name ?? implicitName }, fn),
|
|
14
|
+
]),
|
|
15
|
+
);
|
|
9
16
|
}
|
package/src/utils/version.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The actual latest version to use in links.
|
|
3
3
|
*/
|
|
4
|
-
export const contractsVersion = '0.
|
|
4
|
+
export const contractsVersion = '0.4.1';
|
|
5
5
|
export const contractsVersionTag = `v${contractsVersion}`;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Semantic version string representing of the minimum compatible version of Contracts to display in output.
|
|
9
9
|
*/
|
|
10
|
-
export const compatibleContractsSemver = '^0.
|
|
10
|
+
export const compatibleContractsSemver = '^0.4.1';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* The Soroban version for which compilation and testing have passing tests
|
package/src/zip-rust.ts
CHANGED
|
@@ -4,13 +4,13 @@ import type { Contract } from './contract';
|
|
|
4
4
|
import { printContract, removeCreateLevelAttributes } from './print';
|
|
5
5
|
import {
|
|
6
6
|
addDependenciesWith,
|
|
7
|
-
|
|
7
|
+
libDependencies,
|
|
8
8
|
contractOptionsToContractName,
|
|
9
9
|
createRustLibFile,
|
|
10
10
|
printContractCargo,
|
|
11
11
|
printRustNameTest,
|
|
12
12
|
} from './zip-shared';
|
|
13
|
-
import {
|
|
13
|
+
import { contractsVersion, compatibleSorobanVersion } from './utils/version';
|
|
14
14
|
|
|
15
15
|
const workspaceCargo = `[workspace]
|
|
16
16
|
resolver = "2"
|
|
@@ -23,7 +23,7 @@ license = "Apache-2.0"
|
|
|
23
23
|
version = "0.0.1"
|
|
24
24
|
|
|
25
25
|
[workspace.dependencies]
|
|
26
|
-
${addDependenciesWith(`
|
|
26
|
+
${addDependenciesWith(`"${compatibleSorobanVersion}"`, ['soroban-sdk'])}${addDependenciesWith(`"=${contractsVersion}"`, [...libDependencies])}
|
|
27
27
|
`;
|
|
28
28
|
|
|
29
29
|
const readme = `\
|
|
@@ -41,7 +41,7 @@ Continue your development journey with [Stellar CLI](https://github.com/stellar/
|
|
|
41
41
|
- See [Git installation guide](https://github.com/git-guides/install-git).
|
|
42
42
|
`;
|
|
43
43
|
|
|
44
|
-
export
|
|
44
|
+
export const createRustZipEnvironment = (c: Contract, opts: GenericOptions) => {
|
|
45
45
|
const zip = new JSZip();
|
|
46
46
|
|
|
47
47
|
const contractName = contractOptionsToContractName(opts?.kind || 'contract');
|
|
@@ -51,7 +51,11 @@ export async function zipRust(c: Contract, opts: GenericOptions) {
|
|
|
51
51
|
zip.file(`contracts/${contractName}/src/lib.rs`, createRustLibFile);
|
|
52
52
|
zip.file(`contracts/${contractName}/Cargo.toml`, printContractCargo(contractName));
|
|
53
53
|
zip.file('Cargo.toml', workspaceCargo);
|
|
54
|
-
zip.file('README.md', readme);
|
|
55
54
|
|
|
56
55
|
return zip;
|
|
57
|
-
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const addRustProjectReadme = (zip: JSZip) => zip.file('README.md', readme);
|
|
59
|
+
|
|
60
|
+
export const zipRustProject = async (c: Contract, opts: GenericOptions) =>
|
|
61
|
+
addRustProjectReadme(createRustZipEnvironment(c, opts));
|
package/src/zip-scaffold.ts
CHANGED
|
@@ -1,138 +1,14 @@
|
|
|
1
|
-
import JSZip from 'jszip';
|
|
1
|
+
import type JSZip from 'jszip';
|
|
2
2
|
import type { GenericOptions } from './build-generic';
|
|
3
3
|
import type { Contract } from './contract';
|
|
4
|
-
import {
|
|
5
|
-
import { compatibleSorobanVersion, contractsVersionTag } from './utils/version';
|
|
6
|
-
import {
|
|
7
|
-
addDependenciesWith,
|
|
8
|
-
allStellarDependencies,
|
|
9
|
-
contractOptionsToContractName,
|
|
10
|
-
createRustLibFile,
|
|
11
|
-
printContractCargo,
|
|
12
|
-
printRustNameTest,
|
|
13
|
-
} from './zip-shared';
|
|
4
|
+
import { createRustZipEnvironment } from './zip-rust';
|
|
14
5
|
|
|
15
|
-
|
|
16
|
-
return c.constructorArgs
|
|
17
|
-
.filter(constructorArg => constructorArg.type?.toLowerCase() === 'address')
|
|
18
|
-
.map(constructorArg => constructorArg.name);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const setupSh = (c: Contract, opts: GenericOptions, scaffoldContractName: string) => {
|
|
22
|
-
const environmentsFileUpdate = (setUpContract: Contract, setUpScaffoldContractName: string) => `
|
|
23
|
-
# Update environments.toml: remove original contracts and insert wizard's contract
|
|
24
|
-
setup_environment() {
|
|
25
|
-
local file="environments.toml"
|
|
26
|
-
local temp
|
|
27
|
-
temp="$(mktemp)"
|
|
28
|
-
|
|
29
|
-
local in_dev_contracts=0
|
|
30
|
-
local skip_entry=0
|
|
31
|
-
local contract_entry_inserted=0
|
|
32
|
-
insert_contract_entry() {
|
|
33
|
-
{
|
|
34
|
-
printf '%s\\n' "[development.contracts.${setUpScaffoldContractName}_contract]" \\
|
|
35
|
-
"client = true" "" \\
|
|
36
|
-
"# If your contract has a \\\`__constructor\\\`, specify your arguments to it here." \\
|
|
37
|
-
"# These are the same arguments you could pass after the \\\`--\\\` in a call to" \\
|
|
38
|
-
"# \\\`stellar contract deploy\\\`" \\
|
|
39
|
-
"# Only available in \\\`development\\\` and \\\`test\\\` environments" \\
|
|
40
|
-
${
|
|
41
|
-
setUpContract.constructorArgs.length
|
|
42
|
-
? // Mind the spacing
|
|
43
|
-
`"# TODO add appropriate values for for the constructors arguments" \\
|
|
44
|
-
"constructor_args = \\"\\"\\"" \\
|
|
45
|
-
"${setUpContract.constructorArgs.map(constructorArg => `--${constructorArg.name} \\"ADD_${constructorArg.name.toLocaleUpperCase()}_${constructorArg.type?.toLocaleUpperCase() || 'ARGUMENT'}_HERE\\"`).join(' ')}" \\
|
|
46
|
-
"\\"\\"\\"" \\
|
|
47
|
-
""`
|
|
48
|
-
: '""'
|
|
49
|
-
}
|
|
50
|
-
} >> "$temp"
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
while IFS= read -r line; do
|
|
54
|
-
if [[ $contract_entry_inserted -eq 0 && $line == '[staging.network]' ]]; then
|
|
55
|
-
insert_contract_entry
|
|
56
|
-
contract_entry_inserted=1
|
|
57
|
-
fi
|
|
58
|
-
|
|
59
|
-
if [[ $line =~ ^\\[development\\.contracts\\]$ ]]; then
|
|
60
|
-
printf '%s\\n' "$line" >> "$temp"
|
|
61
|
-
in_dev_contracts=1
|
|
62
|
-
skip_entry=0
|
|
63
|
-
continue
|
|
64
|
-
fi
|
|
65
|
-
|
|
66
|
-
if [[ $line =~ ^\\[[^]]+\\]$ ]]; then
|
|
67
|
-
if (( in_dev_contracts )) && [[ $line =~ ^\\[development\\.contracts\\..+\\]$ ]]; then
|
|
68
|
-
skip_entry=1
|
|
69
|
-
in_dev_contracts=0
|
|
70
|
-
continue
|
|
71
|
-
fi
|
|
72
|
-
in_dev_contracts=0
|
|
73
|
-
skip_entry=0
|
|
74
|
-
printf '%s\\n' "$line" >> "$temp"
|
|
75
|
-
continue
|
|
76
|
-
fi
|
|
77
|
-
|
|
78
|
-
if (( skip_entry )); then
|
|
79
|
-
continue
|
|
80
|
-
fi
|
|
81
|
-
|
|
82
|
-
if (( in_dev_contracts )); then
|
|
83
|
-
if [[ $line =~ ^[[:space:]]*# ]]; then
|
|
84
|
-
printf '%s\\n' "$line" >> "$temp"
|
|
85
|
-
fi
|
|
86
|
-
continue
|
|
87
|
-
fi
|
|
88
|
-
|
|
89
|
-
printf '%s\\n' "$line" >> "$temp"
|
|
90
|
-
done < "$file"
|
|
91
|
-
|
|
92
|
-
mv "$temp" "$file"
|
|
93
|
-
}
|
|
94
|
-
`;
|
|
95
|
-
|
|
96
|
-
const updateWorkspaceCargo = `update_cargo() {
|
|
97
|
-
cp Cargo.toml Cargo.toml.bak
|
|
98
|
-
|
|
99
|
-
cat <<EOF > deps.tmp
|
|
100
|
-
${addDependenciesWith(`{ git = "https://github.com/OpenZeppelin/stellar-contracts", tag = "${contractsVersionTag}" }`, allStellarDependencies)}${addDependenciesWith(`{ version = "${compatibleSorobanVersion}" }`, ['soroban'])}
|
|
101
|
-
EOF
|
|
102
|
-
|
|
103
|
-
awk '
|
|
104
|
-
BEGIN {
|
|
105
|
-
inserted = 0
|
|
106
|
-
deps = ""
|
|
107
|
-
while ((getline line < "deps.tmp") > 0) {
|
|
108
|
-
deps = deps line "\\n"
|
|
109
|
-
}
|
|
110
|
-
close("deps.tmp")
|
|
111
|
-
}
|
|
112
|
-
/^\\[workspace.dependencies\\]/ {
|
|
113
|
-
in_deps = 1
|
|
114
|
-
print
|
|
115
|
-
if (!inserted) {
|
|
116
|
-
printf "%s", deps
|
|
117
|
-
inserted = 1
|
|
118
|
-
}
|
|
119
|
-
next
|
|
120
|
-
}
|
|
121
|
-
/^\\[/ { in_deps = 0 }
|
|
122
|
-
in_deps { next }
|
|
123
|
-
{ print }
|
|
124
|
-
' Cargo.toml.bak > Cargo.toml
|
|
125
|
-
|
|
126
|
-
rm deps.tmp
|
|
127
|
-
rm Cargo.toml.bak
|
|
128
|
-
}`;
|
|
129
|
-
|
|
130
|
-
return `\
|
|
6
|
+
const setupSh = `\
|
|
131
7
|
#!/usr/bin/env bash
|
|
132
8
|
#
|
|
133
9
|
# setup.sh
|
|
134
|
-
#
|
|
135
|
-
# This script is meant to set up a Scaffold project
|
|
10
|
+
#
|
|
11
|
+
# This script is meant to set up a Scaffold project with the Wizard's contracts
|
|
136
12
|
|
|
137
13
|
check_is_installed() {
|
|
138
14
|
if ! which "$1" &> /dev/null; then
|
|
@@ -143,18 +19,7 @@ check_is_installed() {
|
|
|
143
19
|
}
|
|
144
20
|
|
|
145
21
|
scaffold() {
|
|
146
|
-
|
|
147
|
-
stellar scaffold init "$tmp_folder"
|
|
148
|
-
|
|
149
|
-
rm -rf "$tmp_folder/contracts"
|
|
150
|
-
|
|
151
|
-
local current_directory
|
|
152
|
-
current_directory="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
|
|
153
|
-
|
|
154
|
-
shopt -s dotglob
|
|
155
|
-
|
|
156
|
-
cp -a "$current_directory/$tmp_folder"/. "$current_directory"/
|
|
157
|
-
rm -rf "$current_directory/$tmp_folder"
|
|
22
|
+
stellar-scaffold upgrade
|
|
158
23
|
}
|
|
159
24
|
|
|
160
25
|
init_git(){
|
|
@@ -163,10 +28,6 @@ init_git(){
|
|
|
163
28
|
git commit -m "openzeppelin: add wizard output" --quiet
|
|
164
29
|
}
|
|
165
30
|
|
|
166
|
-
${environmentsFileUpdate(c, scaffoldContractName)}
|
|
167
|
-
|
|
168
|
-
${updateWorkspaceCargo}
|
|
169
|
-
|
|
170
31
|
build_contracts() {
|
|
171
32
|
cargo build
|
|
172
33
|
}
|
|
@@ -196,10 +57,6 @@ then
|
|
|
196
57
|
echo "🏗️ Building Scaffold project"
|
|
197
58
|
|
|
198
59
|
scaffold
|
|
199
|
-
|
|
200
|
-
setup_environment
|
|
201
|
-
|
|
202
|
-
update_cargo
|
|
203
60
|
|
|
204
61
|
build_contracts
|
|
205
62
|
|
|
@@ -212,15 +69,11 @@ else
|
|
|
212
69
|
echo "✅ Scaffold project already initialized."
|
|
213
70
|
fi
|
|
214
71
|
`;
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
const readme = (c: Contract) => {
|
|
218
|
-
const hasTodosToResolve = (c: Contract) => getAddressArgs(c).length > 0;
|
|
219
72
|
|
|
220
|
-
|
|
73
|
+
const wizardReadme = `\
|
|
221
74
|
# Sample Scaffold Project
|
|
222
75
|
|
|
223
|
-
This project demonstrates a basic Scaffold use case. It comes with a contract generated by [OpenZeppelin Wizard](https://wizard.openzeppelin.com/), a test for that contract, and a script that
|
|
76
|
+
This project demonstrates a basic Scaffold use case. It comes with a contract generated by [OpenZeppelin Wizard](https://wizard.openzeppelin.com/), a test for that contract, and a script that initiates a Stellar Scaffold project with this contract. [Scaffold Stellar](https://github.com/AhaLabs/scaffold-stellar?tab=readme-ov-file#scaffold-stellar) is a convention-over-configuration toolkit for blockchain and distributed application development on the Stellar network. It provides a seamless development experience through CLI tools, smart contract management, and deployment utilities.
|
|
224
77
|
|
|
225
78
|
## Installing dependencies
|
|
226
79
|
|
|
@@ -235,7 +88,6 @@ This project demonstrates a basic Scaffold use case. It comes with a contract ge
|
|
|
235
88
|
\`\`\`
|
|
236
89
|
bash setup.sh
|
|
237
90
|
\`\`\`
|
|
238
|
-
${hasTodosToResolve(c) ? '\n## Resolve any TODOs \n\nSearch for any TODO comments in the project and resolve them (search for TODO with your code editor).\n' : ''}
|
|
239
91
|
|
|
240
92
|
## Testing the contract
|
|
241
93
|
|
|
@@ -255,19 +107,13 @@ stellar scaffold watch --build-clients
|
|
|
255
107
|
npm run dev
|
|
256
108
|
\`\`\`
|
|
257
109
|
`;
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
export async function zipScaffold(c: Contract, opts: GenericOptions) {
|
|
261
|
-
const zip = new JSZip();
|
|
262
110
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
zip.file(
|
|
266
|
-
zip.file(`contracts/${scaffoldContractName}/src/test.rs`, printRustNameTest(c));
|
|
267
|
-
zip.file(`contracts/${scaffoldContractName}/src/lib.rs`, createRustLibFile);
|
|
268
|
-
zip.file(`contracts/${scaffoldContractName}/Cargo.toml`, printContractCargo(scaffoldContractName));
|
|
269
|
-
zip.file('setup.sh', setupSh(c, opts, scaffoldContractName));
|
|
270
|
-
zip.file('README-WIZARD.md', readme(c));
|
|
111
|
+
const addScaffoldProjectFiles = (zip: JSZip) => {
|
|
112
|
+
zip.file('README-WIZARD.md', wizardReadme);
|
|
113
|
+
zip.file('setup.sh', setupSh);
|
|
271
114
|
|
|
272
115
|
return zip;
|
|
273
|
-
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const zipScaffoldProject = async (c: Contract, opts: GenericOptions) =>
|
|
119
|
+
addScaffoldProjectFiles(createRustZipEnvironment(c, opts));
|