@openzeppelin/wizard-stellar 0.2.3 → 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 (73) 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 +1 -1
  16. package/dist/contract.d.ts.map +1 -1
  17. package/dist/contract.js +9 -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.js +5 -5
  41. package/dist/print.js.map +1 -1
  42. package/dist/set-access-control.d.ts +7 -4
  43. package/dist/set-access-control.d.ts.map +1 -1
  44. package/dist/set-access-control.js +57 -15
  45. package/dist/set-access-control.js.map +1 -1
  46. package/dist/stablecoin.d.ts +11 -0
  47. package/dist/stablecoin.d.ts.map +1 -0
  48. package/dist/stablecoin.js +103 -0
  49. package/dist/stablecoin.js.map +1 -0
  50. package/dist/utils/define-functions.d.ts +4 -2
  51. package/dist/utils/define-functions.d.ts.map +1 -1
  52. package/dist/utils/define-functions.js +7 -1
  53. package/dist/utils/define-functions.js.map +1 -1
  54. package/dist/utils/version.d.ts +3 -3
  55. package/dist/utils/version.js +2 -2
  56. package/dist/zip-shared.d.ts +1 -1
  57. package/package.json +1 -1
  58. package/src/add-pausable.ts +9 -4
  59. package/src/add-upgradeable.ts +6 -2
  60. package/src/api.ts +27 -4
  61. package/src/build-generic.ts +6 -0
  62. package/src/contract.ts +9 -2
  63. package/src/fungible.ts +84 -56
  64. package/src/generate/sources.ts +7 -0
  65. package/src/generate/stablecoin.ts +23 -0
  66. package/src/index.ts +2 -0
  67. package/src/kind.ts +1 -0
  68. package/src/non-fungible.ts +98 -77
  69. package/src/print.ts +5 -5
  70. package/src/set-access-control.ts +72 -19
  71. package/src/stablecoin.ts +124 -0
  72. package/src/utils/define-functions.ts +11 -4
  73. package/src/utils/version.ts +2 -2
@@ -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', 'symbol_short');
19
- c.addUseClause('soroban_sdk', 'Symbol');
20
- c.addVariable({ name: 'OWNER', type: 'Symbol', value: `symbol_short!("OWNER")` });
23
+ c.addUseClause('soroban_sdk', 'Address');
24
+ c.addUseClause('stellar_ownable', 'self', { alias: 'ownable' });
25
+ c.addUseClause('stellar_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.storage().instance().set(&OWNER, &owner);');
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_access_control', 'self', { alias: 'access_control' });
43
+ c.addUseClause('stellar_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
- caller?: string,
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('soroban_sdk', 'Address');
53
- const getOwner = 'let owner: Address = e.storage().instance().get(&OWNER).expect("owner should be set");';
54
- if (caller) {
55
- c.addUseClause('soroban_sdk', 'panic_with_error');
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_ownable_macro', 'only_owner');
82
+
83
+ if (accessProps.useMacro) {
84
+ c.addFunctionTag(fn, 'only_owner', trait);
62
85
  } else {
63
- c.addFunctionCodeBefore(fn, [getOwner, 'owner.require_auth();'], trait);
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_access_control_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_access_control_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_fungible', 'allowlist::{AllowList, FungibleAllowList}');
69
+ c.overrideAssocType('FungibleToken', 'type ContractType = AllowList;');
70
+ } else {
71
+ c.addUseClause('stellar_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 ImplicitNameFunction = Omit<BaseFunction, 'name'>;
3
+ type OverridableImplicitNameFunction = Omit<BaseFunction, 'name'> & { name?: string };
4
4
 
5
- export function defineFunctions<F extends string>(fns: Record<F, ImplicitNameFunction>): Record<F, BaseFunction>;
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, ImplicitNameFunction>): Record<string, BaseFunction> {
8
- return Object.fromEntries(Object.entries(fns).map(([name, fn]) => [name, Object.assign({ name }, fn)]));
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
  }
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * The actual latest version to use in links.
3
3
  */
4
- export const contractsVersion = '0.2.0';
4
+ export const contractsVersion = '0.3.0';
5
5
  export const contractsVersionTag = `v${contractsVersion}`;
6
6
 
7
7
  /**
8
8
  * Semantic version string representing of the minimum compatible version of Contracts to display in output.
9
9
  */
10
- export const compatibleContractsSemver = '^0.2.0';
10
+ export const compatibleContractsSemver = '^0.3.0';
11
11
 
12
12
  /**
13
13
  * The Soroban version for which compilation and testing have passing tests