@openzeppelin/wizard-stellar 0.5.0 → 0.6.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.
Files changed (92) hide show
  1. package/dist/add-upgradeable.d.ts.map +1 -1
  2. package/dist/add-upgradeable.js +15 -14
  3. package/dist/add-upgradeable.js.map +1 -1
  4. package/dist/api.d.ts +5 -2
  5. package/dist/api.d.ts.map +1 -1
  6. package/dist/api.js +7 -1
  7. package/dist/api.js.map +1 -1
  8. package/dist/build-generic.d.ts +4 -0
  9. package/dist/build-generic.d.ts.map +1 -1
  10. package/dist/build-generic.js +3 -0
  11. package/dist/build-generic.js.map +1 -1
  12. package/dist/contract.d.ts +3 -0
  13. package/dist/contract.d.ts.map +1 -1
  14. package/dist/contract.js +4 -0
  15. package/dist/contract.js.map +1 -1
  16. package/dist/fungible.d.ts +3 -1
  17. package/dist/fungible.d.ts.map +1 -1
  18. package/dist/fungible.js +80 -27
  19. package/dist/fungible.js.map +1 -1
  20. package/dist/generate/fungible.d.ts.map +1 -1
  21. package/dist/generate/fungible.js +2 -0
  22. package/dist/generate/fungible.js.map +1 -1
  23. package/dist/generate/governor.d.ts +3 -0
  24. package/dist/generate/governor.d.ts.map +1 -0
  25. package/dist/generate/governor.js +24 -0
  26. package/dist/generate/governor.js.map +1 -0
  27. package/dist/generate/non-fungible.d.ts.map +1 -1
  28. package/dist/generate/non-fungible.js +1 -0
  29. package/dist/generate/non-fungible.js.map +1 -1
  30. package/dist/generate/sources.d.ts.map +1 -1
  31. package/dist/generate/sources.js +6 -0
  32. package/dist/generate/sources.js.map +1 -1
  33. package/dist/generate/stablecoin.d.ts.map +1 -1
  34. package/dist/generate/stablecoin.js +2 -0
  35. package/dist/generate/stablecoin.js.map +1 -1
  36. package/dist/governor.d.ts +17 -0
  37. package/dist/governor.d.ts.map +1 -0
  38. package/dist/governor.js +378 -0
  39. package/dist/governor.js.map +1 -0
  40. package/dist/index.d.ts +2 -0
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +5 -3
  43. package/dist/index.js.map +1 -1
  44. package/dist/kind.js +1 -0
  45. package/dist/kind.js.map +1 -1
  46. package/dist/non-fungible.d.ts +1 -0
  47. package/dist/non-fungible.d.ts.map +1 -1
  48. package/dist/non-fungible.js +68 -7
  49. package/dist/non-fungible.js.map +1 -1
  50. package/dist/print.d.ts.map +1 -1
  51. package/dist/print.js +6 -1
  52. package/dist/print.js.map +1 -1
  53. package/dist/stablecoin.d.ts.map +1 -1
  54. package/dist/stablecoin.js +7 -0
  55. package/dist/stablecoin.js.map +1 -1
  56. package/dist/test.js +3 -0
  57. package/dist/test.js.map +1 -1
  58. package/dist/utils/compile-test.d.ts +2 -2
  59. package/dist/utils/compile-test.d.ts.map +1 -1
  60. package/dist/utils/compile-test.js +54 -3
  61. package/dist/utils/compile-test.js.map +1 -1
  62. package/dist/utils/version.d.ts +4 -4
  63. package/dist/utils/version.js +3 -3
  64. package/dist/zip-rust.d.ts.map +1 -1
  65. package/dist/zip-rust.js +3 -2
  66. package/dist/zip-rust.js.map +1 -1
  67. package/dist/zip-shared.d.ts +3 -4
  68. package/dist/zip-shared.d.ts.map +1 -1
  69. package/dist/zip-shared.js +20 -7
  70. package/dist/zip-shared.js.map +1 -1
  71. package/package.json +1 -1
  72. package/src/add-upgradeable.ts +15 -16
  73. package/src/api.ts +15 -2
  74. package/src/build-generic.ts +6 -0
  75. package/src/contract.ts +6 -0
  76. package/src/fungible.ts +106 -27
  77. package/src/generate/fungible.ts +2 -0
  78. package/src/generate/governor.ts +24 -0
  79. package/src/generate/non-fungible.ts +1 -0
  80. package/src/generate/sources.ts +7 -0
  81. package/src/generate/stablecoin.ts +2 -0
  82. package/src/governor.ts +425 -0
  83. package/src/index.ts +2 -0
  84. package/src/kind.ts +1 -0
  85. package/src/non-fungible.ts +73 -3
  86. package/src/print.ts +6 -1
  87. package/src/stablecoin.ts +8 -0
  88. package/src/test.ts +4 -0
  89. package/src/utils/compile-test.ts +84 -5
  90. package/src/utils/version.ts +3 -3
  91. package/src/zip-rust.ts +4 -2
  92. package/src/zip-shared.ts +17 -6
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.workspaceCargo = exports.createRustLibFile = exports.printContractCargo = exports.addDependenciesWith = exports.allDependencies = exports.libDependencies = exports.printRustNameTest = exports.contractOptionsToContractName = void 0;
3
+ exports.workspaceCargo = exports.createRustLibFile = exports.printContractCargo = exports.addDependenciesWith = exports.printRustNameTest = exports.contractOptionsToContractName = void 0;
4
4
  exports.getAddressArgs = getAddressArgs;
