@openzeppelin/wizard-stellar 0.2.1 → 0.2.3

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip-scaffold.js","sourceRoot":"","sources":["../src/zip-scaffold.ts"],"names":[],"mappings":";;;;;AAmQA,kCAaC;AAhRD,kDAA0B;AAG1B,mCAAqE;AACrE,6CAAgF;AAChF,6CAOsB;AAEtB,SAAS,cAAc,CAAC,CAAW;IACjC,OAAO,CAAC,CAAC,eAAe;SACrB,MAAM,CAAC,cAAc,CAAC,EAAE,WAAC,OAAA,CAAA,MAAA,cAAc,CAAC,IAAI,0CAAE,WAAW,EAAE,MAAK,SAAS,CAAA,EAAA,CAAC;SAC1E,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,OAAO,GAAG,CAAC,CAAW,EAAE,IAAoB,EAAE,oBAA4B,EAAE,EAAE;IAClF,MAAM,sBAAsB,GAAG,CAAC,aAAuB,EAAE,yBAAiC,EAAE,EAAE,CAAC;;;;;;;;;;;;+CAYlD,yBAAyB;;;;;;UAO9D,aAAa,CAAC,eAAe,CAAC,MAAM;QAClC,CAAC,CAAC,mBAAmB;YACnB;;WAEH,aAAa,CAAC,eAAe,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,WAAC,OAAA,KAAK,cAAc,CAAC,IAAI,WAAW,cAAc,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAA,MAAA,cAAc,CAAC,IAAI,0CAAE,iBAAiB,EAAE,KAAI,UAAU,UAAU,CAAA,EAAA,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;;WAE7M;QACC,CAAC,CAAC,IACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6CP,CAAC;IAEA,MAAM,oBAAoB,GAAG;;;;EAI7B,IAAA,gCAAmB,EAAC,uEAAuE,6BAAmB,KAAK,EAAE,mCAAsB,CAAC,GAAG,IAAA,gCAAmB,EAAC,gBAAgB,kCAAwB,KAAK,EAAE,CAAC,SAAS,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4B9N,CAAC;IAED,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCP,sBAAsB,CAAC,CAAC,EAAE,oBAAoB,CAAC;;EAE/C,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CrB,CAAC;AACF,CAAC,CAAC;AAEF,MAAM,MAAM,GAAG,CAAC,CAAW,EAAE,EAAE;IAC7B,MAAM,iBAAiB,GAAG,CAAC,CAAW,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAExE,OAAO;;;;;;;;;;;;;;;;;;EAkBP,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,oIAAoI,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;CAmBjK,CAAC;AACF,CAAC,CAAC;AAEK,KAAK,UAAU,WAAW,CAAC,CAAW,EAAE,IAAoB;IACjE,MAAM,GAAG,GAAG,IAAI,eAAK,EAAE,CAAC;IAExB,MAAM,oBAAoB,GAAG,IAAA,0CAA6B,EAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,IAAI,KAAI,UAAU,CAAC,CAAC;IAErF,GAAG,CAAC,IAAI,CAAC,aAAa,oBAAoB,kBAAkB,EAAE,IAAA,mCAA2B,EAAC,IAAA,qBAAa,EAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7G,GAAG,CAAC,IAAI,CAAC,aAAa,oBAAoB,cAAc,EAAE,IAAA,8BAAiB,EAAC,CAAC,CAAC,CAAC,CAAC;IAChF,GAAG,CAAC,IAAI,CAAC,aAAa,oBAAoB,aAAa,EAAE,8BAAiB,CAAC,CAAC;IAC5E,GAAG,CAAC,IAAI,CAAC,aAAa,oBAAoB,aAAa,EAAE,IAAA,+BAAkB,EAAC,oBAAoB,CAAC,CAAC,CAAC;IACnG,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAC7D,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAExC,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { Contract } from './contract';
2
+ declare function pascalToSnakeCase(string: string): string;
3
+ export declare const contractOptionsToContractName: typeof pascalToSnakeCase;
4
+ export declare function getAddressArgs(c: Pick<Contract, 'constructorArgs'>): string[];
5
+ export declare const printRustNameTest: (c: Pick<Contract, "constructorArgs" | "name">) => string;
6
+ export declare const stellarDependencies: {
7
+ readonly base: readonly ["stellar-default-impl-macro"];
8
+ readonly fungible: readonly ["stellar-fungible"];
9
+ readonly nonFungible: readonly ["stellar-non-fungible"];
10
+ readonly pausable: readonly ["stellar-pausable", "stellar-pausable-macros"];
11
+ readonly upgradable: readonly ["stellar-upgradeable", "stellar-upgradeable-macros"];
12
+ };
13
+ export declare const allStellarDependencies: ("pausable" | "fungible" | "base" | "nonFungible" | "upgradable")[];
14
+ export declare const allDependencies: {
15
+ readonly soroban: readonly ["soroban-sdk"];
16
+ readonly base: readonly ["stellar-default-impl-macro"];
17
+ readonly fungible: readonly ["stellar-fungible"];
18
+ readonly nonFungible: readonly ["stellar-non-fungible"];
19
+ readonly pausable: readonly ["stellar-pausable", "stellar-pausable-macros"];
20
+ readonly upgradable: readonly ["stellar-upgradeable", "stellar-upgradeable-macros"];
21
+ };
22
+ export declare const addDependenciesWith: (dependencyValue: string, dependenciesToAdd: (keyof typeof allDependencies)[]) => string;
23
+ export declare const printContractCargo: (scaffoldContractName: string) => string;
24
+ export declare const createRustLibFile = "#![no_std]\n#![allow(dead_code)]\n\nmod contract;\nmod test;\n";
25
+ export {};
26
+ //# sourceMappingURL=zip-shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip-shared.d.ts","sourceRoot":"","sources":["../src/zip-shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,iBAAS,iBAAiB,CAAC,MAAM,EAAE,MAAM,UAKxC;AAED,eAAO,MAAM,6BAA6B,0BAAoB,CAAC;AAE/D,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,iBAAiB,CAAC,GAAG,MAAM,EAAE,CAI7E;AAED,eAAO,MAAM,iBAAiB,MAAO,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAAC,WAqB9E,CAAC;AAKF,eAAO,MAAM,mBAAmB;;;;;;CAMtB,CAAC;AAEX,eAAO,MAAM,sBAAsB,qEAAiC,CAAC;AAErE,eAAO,MAAM,eAAe;;;;;;;CAGlB,CAAC;AAEX,eAAO,MAAM,mBAAmB,oBAAqB,MAAM,qBAAqB,CAAC,MAAM,OAAO,eAAe,CAAC,EAAE,WAGxG,CAAC;AAET,eAAO,MAAM,kBAAkB,yBAA0B,MAAM,WAcuB,CAAC;AAEvF,eAAO,MAAM,iBAAiB,mEAK7B,CAAC"}
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRustLibFile = exports.printContractCargo = exports.addDependenciesWith = exports.allDependencies = exports.allStellarDependencies = exports.stellarDependencies = exports.printRustNameTest = exports.contractOptionsToContractName = void 0;
4
+ exports.getAddressArgs = getAddressArgs;
5
+ function pascalToSnakeCase(string) {
6
+ return string
7
+ .replace(/([A-Z])/g, '_$1')
8
+ .replace(/^_/, '')
9
+ .toLowerCase();
10
+ }
11
+ exports.contractOptionsToContractName = pascalToSnakeCase;
12
+ function getAddressArgs(c) {
13
+ return (c.constructorArgs || [])
14
+ .filter(constructorArg => { var _a; return ((_a = constructorArg.type) === null || _a === void 0 ? void 0 : _a.trim()) === 'Address'; })
15
+ .map(constructorArg => constructorArg.name);
16
+ }
17
+ const printRustNameTest = (c) => `#![cfg(test)]
18
+
19
+ extern crate std;
20
+
21
+ use soroban_sdk::{ ${getAddressArgs(c).length ? 'testutils::Address as _, Address, ' : ''}Env, String };
22
+
23
+ use crate::contract::{ ${c.name}, ${c.name}Client };
24
+
25
+ #[test]
26
+ fn initial_state() {
27
+ let env = Env::default();
28
+
29
+ let contract_addr = env.register(${c.name}, (${getAddressArgs(c)
30
+ .map(() => 'Address::generate(&env)')
31
+ .join(',')}${getAddressArgs(c).length === 1 ? ',' : ''}));
32
+ let client = ${c.name}Client::new(&env, &contract_addr);
33
+
34
+ assert_eq!(client.name(), String::from_str(&env, "${c.name}"));
35
+ }
36
+
37
+ // Add more tests bellow
38
+ `;
39
+ exports.printRustNameTest = printRustNameTest;
40
+ const getKeysOf = (objectToGetKeysOf) => Object.keys(objectToGetKeysOf);
41
+ exports.stellarDependencies = {
42
+ base: ['stellar-default-impl-macro'],
43
+ fungible: ['stellar-fungible'],
44
+ nonFungible: ['stellar-non-fungible'],
45
+ pausable: ['stellar-pausable', 'stellar-pausable-macros'],
46
+ upgradable: ['stellar-upgradeable', 'stellar-upgradeable-macros'],
47
+ };
48
+ exports.allStellarDependencies = getKeysOf(exports.stellarDependencies);
49
+ exports.allDependencies = {
50
+ ...exports.stellarDependencies,
51
+ soroban: ['soroban-sdk'],
52
+ };
53
+ const addDependenciesWith = (dependencyValue, dependenciesToAdd) => dependenciesToAdd.reduce((addedDependency, dependencyName) => {
54
+ return `${addedDependency}${exports.allDependencies[dependencyName].map(cargoDependencies => `${cargoDependencies} = ${dependencyValue}\n`).join('')}`;
55
+ }, '');
56
+ exports.addDependenciesWith = addDependenciesWith;
57
+ const printContractCargo = (scaffoldContractName) => `[package]
58
+ name = "${scaffoldContractName.replace(/_/, '-')}-contract"
59
+ edition.workspace = true
60
+ license.workspace = true
61
+ publish = false
62
+ version.workspace = true
63
+
64
+ [lib]
65
+ crate-type = ["cdylib"]
66
+ doctest = false
67
+
68
+ [dependencies]
69
+ ${(0, exports.addDependenciesWith)('{ workspace = true }', [...exports.allStellarDependencies, 'soroban'])}
70
+ [dev-dependencies]
71
+ ${(0, exports.addDependenciesWith)('{ workspace = true, features = ["testutils"] }', ['soroban'])}`;
72
+ exports.printContractCargo = printContractCargo;
73
+ exports.createRustLibFile = `#![no_std]
74
+ #![allow(dead_code)]
75
+
76
+ mod contract;
77
+ mod test;
78
+ `;
79
+ //# sourceMappingURL=zip-shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip-shared.js","sourceRoot":"","sources":["../src/zip-shared.ts"],"names":[],"mappings":";;;AAWA,wCAIC;AAbD,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,WAAC,OAAA,CAAA,MAAA,cAAc,CAAC,IAAI,0CAAE,IAAI,EAAE,MAAK,SAAS,CAAA,EAAA,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;AAEF,MAAM,SAAS,GAAG,CAA0C,iBAA0B,EAAE,EAAE,CACxF,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAsB,CAAC;AAEzC,QAAA,mBAAmB,GAAG;IACjC,IAAI,EAAE,CAAC,4BAA4B,CAAC;IACpC,QAAQ,EAAE,CAAC,kBAAkB,CAAC;IAC9B,WAAW,EAAE,CAAC,sBAAsB,CAAC;IACrC,QAAQ,EAAE,CAAC,kBAAkB,EAAE,yBAAyB,CAAC;IACzD,UAAU,EAAE,CAAC,qBAAqB,EAAE,4BAA4B,CAAC;CACzD,CAAC;AAEE,QAAA,sBAAsB,GAAG,SAAS,CAAC,2BAAmB,CAAC,CAAC;AAExD,QAAA,eAAe,GAAG;IAC7B,GAAG,2BAAmB;IACtB,OAAO,EAAE,CAAC,aAAa,CAAC;CAChB,CAAC;AAEJ,MAAM,mBAAmB,GAAG,CAAC,eAAuB,EAAE,iBAAmD,EAAE,EAAE,CAClH,iBAAiB,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,cAAc,EAAE,EAAE;IAC3D,OAAO,GAAG,eAAe,GAAG,uBAAe,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC,GAAG,iBAAiB,MAAM,eAAe,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AACjJ,CAAC,EAAE,EAAE,CAAC,CAAC;AAHI,QAAA,mBAAmB,uBAGvB;AAEF,MAAM,kBAAkB,GAAG,CAAC,oBAA4B,EAAE,EAAE,CAAC;UAC1D,oBAAoB,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC;;;;;;;;;;;EAW9C,IAAA,2BAAmB,EAAC,sBAAsB,EAAE,CAAC,GAAG,8BAAsB,EAAE,SAAS,CAAC,CAAC;;EAEnF,IAAA,2BAAmB,EAAC,gDAAgD,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;AAd1E,QAAA,kBAAkB,sBAcwD;AAE1E,QAAA,iBAAiB,GAAG;;;;;CAKhC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openzeppelin/wizard-stellar",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
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",
package/src/contract.ts CHANGED
@@ -2,6 +2,8 @@ import { toIdentifier } from './utils/convert-strings';
2
2
 