5
+ exports.getRequiredLibDependencies = getRequiredLibDependencies;
5
6
  const version_1 = require("./utils/version");
6
7
  function pascalToSnakeCase(string) {
7
8
  return string
@@ -38,16 +39,27 @@ fn initial_state() {
38
39
  // Add more tests bellow
39
40
  `;
40
41
  exports.printRustNameTest = printRustNameTest;
41
- exports.libDependencies = [
42
+ const libDependencies = [
42
43
  'stellar-tokens',
43
44
  'stellar-access',
44
45
  'stellar-contract-utils',
46
+ 'stellar-governance',
45
47
  'stellar-macros',
46
48
  ];
47
- exports.allDependencies = [...exports.libDependencies, 'soroban-sdk'];
49
+ // Derives required lib crate dependencies from the contract's use clauses.
50
+ // Each use clause has a containerPath like "stellar_tokens::fungible::Base".
51
+ // We extract the first segment (the crate name), convert underscores to hyphens
52
+ // to match Cargo naming (e.g., stellar_tokens -> stellar-tokens), then filter
53
+ // libDependencies to include only crates the contract actually references.
54
+ // Filtering against the known list preserves stable ordering and ignores
55
+ // non-lib crates like soroban_sdk (which is always added separately).
56
+ function getRequiredLibDependencies(c) {
57
+ const usedCrates = new Set(c.useClauses.map(uc => uc.containerPath.split('::')[0].replace(/_/g, '-')));
58
+ return libDependencies.filter(dep => usedCrates.has(dep));
59
+ }
48
60
  const addDependenciesWith = (dependencyValue, dependenciesToAdd) => `${dependenciesToAdd.map(dependency => `${dependency} = ${dependencyValue}\n`).join('')}`;
49
61
  exports.addDependenciesWith = addDependenciesWith;
50
- const printContractCargo = (scaffoldContractName) => `[package]
62
+ const printContractCargo = (scaffoldContractName, requiredLibDeps) => `[package]
51
63
  name = "${scaffoldContractName.replace(/_/, '-')}-contract"
52
64
  edition.workspace = true
53
65
  license.workspace = true
@@ -62,7 +74,7 @@ crate-type = ["cdylib"]
62
74
  doctest = false
63
75
 
64
76
  [dependencies]
65
- ${(0, exports.addDependenciesWith)('{ workspace = true }', [...exports.allDependencies])}
77
+ ${(0, exports.addDependenciesWith)('{ workspace = true }', [...requiredLibDeps, 'soroban-sdk'])}
66
78
  [dev-dependencies]
67
79
  ${(0, exports.addDependenciesWith)('{ workspace = true, features = ["testutils"] }', ['soroban-sdk'])}`;
68
80
  exports.printContractCargo = printContractCargo;
@@ -72,7 +84,7 @@ exports.createRustLibFile = `#![no_std]
72
84
  mod contract;
73
85
  mod test;
74
86
  `;
75
- exports.workspaceCargo = `[workspace]
87
+ const workspaceCargo = (requiredLibDeps) => `[workspace]
76
88
  resolver = "2"
77
89
  members = ["contracts/*"]
78
90
 
@@ -83,7 +95,7 @@ license = "Apache-2.0"
83
95
  version = "0.0.1"
84
96
 
85
97
  [workspace.dependencies]
86
- ${(0, exports.addDependenciesWith)(`"${version_1.compatibleSorobanVersion}"`, ['soroban-sdk'])}${(0, exports.addDependenciesWith)(`"=${version_1.contractsVersion}"`, [...exports.libDependencies])}
98
+ ${(0, exports.addDependenciesWith)(`"${version_1.compatibleSorobanVersion}"`, ['soroban-sdk'])}${(0, exports.addDependenciesWith)(`"=${version_1.contractsVersion}"`, [...requiredLibDeps])}
87
99
 
88
100
  [profile.release]
89
101
  opt-level = "z"
@@ -99,4 +111,5 @@ lto = true
99
111
  inherits = "release"
100
112
  debug-assertions = true
101
113
  `;
114
+ exports.workspaceCargo = workspaceCargo;
102
115
  //# sourceMappingURL=zip-shared.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zip-shared.js","sourceRoot":"","sources":["../src/zip-shared.ts"],"names":[],"mappings":";;;AAYA,wCAIC;AAfD,6CAA6E;AAE7E,SAAS,iBAAiB,CAAC,MAAc;IACvC,OAAO,MAAM;SACV,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC;SAC1B,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;SACjB,WAAW,EAAE,CAAC;AACnB,CAAC;AAEY,QAAA,6BAA6B,GAAG,iBAAiB,CAAC;AAE/D,SAAgB,cAAc,CAAC,CAAoC;IACjE,OAAO,CAAC,CAAC,CAAC,eAAe,IAAI,EAAE,CAAC;SAC7B,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,SAAS,CAAC;SACnE,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;AAChD,CAAC;AAEM,MAAM,iBAAiB,GAAG,CAAC,CAA6C,EAAE,EAAE,CAAC;;;;qBAI/D,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC,EAAE;;yBAEhE,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;;;;;;uCAMH,CAAC,CAAC,IAAI,MAAM,cAAc,CAAC,CAAC,CAAC;KAC7D,GAAG,CAAC,GAAG,EAAE,CAAC,yBAAyB,CAAC;KACpC,IAAI,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;mBACzC,CAAC,CAAC,IAAI;;wDAE+B,CAAC,CAAC,IAAI;;;;CAI7D,CAAC;AArBW,QAAA,iBAAiB,qBAqB5B;AAEW,QAAA,eAAe,GAAG;IAC7B,gBAAgB;IAChB,gBAAgB;IAChB,wBAAwB;IACxB,gBAAgB;CACR,CAAC;AAEE,QAAA,eAAe,GAAG,CAAC,GAAG,uBAAe,EAAE,aAAa,CAAU,CAAC;AAErE,MAAM,mBAAmB,GAAG,CAAC,eAAuB,EAAE,iBAA2B,EAAE,EAAE,CAC1F,GAAG,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,UAAU,MAAM,eAAe,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AAD/E,QAAA,mBAAmB,uBAC4D;AAErF,MAAM,kBAAkB,GAAG,CAAC,oBAA4B,EAAE,EAAE,CAAC;UAC1D,oBAAoB,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC;;;;;;;;;;;;;;EAc9C,IAAA,2BAAmB,EAAC,sBAAsB,EAAE,CAAC,GAAG,uBAAe,CAAC,CAAC;;EAEjE,IAAA,2BAAmB,EAAC,gDAAgD,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;AAjB9E,QAAA,kBAAkB,sBAiB4D;AAE9E,QAAA,iBAAiB,GAAG;;;;;CAKhC,CAAC;AAEW,QAAA,cAAc,GAAG;;;;;;;;;;;EAW5B,IAAA,2BAAmB,EAAC,IAAI,kCAAwB,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC,GAAG,IAAA,2BAAmB,EAAC,KAAK,0BAAgB,GAAG,EAAE,CAAC,GAAG,uBAAe,CAAC,CAAC;;;;;;;;;;;;;;;CAe5I,CAAC"}
1
+ {"version":3,"file":"zip-shared.js","sourceRoot":"","sources":["../src/zip-shared.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openzeppelin/wizard-stellar",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "A boilerplate generator to get started with OpenZeppelin Stellar Soroban Contracts",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": "https://github.com/OpenZeppelin/contracts-wizard",
@@ -6,31 +6,30 @@ import { defineFunctions } from './utils/define-functions';
6
6
 
7
7
  export function addUpgradeable(c: ContractBuilder, access: Access, explicitImplementations: boolean) {
8
8
  const functions = defineFunctions({
9
- _require_auth: {
10
- args: [getSelfArg(), { name: 'operator', type: '&Address' }],
11
- code: ['operator.require_auth();'],
9
+ upgrade: {
10
+ args: [getSelfArg(), { name: 'new_wasm_hash', type: 'BytesN<32>' }, { name: 'operator', type: 'Address' }],
11
+ code: ['upgradeable::upgrade(e, &new_wasm_hash)'],
12
12
  },
13
- _require_auth_unused_operator: {
14
- name: '_require_auth',
15
- args: [getSelfArg(), { name: '_operator', type: '&Address' }],
16
- code: [],
13
+ upgrade_unused_operator: {
14
+ name: 'upgrade',
15
+ args: [getSelfArg(), { name: 'new_wasm_hash', type: 'BytesN<32>' }, { name: '_operator', type: 'Address' }],
16
+ code: ['upgradeable::upgrade(e, &new_wasm_hash)'],
17
17
  },
18
18
  });
19
19
 
20
- c.addUseClause('stellar_contract_utils::upgradeable', 'UpgradeableInternal');
21
- c.addUseClause('stellar_macros', 'Upgradeable');
22
-
23
- c.addDerives('Upgradeable');
20
+ c.addUseClause('soroban_sdk', 'Address');
21
+ c.addUseClause('soroban_sdk', 'BytesN');
22
+ c.addUseClause('stellar_contract_utils::upgradeable', 'self', { alias: 'upgradeable' });
23
+ c.addUseClause('stellar_contract_utils::upgradeable', 'Upgradeable');
24
24
 
25
25
  const upgradeableTrait = {
26
- traitName: 'UpgradeableInternal',
26
+ traitName: 'Upgradeable',
27
27
  structName: c.name,
28
- tags: [],
28
+ tags: ['contractimpl'],
29
29
  section: 'Utils',
30
30
  };
31
31
 
32
- const upgradeFn: BaseFunction =
33
- access === 'ownable' ? functions._require_auth_unused_operator : functions._require_auth;
32
+ const upgradeFn: BaseFunction = access === 'ownable' ? functions.upgrade_unused_operator : functions.upgrade;
34
33
 
35
34
  c.addTraitFunction(upgradeableTrait, upgradeFn);
36
35
 
@@ -40,7 +39,7 @@ export function addUpgradeable(c: ContractBuilder, access: Access, explicitImple
40
39
  upgradeFn,
41
40
  access,
42
41
  {
43
- useMacro: false,
42
+ useMacro: true,
44
43
  role: 'upgrader',
45
44
  caller: 'operator',
46
45
  },
package/src/api.ts CHANGED
@@ -1,5 +1,6 @@
1
- import type { CommonContractOptions } from './common-options';
1
+ import type { CommonContractOptions, CommonOptions } from './common-options';
2
2
  import type { FungibleOptions } from './fungible';
3
+ import type { GovernorOptions } from './governor';
3
4
  import type { NonFungibleOptions } from './non-fungible';
4
5
  import type { StablecoinOptions } from './stablecoin';
5
6
  import {
@@ -12,13 +13,18 @@ import {
12
13
  defaults as fungibledefaults,
13
14
  isAccessControlRequired as fungibleIsAccessControlRequired,
14
15
  } from './fungible';
16
+ import {
17
+ printGovernor,
18
+ defaults as governorDefaults,
19
+ isAccessControlRequired as governorIsAccessControlRequired,
20
+ } from './governor';
15
21
  import {
16
22
  printNonFungible,
17
23
  defaults as nonFungibledefaults,
18
24
  isAccessControlRequired as nonFungibleIsAccessControlRequired,
19
25
  } from './non-fungible';
20
26
 
21
- export interface WizardContractAPI<Options extends CommonContractOptions> {
27
+ export interface WizardContractAPI<Options extends CommonOptions> {
22
28
  /**
23
29
  * Returns a string representation of a contract generated using the provided options. If opts is not provided, uses `defaults`.
24
30
  */
@@ -39,6 +45,7 @@ export interface AccessControlAPI<Options extends CommonContractOptions> {
39
45
  }
40
46
 
41
47
  export type Fungible = WizardContractAPI<FungibleOptions> & AccessControlAPI<FungibleOptions>;
48
+ export type Governor = WizardContractAPI<GovernorOptions> & AccessControlAPI<GovernorOptions>;
42
49
  export type NonFungible = WizardContractAPI<NonFungibleOptions> & AccessControlAPI<NonFungibleOptions>;
43
50
  export type Stablecoin = WizardContractAPI<StablecoinOptions> & AccessControlAPI<StablecoinOptions>;
44
51
 
@@ -48,6 +55,12 @@ export const fungible: Fungible = {
48
55
  isAccessControlRequired: fungibleIsAccessControlRequired,
49
56
  };
50
57
 
58
+ export const governor: Governor = {
59
+ print: printGovernor,
60
+ defaults: governorDefaults,
61
+ isAccessControlRequired: governorIsAccessControlRequired,
62
+ };
63
+
51
64
  export const nonFungible: NonFungible = {
52
65
  print: printNonFungible,
53
66
  defaults: nonFungibledefaults,
@@ -1,5 +1,7 @@
1
1
  import type { FungibleOptions } from './fungible';
2
2
  import { buildFungible } from './fungible';
3
+ import type { GovernorOptions } from './governor';
4
+ import { buildGovernor } from './governor';
3
5
  import type { NonFungibleOptions } from './non-fungible';
4
6
  import { buildNonFungible } from './non-fungible';
5
7
  import type { StablecoinOptions } from './stablecoin';
@@ -7,6 +9,7 @@ import { buildStablecoin } from './stablecoin';
7
9
 
8
10
  export interface KindedOptions {
9
11
  Fungible: { kind: 'Fungible' } & FungibleOptions;
12
+ Governor: { kind: 'Governor' } & GovernorOptions;
10
13
  NonFungible: { kind: 'NonFungible' } & NonFungibleOptions;
11
14
  Stablecoin: { kind: 'Stablecoin' } & StablecoinOptions;
12
15
  }
@@ -18,6 +21,9 @@ export function buildGeneric(opts: GenericOptions) {
18
21
  case 'Fungible':
19
22
  return buildFungible(opts);
20
23
 
24
+ case 'Governor':
25
+ return buildGovernor(opts);
26
+
21
27
  case 'NonFungible':
22
28
  return buildNonFungible(opts);
23
29
 
package/src/contract.ts CHANGED
@@ -10,6 +10,7 @@ export interface Contract {
10
10
  constructorArgs: Argument[];
11
11
  implementedTraits: TraitImplBlock[];
12
12
  freeFunctions: ContractFunction[];
13
+ topLevelDeclarations: string[][];
13
14
  variables: Variable[];
14
15
  errors: Error[];
15
16
  ownable: boolean;
@@ -81,6 +82,7 @@ export class ContractBuilder implements Contract {
81
82
 
82
83
  readonly constructorArgs: Argument[] = [];
83
84
  readonly constructorCode: string[] = [];
85
+ readonly topLevelDeclarations: string[][] = [];
84
86
 
85
87
  private implementedTraitsMap: Map<string, TraitImplBlock> = new Map();
86
88
  private freeFunctionsMap: Map<string, ContractFunction> = new Map();
@@ -250,6 +252,10 @@ export class ContractBuilder implements Contract {
250
252
  existingFn.code = [...code];
251
253
  }
252
254
 
255
+ addTopLevelDeclaration(lines: string[]): void {
256
+ this.topLevelDeclarations.push(lines);
257
+ }
258
+
253
259
  addConstructorArgument(arg: Argument): void {
254
260
  for (const existingArg of this.constructorArgs) {
255
261
  if (existingArg.name == arg.name) {
package/src/fungible.ts CHANGED
@@ -13,10 +13,14 @@ import { printContract } from './print';
13
13
  import { toByteArray, toUint } from './utils/convert-strings';
14
14
  import { pickKeys } from '@openzeppelin/wizard-common';
15
15
 
16
+ const DEFAULT_DECIMALS = 7;
17
+
16
18
  export const defaults: Required<FungibleOptions> = {
17
19
  name: 'MyToken',
18
20
  symbol: 'MTK',
21
+ decimals: DEFAULT_DECIMALS.toString(),
19
22
  burnable: false,
23
+ votes: false,
20
24
  pausable: false,
21
25
  upgradeable: false,
22
26
  premint: '0',
@@ -33,7 +37,9 @@ export function printFungible(opts: FungibleOptions = defaults): string {
33
37
  export interface FungibleOptions extends CommonContractOptions {
34
38
  name: string;
35
39
  symbol: string;
40
+ decimals?: string;
36
41
  burnable?: boolean;
42
+ votes?: boolean;
37
43
  pausable?: boolean;
38
44
  upgradeable?: boolean;
39
45
  premint?: string;
@@ -44,7 +50,9 @@ export function withDefaults(opts: FungibleOptions): Required<FungibleOptions> {
44
50
  return {
45
51
  ...opts,
46
52
  ...withCommonContractDefaults(opts),
53
+ decimals: opts.decimals ?? defaults.decimals,
47
54
  burnable: opts.burnable ?? defaults.burnable,
55
+ votes: opts.votes ?? defaults.votes,
48
56
  pausable: opts.pausable ?? defaults.pausable,
49
57
  upgradeable: opts.upgradeable ?? defaults.upgradeable,
50
58
  premint: opts.premint || defaults.premint,
@@ -61,10 +69,20 @@ export function buildFungible(opts: FungibleOptions): ContractBuilder {
61
69
 
62
70
  const allOpts = withDefaults(opts);
63
71
 
64
- addBase(c, toByteArray(allOpts.name), toByteArray(allOpts.symbol), allOpts.pausable, allOpts.explicitImplementations);
72
+ const decimals = toUint(allOpts.decimals, 'decimals', 'u32');
73
+
74
+ addBase(
75
+ c,
76
+ toByteArray(allOpts.name),
77
+ toByteArray(allOpts.symbol),
78
+ decimals,
79
+ allOpts.votes,
80
+ allOpts.pausable,
81
+ allOpts.explicitImplementations,
82
+ );
65
83
 
66
84
  if (allOpts.premint) {
67
- addPremint(c, allOpts.premint);
85
+ addPremint(c, allOpts.premint, decimals, allOpts.votes);
68
86
  }
69
87
 
70
88
  if (allOpts.pausable) {
@@ -76,11 +94,11 @@ export function buildFungible(opts: FungibleOptions): ContractBuilder {
76
94
  }
77
95
 
78
96
  if (allOpts.burnable) {
79
- addBurnable(c, allOpts.pausable, allOpts.explicitImplementations);
97
+ addBurnable(c, allOpts.votes, allOpts.pausable, allOpts.explicitImplementations);
80
98
  }
81
99
 
82
100
  if (allOpts.mintable) {
83
- addMintable(c, allOpts.access, allOpts.pausable, allOpts.explicitImplementations);
101
+ addMintable(c, allOpts.access, allOpts.votes, allOpts.pausable, allOpts.explicitImplementations);
84
102
  }
85
103
 
86
104
  setAccessControl(c, allOpts.access, allOpts.explicitImplementations);
@@ -93,15 +111,24 @@ function addBase(
93
111
  c: ContractBuilder,
94
112
  name: string,
95
113
  symbol: string,
114
+ decimals: bigint,
115
+ votes: boolean,
96
116
  pausable: boolean,
97
117
  explicitImplementations: boolean,
98
118
  ) {
99
119
  // Set metadata
100
- c.addConstructorCode(`Base::set_metadata(e, 7, String::from_str(e, "${name}"), String::from_str(e, "${symbol}"));`);
120
+ c.addConstructorCode(
121
+ `Base::set_metadata(e, ${decimals}, String::from_str(e, "${name}"), String::from_str(e, "${symbol}"));`,
122
+ );
101
123
 
102
124
  // Set token functions
103
125
  c.addUseClause('stellar_tokens::fungible', 'Base');
104
126
  c.addUseClause('stellar_tokens::fungible', 'FungibleToken');
127
+ if (votes) {
128
+ c.addUseClause('stellar_tokens::fungible', 'ContractOverrides');
129
+ c.addUseClause('stellar_governance::votes', 'Votes');
130
+ c.addUseClause('stellar_tokens::fungible', 'votes::FungibleVotes');
131
+ }
105
132
  c.addUseClause('soroban_sdk', 'contract');
106
133
  c.addUseClause('soroban_sdk', 'contractimpl');
107
134
  c.addUseClause('soroban_sdk', 'String');
@@ -115,7 +142,7 @@ function addBase(
115
142
  traitName: 'FungibleToken',
116
143
  structName: c.name,
117
144
  tags: explicitImplementations ? ['contractimpl'] : ['contractimpl(contracttrait)'],
118
- assocType: 'type ContractType = Base;',
145
+ assocType: `type ContractType = ${votes ? 'FungibleVotes' : 'Base'};`,
119
146
  };
120
147
 
121
148
  c.addTraitImplBlock(fungibleTokenTrait);
@@ -131,29 +158,47 @@ function addBase(
131
158
  c.addTraitFunction(fungibleTokenTrait, functions.transfer_from);
132
159
  c.addFunctionTag(functions.transfer_from, 'when_not_paused', fungibleTokenTrait);
133
160
  }
161
+
162
+ if (votes) {
163
+ c.addTraitImplBlock({
164
+ traitName: 'Votes',
165
+ structName: c.name,
166
+ tags: explicitImplementations ? ['contractimpl'] : ['contractimpl(contracttrait)'],
167
+ section: 'Extensions',
168
+ });
169
+ }
134
170
  }
135
171
 
136
- function addMintable(c: ContractBuilder, access: Access, pausable: boolean, explicitImplementations: boolean) {
172
+ function addMintable(
173
+ c: ContractBuilder,
174
+ access: Access,
175
+ votes: boolean,
176
+ pausable: boolean,
177
+ explicitImplementations: boolean,
178
+ ) {
179
+ const mintFn = votes ? votesFunctions.mint : functions.mint;
180
+ const mintWithCallerFn = votes ? votesFunctions.mint_with_caller : functions.mint_with_caller;
181
+
137
182
  switch (access) {
138
183
  case false:
139
184
  break;
140
185
  case 'ownable': {
141
- c.addFreeFunction(functions.mint);
186
+ c.addFreeFunction(mintFn);
142
187
 
143
- requireAccessControl(c, undefined, functions.mint, access, undefined, explicitImplementations);
188
+ requireAccessControl(c, undefined, mintFn, access, undefined, explicitImplementations);
144
189
 
145
190
  if (pausable) {
146
- c.addFunctionTag(functions.mint, 'when_not_paused');
191
+ c.addFunctionTag(mintFn, 'when_not_paused');
147
192
  }
148
193
  break;
149
194
  }
150
195
  case 'roles': {
151
- c.addFreeFunction(functions.mint_with_caller);
196
+ c.addFreeFunction(mintWithCallerFn);
152
197
 
153
198
  requireAccessControl(
154
199
  c,
155
200
  undefined,
156
- functions.mint_with_caller,
201
+ mintWithCallerFn,
157
202
  access,
158
203
  {
159
204
  useMacro: true,
@@ -164,7 +209,7 @@ function addMintable(c: ContractBuilder, access: Access, pausable: boolean, expl
164
209
  );
165
210
 
166
211
  if (pausable) {
167
- c.addFunctionTag(functions.mint_with_caller, 'when_not_paused');
212
+ c.addFunctionTag(mintWithCallerFn, 'when_not_paused');
168
213
  }
169
214
  break;
170
215
  }
@@ -175,7 +220,7 @@ function addMintable(c: ContractBuilder, access: Access, pausable: boolean, expl
175
220
  }
176
221
  }
177
222
 
178
- function addBurnable(c: ContractBuilder, pausable: boolean, explicitImplementations: boolean) {
223
+ function addBurnable(c: ContractBuilder, votes: boolean, pausable: boolean, explicitImplementations: boolean) {
179
224
  c.addUseClause('stellar_tokens::fungible', 'burnable::FungibleBurnable');
180
225
 
181
226
  const fungibleBurnableTrait = {
@@ -185,23 +230,29 @@ function addBurnable(c: ContractBuilder, pausable: boolean, explicitImplementati
185
230
  section: 'Extensions',
186
231
  };
187
232
 
188
- if (pausable) {
189
- c.addUseClause('stellar_macros', 'when_not_paused');
233
+ const burnFn = votes ? votesFunctions.burn : functions.burn;
234
+ const burnFromFn = votes ? votesFunctions.burn_from : functions.burn_from;
235
+
236
+ if (pausable || votes || explicitImplementations) {
237
+ if (pausable) {
238
+ c.addUseClause('stellar_macros', 'when_not_paused');
239
+ }
190
240
 
191
- c.addTraitFunction(fungibleBurnableTrait, functions.burn);
192
- c.addFunctionTag(functions.burn, 'when_not_paused', fungibleBurnableTrait);
241
+ c.addTraitFunction(fungibleBurnableTrait, burnFn);
242
+ c.addTraitFunction(fungibleBurnableTrait, burnFromFn);
193
243
 
194
- c.addTraitFunction(fungibleBurnableTrait, functions.burn_from);
195
- c.addFunctionTag(functions.burn_from, 'when_not_paused', fungibleBurnableTrait);
196
- } else if (explicitImplementations) c.addTraitForEachFunctions(fungibleBurnableTrait, fungibleBurnableFunctions);
197
- else {
244
+ if (pausable) {
245
+ c.addFunctionTag(burnFn, 'when_not_paused', fungibleBurnableTrait);
246
+ c.addFunctionTag(burnFromFn, 'when_not_paused', fungibleBurnableTrait);
247
+ }
248
+ } else {
198
249
  c.addTraitImplBlock(fungibleBurnableTrait);
199
250
  }
200
251
  }
201
252
 
202
253
  export const premintPattern = /^(\d*\.?\d*)$/;
203
254
 
204
- function addPremint(c: ContractBuilder, amount: string) {
255
+ function addPremint(c: ContractBuilder, amount: string, decimals: bigint, votes: boolean) {
205
256
  if (amount !== undefined && amount !== '0') {
206
257
  if (!premintPattern.test(amount)) {
207
258
  throw new OptionsError({
@@ -210,10 +261,10 @@ function addPremint(c: ContractBuilder, amount: string) {
210
261
  }
211
262
 
212
263
  // TODO: handle signed int?
213
- const premintAbsolute = toUint(getInitialSupply(amount, 7), 'premint', 'u128');
264
+ const premintAbsolute = toUint(getInitialSupply(amount, Number(decimals)), 'premint', 'u128');
214
265
 
215
266
  c.addConstructorArgument({ name: 'recipient', type: 'Address' });
216
- c.addConstructorCode(`Base::mint(e, &recipient, ${premintAbsolute});`);
267
+ c.addConstructorCode(`${votes ? 'FungibleVotes' : 'Base'}::mint(e, &recipient, ${premintAbsolute});`);
217
268
  }
218
269
  }
219
270
 
@@ -350,6 +401,36 @@ export const functions = defineFunctions({
350
401
  },
351
402
  });
352
403
 
404
+ const votesFunctions = defineFunctions({
405
+ burn: {
406
+ args: [getSelfArg(), { name: 'from', type: 'Address' }, { name: 'amount', type: 'i128' }],
407
+ code: ['FungibleVotes::burn(e, &from, amount)'],
408
+ },
409
+ burn_from: {
410
+ args: [
411
+ getSelfArg(),
412
+ { name: 'spender', type: 'Address' },
413
+ { name: 'from', type: 'Address' },
414
+ { name: 'amount', type: 'i128' },
415
+ ],
416
+ code: ['FungibleVotes::burn_from(e, &spender, &from, amount)'],
417
+ },
418
+ mint: {
419
+ args: [getSelfArg(), { name: 'account', type: 'Address' }, { name: 'amount', type: 'i128' }],
420
+ code: ['FungibleVotes::mint(e, &account, amount);'],
421
+ },
422
+ mint_with_caller: {
423
+ name: 'mint',
424
+ args: [
425
+ getSelfArg(),
426
+ { name: 'account', type: 'Address' },
427
+ { name: 'amount', type: 'i128' },
428
+ { name: 'caller', type: 'Address' },
429
+ ],
430
+ code: ['FungibleVotes::mint(e, &account, amount);'],
431
+ },
432
+ });
433
+
353
434
  const fungibleTokenTraitFunctions = pickKeys(functions, [
354
435
  'total_supply',
355
436
  'balance',
@@ -361,5 +442,3 @@ const fungibleTokenTraitFunctions = pickKeys(functions, [
361
442
  'name',
362
443
  'symbol',
363
444
  ]);
364
-
365
- const fungibleBurnableFunctions = pickKeys(functions, ['burn', 'burn_from']);
@@ -8,7 +8,9 @@ const booleans = [true, false];
8
8
  const blueprint = {
9
9
  name: ['MyToken'],
10
10
  symbol: ['MTK'],
11
+ decimals: ['7', '18'],
11
12
  burnable: booleans,
13
+ votes: booleans,
12
14
  pausable: booleans,
13
15
  upgradeable: booleans,
14
16
  mintable: booleans,
@@ -0,0 +1,24 @@
1
+ import type { GovernorOptions } from '../governor';
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: ['MyGovernor'],
10
+ version: ['1.0.0'],
11
+ votingDelay: ['10'],
12
+ votingPeriod: ['100'],
13
+ proposalThreshold: ['100'],
14
+ quorum: ['500'],
15
+ upgradeable: booleans,
16
+ timelock: booleans,
17
+ access: accessOptions,
18
+ info: infoOptions,
19
+ explicitImplementations: booleans,
20
+ };
21
+
22
+ export function* generateGovernorOptions(): Generator<Required<GovernorOptions>> {
23
+ yield* generateAlternatives(blueprint);
24
+ }
@@ -10,6 +10,7 @@ const blueprint = {
10
10
  symbol: ['MTK'],
11
11
  tokenUri: ['https://www.mytoken.com'],
12
12
  burnable: booleans,
13
+ votes: booleans,
13
14
  pausable: booleans,
14
15
  upgradeable: booleans,
15
16
  enumerable: booleans,
@@ -3,6 +3,7 @@ import path from 'path';
3
3
  import crypto from 'crypto';
4
4
 
5
5
  import { generateFungibleOptions } from './fungible';
6
+ import { generateGovernorOptions } from './governor';
6
7
  import { generateNonFungibleOptions } from './non-fungible';
7
8
  import { generateStablecoinOptions } from './stablecoin';
8
9
  import type { GenericOptions, KindedOptions } from '../build-generic';
@@ -20,6 +21,12 @@ export function* generateOptions(kind?: Kind): Generator<GenericOptions> {
20
21
  }
21
22
  }
22
23
 
24
+ if (!kind || kind === 'Governor') {
25
+ for (const kindOpts of generateGovernorOptions()) {
26
+ yield { kind: 'Governor', ...kindOpts };
27
+ }
28
+ }
29
+
23
30
  if (!kind || kind === 'NonFungible') {
24
31
  for (const kindOpts of generateNonFungibleOptions()) {
25
32
  yield { kind: 'NonFungible', ...kindOpts };
@@ -8,7 +8,9 @@ const booleans = [true, false];
8
8
  const blueprint = {
9
9
  name: ['MyStablecoin'],
10
10
  symbol: ['MST'],
11
+ decimals: ['7', '18'],
11
12
  burnable: booleans,
13
+ votes: booleans,
12
14
  pausable: booleans,
13
15
  upgradeable: booleans,
14
16
  mintable: booleans,