3
3
  export interface Contract {
4
4
  license: string;
5
+ securityContact: string;
6
+ documentations: string[];
5
7
  name: string;
6
8
  useClauses: UseClause[];
7
9
  constructorCode: string[];
@@ -72,8 +74,11 @@ export interface Argument {
72
74
  export class ContractBuilder implements Contract {
73
75
  readonly name: string;
74
76
  license = 'MIT';
77
+ securityContact = '';
75
78
  ownable = false;
76
79
 
80
+ readonly documentations: string[] = [];
81
+
77
82
  readonly constructorArgs: Argument[] = [];
78
83
  readonly constructorCode: string[] = [];
79
84
 
@@ -250,4 +255,12 @@ export class ContractBuilder implements Contract {
250
255
  addDerives(derive: string): void {
251
256
  this.derivesSet.add(derive);
252
257
  }
258
+
259
+ addDocumentation(description: string) {
260
+ this.documentations.push(description);
261
+ }
262
+
263
+ addSecurityTag(securityContact: string) {
264
+ this.securityContact = securityContact;
265
+ }
253
266
  }
package/src/index.ts CHANGED
@@ -23,3 +23,6 @@ export { contractsVersion, contractsVersionTag, compatibleContractsSemver } from
23
23
 
24
24
  export { fungible } from './api';
25
25
  export { nonFungible } from './api';
26
+
27
+ export type { FungibleOptions } from './fungible';
28
+ export type { NonFungibleOptions } from './non-fungible';
package/src/print.ts CHANGED
@@ -9,6 +9,13 @@ const DEFAULT_SECTION = '1. with no section';
9
9
  const STANDALONE_IMPORTS_GROUP = 'Standalone Imports';
10
10
  const MAX_USE_CLAUSE_LINE_LENGTH = 90;
11
11
  const TAB = ' ';
12
+ export const createLevelAttributes = [`#![no_std]`];
13
+
14
+ export const removeCreateLevelAttributes = (printedContract: string) =>
15
+ createLevelAttributes.reduce(
16
+ (cleanedPrintedContract, createLevelAttribute) => cleanedPrintedContract.replace(createLevelAttribute, ''),
17
+ printedContract,
18
+ );
12
19
 
13
20
  export function printContract(contract: Contract): string {
14
21
  return formatLines(
@@ -16,7 +23,9 @@ export function printContract(contract: Contract): string {
16
23
  [
17
24
  `// SPDX-License-Identifier: ${contract.license}`,
18
25
  `// Compatible with OpenZeppelin Stellar Soroban Contracts ${compatibleContractsSemver}`,
19
- `#![no_std]`,
26
+ ...(contract.documentations.length ? ['', ...printDocumentations(contract.documentations)] : []),
27
+ ...(contract.securityContact ? ['', ...printSecurityTag(contract.securityContact)] : []),
28
+ ...createLevelAttributes,
20
29
  ],
21
30
  spaceBetween(
22
31
  printUseClauses(contract),
@@ -353,3 +362,11 @@ function printArgument(arg: Argument): string {
353
362
  return `${arg.name}`;
354
363
  }
355
364
  }
365
+
366
+ function printDocumentations(documentations: string[]): string[] {
367
+ return documentations.map(documentation => `//! ${documentation}`);
368
+ }
369
+
370
+ function printSecurityTag(securityContact: string) {
371
+ return ['//! # Security', '//!', `//! For security issues, please contact: ${securityContact}`];
372
+ }
package/src/set-info.ts CHANGED
@@ -1,15 +1,22 @@
1
1
  import type { ContractBuilder } from './contract';
2
2
 
3
+ export const TAG_SECURITY_CONTACT = `@custom:security-contact`;
4
+
3
5
  export const infoOptions = [{}, { license: 'WTFPL' }] as const;
4
6
 
5
7
  export const defaults: Info = { license: 'MIT' };
6
8
 
7
9
  export type Info = {
8
10
  license?: string;
11
+ securityContact?: string;
9
12
  };
10
13
 
11
14
  export function setInfo(c: ContractBuilder, info: Info): void {
12
- const { license } = info;
15
+ const { securityContact, license } = info;
16
+
17
+ if (securityContact) {
18
+ c.addSecurityTag(securityContact);
19
+ }
13
20
 
14
21
  if (license) {
15
22
  c.license = license;
@@ -8,3 +8,8 @@ export const contractsVersionTag = `v${contractsVersion}`;
8
8
  * Semantic version string representing of the minimum compatible version of Contracts to display in output.
9
9
  */
10
10
  export const compatibleContractsSemver = '^0.2.0';
11
+
12
+ /**
13
+ * The Soroban version for which compilation and testing have passing tests
14
+ */
15
+ export const compatibleSorobanVersion = '22.0.8';
@@ -0,0 +1,57 @@
1
+ import JSZip from 'jszip';
2
+ import type { GenericOptions } from './build-generic';
3
+ import type { Contract } from './contract';
4
+ import { printContract, removeCreateLevelAttributes } from './print';
5
+ import {
6
+ addDependenciesWith,
7
+ allStellarDependencies,
8
+ contractOptionsToContractName,
9
+ createRustLibFile,
10
+ printContractCargo,
11
+ printRustNameTest,
12
+ } from './zip-shared';
13
+ import { contractsVersionTag, compatibleSorobanVersion } from './utils/version';
14
+
15
+ const workspaceCargo = `[workspace]
16
+ resolver = "2"
17
+ members = ["contracts/*"]
18
+
19
+ [workspace.package]
20
+ authors = []
21
+ edition = "2021"
22
+ license = "Apache-2.0"
23
+ version = "0.0.1"
24
+
25
+ [workspace.dependencies]
26
+ ${addDependenciesWith(`{ git = "https://github.com/OpenZeppelin/stellar-contracts", tag = "${contractsVersionTag}" }`, allStellarDependencies)}${addDependenciesWith(`{ version = "${compatibleSorobanVersion}" }`, ['soroban'])}
27
+ `;
28
+
29
+ const readme = `\
30
+ # Sample Rust Contract Environment
31
+
32
+ This project demonstrates a basic Rust contract environment use case. It comes with a contract generated by [OpenZeppelin Wizard](https://wizard.openzeppelin.com/) and a test for that contract. Make sure you have the required dependencies and keep building!
33
+
34
+ ## Go further
35
+
36
+ Continue your development journey with [Stellar CLI](https://github.com/stellar/stellar-cli).
37
+
38
+ ## Installing dependencies
39
+
40
+ - See [Rust and Stellar installation guide](https://developers.stellar.org/docs/build/smart-contracts/getting-started/setup).
41
+ - See [Git installation guide](https://github.com/git-guides/install-git).
42
+ `;
43
+
44
+ export async function zipRust(c: Contract, opts: GenericOptions) {
45
+ const zip = new JSZip();
46
+
47
+ const contractName = contractOptionsToContractName(opts?.kind || 'contract');
48
+
49
+ zip.file(`contracts/${contractName}/src/contract.rs`, removeCreateLevelAttributes(printContract(c)));
50
+ zip.file(`contracts/${contractName}/src/test.rs`, printRustNameTest(c));
51
+ zip.file(`contracts/${contractName}/src/lib.rs`, createRustLibFile);
52
+ zip.file(`contracts/${contractName}/Cargo.toml`, printContractCargo(contractName));
53
+ zip.file('Cargo.toml', workspaceCargo);
54
+ zip.file('README.md', readme);
55
+
56
+ return zip;
57
+ }
@@ -0,0 +1,273 @@
1
+ import JSZip from 'jszip';
2
+ import type { GenericOptions } from './build-generic';
3
+ import type { Contract } from './contract';
4
+ import { printContract, removeCreateLevelAttributes } from './print';
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';
14
+
15
+ function getAddressArgs(c: Contract): string[] {
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 `\
131
+ #!/usr/bin/env bash
132
+ #
133
+ # setup.sh
134
+ #
135
+ # This script is meant to set up a Scaffold project and insert the Wizard's contracts in the project
136
+
137
+ check_is_installed() {
138
+ if ! which "$1" &> /dev/null; then
139
+ echo "❌ $1 command not found."
140
+ echo "Install $2 and try again, you can find installation guides in the README."
141
+ exit 1
142
+ fi
143
+ }
144
+
145
+ scaffold() {
146
+ tmp_folder="tmp"
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"
158
+ }
159
+
160
+ init_git(){
161
+ git init
162
+ git add .
163
+ git commit -m "openzeppelin: add wizard output" --quiet
164
+ }
165
+
166
+ ${environmentsFileUpdate(c, scaffoldContractName)}
167
+
168
+ ${updateWorkspaceCargo}
169
+
170
+ build_contracts() {
171
+ cargo build
172
+ }
173
+
174
+ install_npm_dependencies() {
175
+ if ! npm install --silent; then
176
+ echo "❌ Failed to set up the project."
177
+ exit 1
178
+ fi
179
+ }
180
+
181
+
182
+ ################
183
+ ##### Start ####
184
+ ################
185
+
186
+ echo "⚙️ Checking dependencies requirement"
187
+ check_is_installed git "Git"
188
+ check_is_installed cargo "Rust"
189
+ check_is_installed stellar "Scaffold"
190
+ check_is_installed docker "Docker"
191
+ check_is_installed node "Node"
192
+
193
+
194
+ if ! [ -f "environments.toml" ]
195
+ then
196
+ echo "🏗️ Building Scaffold project"
197
+
198
+ scaffold
199
+
200
+ setup_environment
201
+
202
+ update_cargo
203
+
204
+ build_contracts
205
+
206
+ install_npm_dependencies
207
+
208
+ init_git
209
+
210
+ echo "✅ Installation complete"
211
+ else
212
+ echo "✅ Scaffold project already initialized."
213
+ fi
214
+ `;
215
+ };
216
+
217
+ const readme = (c: Contract) => {
218
+ const hasTodosToResolve = (c: Contract) => getAddressArgs(c).length > 0;
219
+
220
+ return `\
221
+ # Sample Scaffold Project
222
+
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 initiate 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
+
225
+ ## Installing dependencies
226
+
227
+ - See [Git installation guide](https://github.com/git-guides/install-git).
228
+ - See [Rust and Stellar installation guide](https://developers.stellar.org/docs/build/smart-contracts/getting-started/setup).
229
+ - See [Scaffold CLI installation guide](https://github.com/AhaLabs/scaffold-stellar?tab=readme-ov-file#quick-start).
230
+ - See [Docker installation guide](https://docs.docker.com/engine/install/).
231
+ - See [Node installation guide](https://nodejs.org/en/download).
232
+
233
+ ## Initializing the project
234
+
235
+ \`\`\`
236
+ bash setup.sh
237
+ \`\`\`
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
+
240
+ ## Testing the contract
241
+
242
+ \`\`\`
243
+ cargo test
244
+ \`\`\`
245
+
246
+ ## Deploying the contract
247
+
248
+ \`\`\`
249
+ stellar scaffold watch --build-clients
250
+ \`\`\`
251
+
252
+ ## Deploying the contract and run the Scaffold UI app
253
+
254
+ \`\`\`
255
+ npm run dev
256
+ \`\`\`
257
+ `;
258
+ };
259
+
260
+ export async function zipScaffold(c: Contract, opts: GenericOptions) {
261
+ const zip = new JSZip();
262
+
263
+ const scaffoldContractName = contractOptionsToContractName(opts?.kind || 'contract');
264
+
265
+ zip.file(`contracts/${scaffoldContractName}/src/contract.rs`, removeCreateLevelAttributes(printContract(c)));
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));
271
+
272
+ return zip;
273
+ }
@@ -0,0 +1,85 @@
1
+ import type { Contract } from './contract';
2
+
3
+ function pascalToSnakeCase(string: string) {
4
+ return string
5
+ .replace(/([A-Z])/g, '_$1')
6
+ .replace(/^_/, '')
7
+ .toLowerCase();
8
+ }
9
+
10
+ export const contractOptionsToContractName = pascalToSnakeCase;
11
+
12
+ export function getAddressArgs(c: Pick<Contract, 'constructorArgs'>): string[] {
13
+ return (c.constructorArgs || [])
14
+ .filter(constructorArg => constructorArg.type?.trim() === 'Address')
15
+ .map(constructorArg => constructorArg.name);
16
+ }
17
+
18
+ export const printRustNameTest = (c: Pick<Contract, 'constructorArgs' | 'name'>) => `#![cfg(test)]
19
+
20
+ extern crate std;
21
+
22
+ use soroban_sdk::{ ${getAddressArgs(c).length ? 'testutils::Address as _, Address, ' : ''}Env, String };
23
+
24
+ use crate::contract::{ ${c.name}, ${c.name}Client };
25
+
26
+ #[test]
27
+ fn initial_state() {
28
+ let env = Env::default();
29
+
30
+ let contract_addr = env.register(${c.name}, (${getAddressArgs(c)
31
+ .map(() => 'Address::generate(&env)')
32
+ .join(',')}${getAddressArgs(c).length === 1 ? ',' : ''}));
33
+ let client = ${c.name}Client::new(&env, &contract_addr);
34
+
35
+ assert_eq!(client.name(), String::from_str(&env, "${c.name}"));
36
+ }
37
+
38
+ // Add more tests bellow
39
+ `;
40
+
41
+ const getKeysOf = <TObject extends Record<string, unknown>>(objectToGetKeysOf: TObject) =>
42
+ Object.keys(objectToGetKeysOf) as (keyof TObject)[];
43
+
44
+ export const stellarDependencies = {
45
+ base: ['stellar-default-impl-macro'],
46
+ fungible: ['stellar-fungible'],
47
+ nonFungible: ['stellar-non-fungible'],
48
+ pausable: ['stellar-pausable', 'stellar-pausable-macros'],
49
+ upgradable: ['stellar-upgradeable', 'stellar-upgradeable-macros'],
50
+ } as const;
51
+
52
+ export const allStellarDependencies = getKeysOf(stellarDependencies);
53
+
54
+ export const allDependencies = {
55
+ ...stellarDependencies,
56
+ soroban: ['soroban-sdk'],
57
+ } as const;
58
+
59
+ export const addDependenciesWith = (dependencyValue: string, dependenciesToAdd: (keyof typeof allDependencies)[]) =>
60
+ dependenciesToAdd.reduce((addedDependency, dependencyName) => {
61
+ return `${addedDependency}${allDependencies[dependencyName].map(cargoDependencies => `${cargoDependencies} = ${dependencyValue}\n`).join('')}`;
62
+ }, '');
63
+
64
+ export const printContractCargo = (scaffoldContractName: string) => `[package]
65
+ name = "${scaffoldContractName.replace(/_/, '-')}-contract"
66
+ edition.workspace = true
67
+ license.workspace = true
68
+ publish = false
69
+ version.workspace = true
70
+
71
+ [lib]
72
+ crate-type = ["cdylib"]
73
+ doctest = false
74
+
75
+ [dependencies]
76
+ ${addDependenciesWith('{ workspace = true }', [...allStellarDependencies, 'soroban'])}
77
+ [dev-dependencies]
78
+ ${addDependenciesWith('{ workspace = true, features = ["testutils"] }', ['soroban'])}`;
79
+
80
+ export const createRustLibFile = `#![no_std]
81
+ #![allow(dead_code)]
82
+
83
+ mod contract;
84
+ mod test;
85
+ `;