@clarigen/cli 0.3.6 → 1.0.0-next.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.
@@ -4,21 +4,22 @@ exports.getClarinetAccounts = exports.sortClarinetContracts = exports.getContrac
4
4
  const j_toml_1 = require("@ltd/j-toml");
5
5
  const path_1 = require("path");
6
6
  const promises_1 = require("fs/promises");
7
- const wallet_sdk_1 = require("@stacks/wallet-sdk");
7
+ const wallet_sdk_1 = require("micro-stacks/wallet-sdk");
8
8
  const toposort_1 = require("toposort");
9
+ const crypto_1 = require("micro-stacks/crypto");
9
10
  async function getClarinetDevConfig(folder) {
10
- const baseConfigPath = path_1.resolve(folder, 'settings', 'Devnet.toml');
11
- const configContents = await promises_1.readFile(baseConfigPath, { encoding: 'utf-8' });
12
- const config = j_toml_1.parse(configContents, 1.0, '\n', true, {
11
+ const baseConfigPath = (0, path_1.resolve)(folder, 'settings', 'Devnet.toml');
12
+ const configContents = await (0, promises_1.readFile)(baseConfigPath, { encoding: 'utf-8' });
13
+ const config = (0, j_toml_1.parse)(configContents, 1.0, '\n', true, {
13
14
  longer: true,
14
15
  });
15
16
  return config;
16
17
  }
17
18
  exports.getClarinetDevConfig = getClarinetDevConfig;
18
19
  async function getClarinetConfig(folder) {
19
- const baseConfigPath = path_1.resolve(folder, 'Clarinet.toml');
20
- const configContents = await promises_1.readFile(baseConfigPath, { encoding: 'utf-8' });
21
- const config = j_toml_1.parse(configContents, 1.0, '\n', true);
20
+ const baseConfigPath = (0, path_1.resolve)(folder, 'Clarinet.toml');
21
+ const configContents = await (0, promises_1.readFile)(baseConfigPath, { encoding: 'utf-8' });
22
+ const config = (0, j_toml_1.parse)(configContents, 1.0, '\n', true);
22
23
  return config;
23
24
  }
24
25
  exports.getClarinetConfig = getClarinetConfig;
@@ -26,12 +27,13 @@ async function getContractsFromClarinet(folder, accounts) {
26
27
  const clarinetConfig = await getClarinetConfig(folder);
27
28
  const deployerAddress = accounts.deployer.address;
28
29
  const sortedContracts = sortClarinetContracts(clarinetConfig.contracts);
29
- const contracts = sortedContracts.map(contractName => {
30
+ const contracts = sortedContracts.map((contractName) => {
30
31
  const info = clarinetConfig.contracts[contractName];
31
32
  const file = info.path.replace(/^contracts\//, '');
32
33
  return {
33
34
  file,
34
35
  address: deployerAddress,
36
+ name: contractName,
35
37
  };
36
38
  });
37
39
  return contracts;
@@ -44,19 +46,16 @@ function sortClarinetContracts(contractsConfig) {
44
46
  nodes.push(contractName);
45
47
  info.depends_on.forEach((dependency) => edges.push([contractName, dependency]));
46
48
  });
47
- const sorted = toposort_1.array(nodes, edges).reverse();
49
+ const sorted = (0, toposort_1.array)(nodes, edges).reverse();
48
50
  return sorted;
49
51
  }
50
52
  exports.sortClarinetContracts = sortClarinetContracts;
51
53
  async function getClarinetAccounts(folder) {
52
54
  const devConfig = await getClarinetDevConfig(folder);
53
55
  const accountEntries = await Promise.all(Object.entries(devConfig.accounts).map(async ([key, info]) => {
54
- const wallet = await wallet_sdk_1.generateWallet({
55
- secretKey: info.mnemonic,
56
- password: 'password',
57
- });
56
+ const wallet = await (0, wallet_sdk_1.generateWallet)(info.mnemonic, 'password');
58
57
  const [account] = wallet.accounts;
59
- const address = wallet_sdk_1.getStxAddress({ account });
58
+ const address = (0, wallet_sdk_1.getStxAddressFromAccount)(account, crypto_1.StacksNetworkVersion.testnetP2PKH);
60
59
  return [
61
60
  key,
62
61
  {
@@ -15,12 +15,12 @@ class Generate extends command_1.Command {
15
15
  const cwd = process.cwd();
16
16
  if (flags.watch) {
17
17
  const spinner = ora('Generating files').start();
18
- const { contractsDir } = await config_1.getConfigFile(cwd);
19
- const watcher = chokidar_1.watch([contractsDir], {
18
+ const { contractsDir } = await (0, config_1.getProjectConfig)(cwd);
19
+ const watcher = (0, chokidar_1.watch)([contractsDir], {
20
20
  cwd,
21
21
  });
22
22
  try {
23
- await utils_1.generateProject(cwd);
23
+ await (0, utils_1.generateProject)(cwd);
24
24
  spinner.succeed(`Finished generating files. Watching for changes.`);
25
25
  }
26
26
  catch (error) {
@@ -28,17 +28,17 @@ class Generate extends command_1.Command {
28
28
  spinner.fail(`Error generating files.\n${error.message}`);
29
29
  }
30
30
  watcher.on('change', async (path) => {
31
- const file = path_1.basename(path);
31
+ const file = (0, path_1.basename)(path);
32
32
  spinner.clear();
33
- spinner.start(`Change detected for ${chalk_1.green(file)}, generating.`);
33
+ spinner.start(`Change detected for ${(0, chalk_1.green)(file)}, generating.`);
34
34
  try {
35
- await utils_1.generateProject(cwd);
36
- spinner.succeed(`Finished generating files for ${chalk_1.green(file)}. Watching for changes.`);
35
+ await (0, utils_1.generateProject)(cwd);
36
+ spinner.succeed(`Finished generating files for ${(0, chalk_1.green)(file)}. Watching for changes.`);
37
37
  }
38
38
  catch (error) {
39
39
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
40
40
  const msg = error.message;
41
- spinner.fail(`Error after saving ${chalk_1.red(file)}.\n${msg}`);
41
+ spinner.fail(`Error after saving ${(0, chalk_1.red)(file)}.\n${msg}`);
42
42
  }
43
43
  });
44
44
  process.on('SIGINT', async () => {
@@ -47,7 +47,7 @@ class Generate extends command_1.Command {
47
47
  });
48
48
  }
49
49
  else {
50
- await utils_1.generateProject(cwd);
50
+ await (0, utils_1.generateProject)(cwd);
51
51
  }
52
52
  }
53
53
  }
package/dist/config.js CHANGED
@@ -1,31 +1,54 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getConfigFile = void 0;
3
+ exports.getProjectConfig = exports.getConfigFile = exports.configFileExists = exports.configFilePath = exports.defaultConfigFile = void 0;
4
4
  const path_1 = require("path");
5
5
  const promises_1 = require("fs/promises");
6
+ const fs_1 = require("fs");
6
7
  const clarinet_config_1 = require("./clarinet-config");
8
+ exports.defaultConfigFile = {
9
+ outputDir: 'src/clarigen',
10
+ clarinet: '.',
11
+ };
12
+ function configFilePath(rootPath) {
13
+ return (0, path_1.resolve)(rootPath, 'clarigen.config.json');
14
+ }
15
+ exports.configFilePath = configFilePath;
16
+ async function configFileExists(configPath) {
17
+ try {
18
+ await (0, promises_1.access)(configPath, fs_1.constants.R_OK);
19
+ return true;
20
+ }
21
+ catch (error) {
22
+ return false;
23
+ }
24
+ }
25
+ exports.configFileExists = configFileExists;
7
26
  async function getConfigFile(rootPath) {
8
- const fullPath = path_1.resolve(rootPath, 'clarigen.config.json');
9
- const configContents = await promises_1.readFile(fullPath, { encoding: 'utf-8' });
10
- const configFile = JSON.parse(configContents);
11
- if (!configFile.outputDir)
12
- throw new Error('Config file missing "outputDir"');
13
- if ('clarinet' in configFile) {
14
- const clarinetPath = path_1.resolve(rootPath, configFile.clarinet);
15
- const accounts = await clarinet_config_1.getClarinetAccounts(clarinetPath);
16
- const contracts = await clarinet_config_1.getContractsFromClarinet(clarinetPath, accounts);
17
- const contractsDir = path_1.relative(process.cwd(), path_1.join(configFile.clarinet, 'contracts'));
27
+ const fullPath = configFilePath(rootPath);
28
+ const exists = await configFileExists(fullPath);
29
+ if (exists) {
30
+ const configContents = await (0, promises_1.readFile)(fullPath, { encoding: 'utf-8' });
31
+ const configFile = JSON.parse(configContents);
18
32
  return {
33
+ ...exports.defaultConfigFile,
19
34
  ...configFile,
20
- contracts,
21
- contractsDir,
22
- accounts,
23
35
  };
24
36
  }
25
- if (!configFile.contracts)
26
- throw new Error('Config file missing "contracts"');
27
- if (!configFile.contractsDir)
28
- throw new Error('Config file missing "contractDir"');
29
- return configFile;
37
+ return exports.defaultConfigFile;
30
38
  }
31
39
  exports.getConfigFile = getConfigFile;
40
+ async function getProjectConfig(rootPath) {
41
+ const configFile = await getConfigFile(rootPath);
42
+ const clarinetPath = (0, path_1.resolve)(rootPath, configFile.clarinet || '.');
43
+ const accounts = await (0, clarinet_config_1.getClarinetAccounts)(clarinetPath);
44
+ const contracts = await (0, clarinet_config_1.getContractsFromClarinet)(clarinetPath, accounts);
45
+ const contractsDir = (0, path_1.relative)(process.cwd(), (0, path_1.join)(configFile.clarinet, 'contracts'));
46
+ return {
47
+ ...configFile,
48
+ contracts,
49
+ contractsDir,
50
+ accounts,
51
+ clarinet: configFile.clarinet || '.',
52
+ };
53
+ }
54
+ exports.getProjectConfig = getProjectConfig;
@@ -1,57 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeTypes = exports.jsTypeFromAbiType = exports.cvFromType = void 0;
4
- const transactions_1 = require("@stacks/transactions");
3
+ exports.makePureTypes = exports.jsTypeFromAbiType = void 0;
4
+ const transactions_1 = require("micro-stacks/transactions");
5
5
  const core_1 = require("@clarigen/core");
6
- const cvFromType = (val) => {
7
- if (transactions_1.isClarityAbiPrimitive(val)) {
8
- if (val === 'uint128') {
9
- return 'ClarityTypes.UIntCV';
10
- }
11
- else if (val === 'int128') {
12
- return 'ClarityTypes.IntCV';
13
- }
14
- else if (val === 'bool') {
15
- return 'ClarityTypes.BooleanCV';
16
- }
17
- else if (val === 'principal') {
18
- return 'ClarityTypes.PrincipalCV';
19
- }
20
- else if (val === 'none') {
21
- return 'ClarityTypes.NoneCV';
22
- }
23
- else {
24
- throw new Error(`Unexpected Clarity ABI type primitive: ${JSON.stringify(val)}`);
25
- }
26
- }
27
- else if (transactions_1.isClarityAbiBuffer(val)) {
28
- return 'ClarityTypes.BufferCV';
29
- }
30
- else if (transactions_1.isClarityAbiResponse(val)) {
31
- return 'ClarityTypes.ResponseCV';
32
- }
33
- else if (transactions_1.isClarityAbiOptional(val)) {
34
- return 'ClarityTypes.OptionalCV';
35
- }
36
- else if (transactions_1.isClarityAbiTuple(val)) {
37
- return 'ClarityTypes.TupleCV';
38
- }
39
- else if (transactions_1.isClarityAbiList(val)) {
40
- return 'ClarityTypes.ListCV';
41
- }
42
- else if (transactions_1.isClarityAbiStringAscii(val)) {
43
- return 'ClarityTypes.StringAsciiCV';
44
- }
45
- else if (transactions_1.isClarityAbiStringUtf8(val)) {
46
- return 'ClarityTypes.StringUtf8CV';
47
- }
48
- else {
49
- throw new Error(`Unexpected Clarity ABI type: ${JSON.stringify(val)}`);
50
- }
51
- };
52
- exports.cvFromType = cvFromType;
6
+ const reserved_words_1 = require("reserved-words");
53
7
  const jsTypeFromAbiType = (val, isArgument = false) => {
54
- if (transactions_1.isClarityAbiPrimitive(val)) {
8
+ if ((0, transactions_1.isClarityAbiPrimitive)(val)) {
55
9
  if (val === 'uint128') {
56
10
  if (isArgument)
57
11
  return 'number | bigint';
@@ -78,36 +32,36 @@ const jsTypeFromAbiType = (val, isArgument = false) => {
78
32
  throw new Error(`Unexpected Clarity ABI type primitive: ${JSON.stringify(val)}`);
79
33
  }
80
34
  }
81
- else if (transactions_1.isClarityAbiBuffer(val)) {
82
- return 'Buffer';
35
+ else if ((0, transactions_1.isClarityAbiBuffer)(val)) {
36
+ return 'Uint8Array';
83
37
  }
84
- else if (transactions_1.isClarityAbiResponse(val)) {
85
- const ok = exports.jsTypeFromAbiType(val.response.ok);
86
- const err = exports.jsTypeFromAbiType(val.response.error);
38
+ else if ((0, transactions_1.isClarityAbiResponse)(val)) {
39
+ const ok = (0, exports.jsTypeFromAbiType)(val.response.ok);
40
+ const err = (0, exports.jsTypeFromAbiType)(val.response.error);
87
41
  return `ClarityTypes.Response<${ok}, ${err}>`;
88
42
  }
89
- else if (transactions_1.isClarityAbiOptional(val)) {
90
- const innerType = exports.jsTypeFromAbiType(val.optional);
43
+ else if ((0, transactions_1.isClarityAbiOptional)(val)) {
44
+ const innerType = (0, exports.jsTypeFromAbiType)(val.optional);
91
45
  return `${innerType} | null`;
92
46
  }
93
- else if (transactions_1.isClarityAbiTuple(val)) {
47
+ else if ((0, transactions_1.isClarityAbiTuple)(val)) {
94
48
  const tupleDefs = [];
95
49
  val.tuple.forEach(({ name, type }) => {
96
- const innerType = exports.jsTypeFromAbiType(type);
50
+ const innerType = (0, exports.jsTypeFromAbiType)(type);
97
51
  tupleDefs.push(`"${name}": ${innerType}`);
98
52
  });
99
53
  return `{
100
54
  ${tupleDefs.join(';\n ')}
101
55
  }`;
102
56
  }
103
- else if (transactions_1.isClarityAbiList(val)) {
104
- const innerType = exports.jsTypeFromAbiType(val.list.type);
57
+ else if ((0, transactions_1.isClarityAbiList)(val)) {
58
+ const innerType = (0, exports.jsTypeFromAbiType)(val.list.type);
105
59
  return `${innerType}[]`;
106
60
  }
107
- else if (transactions_1.isClarityAbiStringAscii(val)) {
61
+ else if ((0, transactions_1.isClarityAbiStringAscii)(val)) {
108
62
  return 'string';
109
63
  }
110
- else if (transactions_1.isClarityAbiStringUtf8(val)) {
64
+ else if ((0, transactions_1.isClarityAbiStringUtf8)(val)) {
111
65
  return 'string';
112
66
  }
113
67
  else if (val === 'trait_reference') {
@@ -118,40 +72,49 @@ const jsTypeFromAbiType = (val, isArgument = false) => {
118
72
  }
119
73
  };
120
74
  exports.jsTypeFromAbiType = jsTypeFromAbiType;
121
- const makeTypes = (abi) => {
75
+ // Check if it's a reserved word, and then camelCase
76
+ function getArgName(name) {
77
+ const camel = (0, core_1.toCamelCase)(name);
78
+ const prefix = (0, reserved_words_1.check)(camel, 6) ? '_' : '';
79
+ return `${prefix}${camel}`;
80
+ }
81
+ const accessToReturnType = {
82
+ public: 'Public',
83
+ read_only: 'ReadOnly',
84
+ private: 'Private',
85
+ };
86
+ function makePureTypes(abi) {
122
87
  let typings = '';
123
88
  abi.functions.forEach((func, index) => {
124
- if (func.access === 'private')
125
- return;
126
- let functionLine = `${core_1.toCamelCase(func.name)}: `;
89
+ let functionLine = `${(0, core_1.toCamelCase)(func.name)}: `;
127
90
  const args = func.args.map((arg) => {
128
- return `${core_1.toCamelCase(arg.name)}: ${exports.jsTypeFromAbiType(arg.type, true)}`;
91
+ return `${getArgName(arg.name)}: ${(0, exports.jsTypeFromAbiType)(arg.type, true)}`;
129
92
  });
130
93
  functionLine += `(${args.join(', ')}) => `;
94
+ const funcType = accessToReturnType[func.access];
95
+ functionLine += `ContractCalls.${funcType}<`;
131
96
  if (func.access === 'public') {
132
97
  const { type } = func.outputs;
133
- if (!transactions_1.isClarityAbiResponse(type))
98
+ if (!(0, transactions_1.isClarityAbiResponse)(type))
134
99
  throw new Error('Expected response type for public function');
135
- functionLine += 'Transaction';
136
- const ok = exports.jsTypeFromAbiType(type.response.ok);
137
- const err = exports.jsTypeFromAbiType(type.response.error);
138
- functionLine += `<${ok}, ${err}>;`;
100
+ const ok = (0, exports.jsTypeFromAbiType)(type.response.ok);
101
+ const err = (0, exports.jsTypeFromAbiType)(type.response.error);
102
+ functionLine += `${ok}, ${err}>;`;
139
103
  }
140
104
  else {
141
- const jsType = exports.jsTypeFromAbiType(func.outputs.type);
142
- functionLine += `Promise<${jsType}>;`;
143
- // const { type } = func.outputs;
144
- // if (isClarityAbiResponse(type)) {
145
- // const ok = jsTypeFromAbiType(type.response.ok);
146
- // const err = jsTypeFromAbiType(type.response.error);
147
- // functionLine += `Promise<ClarityTypes.Response<${ok}, ${err}>>;`;
148
- // } else {
149
- // const jsType = jsTypeFromAbiType(func.outputs.type);
150
- // functionLine += `Promise<${jsType}>;`;
151
- // }
105
+ const returnType = (0, exports.jsTypeFromAbiType)(func.outputs.type);
106
+ functionLine += `${returnType}>;`;
152
107
  }
153
108
  typings += `${index === 0 ? '' : '\n'} ${functionLine}`;
154
109
  });
110
+ abi.maps.forEach((map) => {
111
+ let functionLine = `${(0, core_1.toCamelCase)(map.name)}: `;
112
+ const keyType = (0, exports.jsTypeFromAbiType)(map.key, true);
113
+ const arg = `key: ${keyType}`;
114
+ const valType = (0, exports.jsTypeFromAbiType)(map.value);
115
+ functionLine += `(${arg}) => ContractCalls.Map<${keyType}, ${valType}>;`;
116
+ typings += `\n ${functionLine}`;
117
+ });
155
118
  return typings;
156
- };
157
- exports.makeTypes = makeTypes;
119
+ }
120
+ exports.makePureTypes = makePureTypes;
@@ -3,11 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateProjectIndexFile = exports.generateTypesFile = exports.generateIndexFile = exports.generateInterfaceFile = exports.generateInterface = void 0;
4
4
  const native_bin_1 = require("@clarigen/native-bin");
5
5
  const core_1 = require("@clarigen/core");
6
- const declaration_1 = require("./declaration");
7
6
  const path_1 = require("path");
8
- const generateInterface = async ({ provider: _provider, contractFile, contractAddress = 'S1G2081040G2081040G2081040G208105NK8PE5', }) => {
9
- const provider = _provider || (await native_bin_1.createClarityBin());
10
- const contractName = core_1.getContractNameFromPath(contractFile);
7
+ const __1 = require("..");
8
+ const generateInterface = async ({ provider, contractFile, contractAddress, contractName, }) => {
11
9
  const receipt = await provider.runCommand([
12
10
  'launch',
13
11
  `${contractAddress}.${contractName}`,
@@ -17,7 +15,7 @@ const generateInterface = async ({ provider: _provider, contractFile, contractAd
17
15
  '--costs',
18
16
  '--assets',
19
17
  ]);
20
- if (native_bin_1.hasStdErr(receipt.stderr)) {
18
+ if ((0, native_bin_1.hasStdErr)(receipt.stderr)) {
21
19
  throw new Error(`Error on ${contractFile}:
22
20
  ${receipt.stderr}
23
21
  `);
@@ -47,10 +45,10 @@ const generateInterface = async ({ provider: _provider, contractFile, contractAd
47
45
  return abi;
48
46
  };
49
47
  exports.generateInterface = generateInterface;
50
- const generateInterfaceFile = ({ contractFile, abi, }) => {
51
- const contractName = core_1.getContractNameFromPath(contractFile);
52
- const variableName = core_1.toCamelCase(contractName, true);
53
- const abiString = JSON.stringify(abi, null, 2);
48
+ const generateInterfaceFile = ({ contractName, abi, }) => {
49
+ const variableName = (0, core_1.toCamelCase)(contractName, true);
50
+ const { clarity_version, ...rest } = abi;
51
+ const abiString = JSON.stringify(rest, null, 2);
54
52
  const fileContents = `import { ClarityAbi } from '@clarigen/core';
55
53
 
56
54
  // prettier-ignore
@@ -59,34 +57,39 @@ export const ${variableName}Interface: ClarityAbi = ${abiString};
59
57
  return fileContents;
60
58
  };
61
59
  exports.generateInterfaceFile = generateInterfaceFile;
62
- const generateIndexFile = ({ contractFile, address, }) => {
63
- const contractName = core_1.getContractNameFromPath(contractFile);
64
- const contractTitle = core_1.toCamelCase(contractName, true);
65
- const varName = core_1.toCamelCase(contractName);
60
+ const generateIndexFile = ({ contractFile, contractAddress, contractName, }) => {
61
+ const contractTitle = (0, core_1.toCamelCase)(contractName, true);
62
+ const varName = (0, core_1.toCamelCase)(contractName);
66
63
  const contractType = `${contractTitle}Contract`;
67
- const fileContents = `import { proxy, BaseProvider, Contract } from '@clarigen/core';
64
+ const interfaceVar = `${contractTitle}Interface`;
65
+ const fileContents = `import { pureProxy, Contract } from '@clarigen/core';
68
66
  import type { ${contractType} } from './types';
69
- import { ${contractTitle}Interface } from './abi';
67
+ import { ${interfaceVar} } from './abi';
70
68
  export type { ${contractType} } from './types';
71
69
 
72
- export const ${varName}Contract = (provider: BaseProvider) => {
73
- const contract = proxy<${contractType}>(${contractTitle}Interface, provider);
74
- return contract;
75
- };
70
+ export function ${varName}Contract(contractAddress: string, contractName: string) {
71
+ return pureProxy<${contractType}>({
72
+ abi: ${interfaceVar},
73
+ contractAddress,
74
+ contractName,
75
+ });
76
+ }
76
77
 
77
78
  export const ${varName}Info: Contract<${contractType}> = {
78
79
  contract: ${varName}Contract,
79
- address: '${address}',
80
+ address: '${contractAddress}',
80
81
  contractFile: '${contractFile}',
82
+ name: '${contractName}',
83
+ abi: ${interfaceVar},
81
84
  };
82
85
  `;
83
86
  return fileContents;
84
87
  };
85
88
  exports.generateIndexFile = generateIndexFile;
86
89
  const generateTypesFile = (abi, contractName) => {
87
- const name = core_1.toCamelCase(contractName, true);
88
- const typings = declaration_1.makeTypes(abi);
89
- const fileContents = `import { ClarityTypes, Transaction } from '@clarigen/core';
90
+ const name = (0, core_1.toCamelCase)(contractName, true);
91
+ const typings = (0, __1.makePureTypes)(abi);
92
+ const fileContents = `import { ClarityTypes, ContractCalls } from '@clarigen/core';
90
93
 
91
94
  // prettier-ignore
92
95
  export interface ${name}Contract {
@@ -97,7 +100,9 @@ ${typings}
97
100
  };
98
101
  exports.generateTypesFile = generateTypesFile;
99
102
  const generateProjectIndexFile = (config) => {
100
- const imports = [];
103
+ const imports = [
104
+ "import type { ContractInstances } from '@clarigen/core';",
105
+ ];
101
106
  const exports = [];
102
107
  const contractMap = [];
103
108
  let accounts = '';
@@ -116,12 +121,12 @@ export const accounts = {
116
121
  };`;
117
122
  }
118
123
  config.contracts.forEach((contract) => {
119
- const contractName = core_1.getContractNameFromPath(contract.file);
120
- const contractVar = core_1.toCamelCase(contractName);
124
+ const contractName = contract.name;
125
+ const contractVar = (0, core_1.toCamelCase)(contractName);
121
126
  const contractInfo = `${contractVar}Info`;
122
- const contractInterface = `${core_1.toCamelCase(contractName, true)}Contract`;
123
- const dirName = path_1.dirname(contract.file);
124
- const importPath = `'./${path_1.join(dirName || '.', contractName)}'`;
127
+ const contractInterface = `${(0, core_1.toCamelCase)(contractName, true)}Contract`;
128
+ const dirName = (0, path_1.dirname)(contract.file);
129
+ const importPath = `'./${(0, path_1.join)(dirName || '.', contractName)}'`;
125
130
  const _import = `import { ${contractInfo} } from ${importPath};`;
126
131
  imports.push(_import);
127
132
  const _export = `export type { ${contractInterface} } from ${importPath};`;
@@ -129,9 +134,10 @@ export const accounts = {
129
134
  const map = `${contractVar}: ${contractInfo},`;
130
135
  contractMap.push(map);
131
136
  });
137
+ const contractsType = `\nexport type Contracts = ContractInstances<typeof contracts>;\n`;
132
138
  const file = `${imports.join('\n')}
133
139
  ${exports.join('\n')}
134
-
140
+ ${contractsType}
135
141
  export const contracts = {
136
142
  ${contractMap.join('\n ')}
137
143
  };${accounts}
package/dist/start.js CHANGED
@@ -6,4 +6,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const errors_1 = require("@oclif/errors");
7
7
  const flush_1 = __importDefault(require("@oclif/command/flush"));
8
8
  const index_1 = require("./index");
9
- index_1.run().then(flush_1.default, errors_1.handle);
9
+ (0, index_1.run)().then(flush_1.default, errors_1.handle);
package/dist/utils.js CHANGED
@@ -2,55 +2,52 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateProject = exports.generateFilesForContract = void 0;
4
4
  const files_1 = require("./generate/files");
5
- const core_1 = require("@clarigen/core");
6
5
  const native_bin_1 = require("@clarigen/native-bin");
7
6
  const path_1 = require("path");
8
7
  const promises_1 = require("fs/promises");
9
8
  const config_1 = require("./config");
10
- const generateFilesForContract = async ({ contractFile: _contractFile, outputFolder, provider, contractAddress, dirName, }) => {
11
- const contractFile = path_1.resolve(process.cwd(), _contractFile);
12
- const contractName = core_1.getContractNameFromPath(contractFile);
13
- const abi = await files_1.generateInterface({
9
+ const generateFilesForContract = async ({ contractFile: _contractFile, outputFolder, provider, contractAddress, dirName, contractName, }) => {
10
+ const contractFile = (0, path_1.resolve)(process.cwd(), _contractFile);
11
+ const abi = await (0, files_1.generateInterface)({
14
12
  contractFile,
15
13
  provider,
16
14
  contractAddress,
15
+ contractName,
17
16
  });
18
- const typesFile = files_1.generateTypesFile(abi, contractName);
19
- if (!contractAddress && process.env.NODE_ENV !== 'test') {
20
- console.warn('Please provide an address with every contract.');
21
- }
22
- const indexFile = files_1.generateIndexFile({
23
- contractFile: path_1.relative(process.cwd(), contractFile),
24
- address: contractAddress || '',
17
+ const typesFile = (0, files_1.generateTypesFile)(abi, contractName);
18
+ const indexFile = (0, files_1.generateIndexFile)({
19
+ contractFile: (0, path_1.relative)(process.cwd(), contractFile),
20
+ contractAddress: contractAddress,
21
+ contractName,
25
22
  });
26
- const abiFile = files_1.generateInterfaceFile({ contractFile, abi });
27
- const baseDir = outputFolder || path_1.resolve(process.cwd(), `tmp/${contractName}`);
28
- const outputPath = path_1.resolve(baseDir, dirName || '.', contractName);
29
- await promises_1.mkdir(outputPath, { recursive: true });
30
- await promises_1.writeFile(path_1.resolve(outputPath, 'abi.ts'), abiFile);
31
- await promises_1.writeFile(path_1.resolve(outputPath, 'index.ts'), indexFile);
32
- await promises_1.writeFile(path_1.resolve(outputPath, 'types.ts'), typesFile);
23
+ const abiFile = (0, files_1.generateInterfaceFile)({ contractName, abi });
24
+ const outputPath = (0, path_1.resolve)(outputFolder, dirName || '.', contractName);
25
+ await (0, promises_1.mkdir)(outputPath, { recursive: true });
26
+ await (0, promises_1.writeFile)((0, path_1.resolve)(outputPath, 'abi.ts'), abiFile);
27
+ await (0, promises_1.writeFile)((0, path_1.resolve)(outputPath, 'index.ts'), indexFile);
28
+ await (0, promises_1.writeFile)((0, path_1.resolve)(outputPath, 'types.ts'), typesFile);
33
29
  };
34
30
  exports.generateFilesForContract = generateFilesForContract;
35
31
  const generateProject = async (projectPath) => {
36
- const configFile = await config_1.getConfigFile(projectPath);
32
+ const configFile = await (0, config_1.getProjectConfig)(projectPath);
37
33
  const { contractsDir, outputDir, contracts } = configFile;
38
- const outputFolder = path_1.resolve(projectPath, outputDir);
39
- const provider = await native_bin_1.createClarityBin();
34
+ const outputFolder = (0, path_1.resolve)(projectPath, outputDir);
35
+ const provider = await (0, native_bin_1.createClarityBin)();
40
36
  // this needs to be serial
41
37
  for (const contract of contracts) {
42
- const contractFile = path_1.resolve(projectPath, contractsDir, contract.file);
43
- const dirName = path_1.dirname(contract.file);
44
- await exports.generateFilesForContract({
38
+ const contractFile = (0, path_1.resolve)(projectPath, contractsDir, contract.file);
39
+ const dirName = (0, path_1.dirname)(contract.file);
40
+ await (0, exports.generateFilesForContract)({
45
41
  contractFile,
46
42
  outputFolder: outputFolder,
47
43
  provider,
48
44
  contractAddress: contract.address,
49
45
  dirName,
46
+ contractName: contract.name,
50
47
  });
51
48
  }
52
- const indexFile = files_1.generateProjectIndexFile(configFile);
53
- const indexPath = path_1.resolve(outputFolder, 'index.ts');
54
- await promises_1.writeFile(indexPath, indexFile);
49
+ const indexFile = (0, files_1.generateProjectIndexFile)(configFile);
50
+ const indexPath = (0, path_1.resolve)(outputFolder, 'index.ts');
51
+ await (0, promises_1.writeFile)(indexPath, indexFile);
55
52
  };
56
53
  exports.generateProject = generateProject;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@clarigen/cli",
3
3
  "description": "A CLI for generating a Typescript interface for a Clarity contract.",
4
4
  "author": "Hank Stoever",
5
- "version": "0.3.6",
5
+ "version": "1.0.0-next.3",
6
6
  "license": "MIT",
7
7
  "main": "dist/index.js",
8
8
  "files": [
@@ -19,9 +19,9 @@
19
19
  "compile": "ncc build src/index.ts --no-source-map-register -e @oclif/command -e @oclif/errors",
20
20
  "build-single-file": "yarn compile && oclif-dev readme",
21
21
  "build": "rm -rf dist && tsc -b",
22
- "test": "tsdx test",
22
+ "test": "jest",
23
23
  "lint": "tsdx lint",
24
- "typecheck": "tsc --noEmit",
24
+ "typecheck": "tsc --noEmit -p tsconfig-test.json",
25
25
  "prepublishOnly": "yarn build"
26
26
  },
27
27
  "bin": {
@@ -40,26 +40,28 @@
40
40
  "devDependencies": {
41
41
  "@oclif/dev-cli": "^1.26.0",
42
42
  "@oclif/errors": "^1.3.4",
43
+ "@types/reserved-words": "0.1.0",
43
44
  "@types/toposort": "2.0.3",
44
45
  "@vercel/ncc": "0.27.0",
45
46
  "oclif": "^1.16.1",
46
47
  "ts-node": "^9.1.1"
47
48
  },
48
49
  "dependencies": {
49
- "@clarigen/core": "0.3.4",
50
- "@clarigen/native-bin": "0.3.4",
50
+ "@clarigen/core": "1.0.0-next.3",
51
+ "@clarigen/native-bin": "1.0.0-next.3",
51
52
  "@ltd/j-toml": "1.12.2",
52
53
  "@oclif/command": "^1.8.0",
53
54
  "@oclif/config": "^1.17.0",
54
55
  "@oclif/plugin-help": "3.2.3",
55
- "@stacks/wallet-sdk": "1.0.0-wallet-sdk.4",
56
56
  "chalk": "4.1.0",
57
57
  "chokidar": "3.5.1",
58
+ "micro-stacks": "^0.2.0",
58
59
  "ora": "5.4.0",
60
+ "reserved-words": "0.1.2",
59
61
  "toposort": "2.0.2"
60
62
  },
61
63
  "publishConfig": {
62
64
  "access": "public"
63
65
  },
64
- "gitHead": "b438736c231e6d6adf20a8e384f03bf522be6a64"
66
+ "gitHead": "4ef5ca2c7aec78bdc14072f09ada2aab6eff627a"
65
67
  }
@@ -2,8 +2,12 @@ import { parse } from '@ltd/j-toml';
2
2
  import { resolve } from 'path';
3
3
  import { readFile } from 'fs/promises';
4
4
  import { ConfigContract } from './config';
5
- import { generateWallet, getStxAddress } from '@stacks/wallet-sdk';
5
+ import {
6
+ generateWallet,
7
+ getStxAddressFromAccount,
8
+ } from 'micro-stacks/wallet-sdk';
6
9
  import { array as toposort } from 'toposort';
10
+ import { StacksNetworkVersion } from 'micro-stacks/crypto';
7
11
 
8
12
  interface ClarinetConfigAccount {
9
13
  mnemonic: string;
@@ -63,14 +67,15 @@ export async function getContractsFromClarinet(
63
67
  const clarinetConfig = await getClarinetConfig(folder);
64
68
  const deployerAddress = accounts.deployer.address;
65
69
  const sortedContracts = sortClarinetContracts(clarinetConfig.contracts);
66
- const contracts: ConfigContract[] = sortedContracts.map(contractName => {
70
+ const contracts: ConfigContract[] = sortedContracts.map((contractName) => {
67
71
  const info = clarinetConfig.contracts[contractName];
68
72
  const file = info.path.replace(/^contracts\//, '');
69
73
  return {
70
74
  file,
71
75
  address: deployerAddress,
76
+ name: contractName,
72
77
  };
73
- })
78
+ });
74
79
  return contracts;
75
80
  }
76
81
 
@@ -102,12 +107,12 @@ export async function getClarinetAccounts(
102
107
  const devConfig = await getClarinetDevConfig(folder);
103
108
  const accountEntries = await Promise.all(
104
109
  Object.entries(devConfig.accounts).map(async ([key, info]) => {
105
- const wallet = await generateWallet({
106
- secretKey: info.mnemonic,
107
- password: 'password',
108
- });
110
+ const wallet = await generateWallet(info.mnemonic, 'password');
109
111
  const [account] = wallet.accounts;
110
- const address = getStxAddress({ account });
112
+ const address = getStxAddressFromAccount(
113
+ account,
114
+ StacksNetworkVersion.testnetP2PKH
115
+ );
111
116
  return [
112
117
  key,
113
118
  {
@@ -1,6 +1,6 @@
1
1
  import { Command, flags } from '@oclif/command';
2
2
  import { generateProject } from '../utils';
3
- import { getConfigFile } from '../config';
3
+ import { getProjectConfig } from '../config';
4
4
  import { watch } from 'chokidar';
5
5
  import { basename } from 'path';
6
6
  import { red, green } from 'chalk';
@@ -28,7 +28,7 @@ export class Generate extends Command {
28
28
 
29
29
  if (flags.watch) {
30
30
  const spinner = ora('Generating files').start();
31
- const { contractsDir } = await getConfigFile(cwd);
31
+ const { contractsDir } = await getProjectConfig(cwd);
32
32
  const watcher = watch([contractsDir], {
33
33
  cwd,
34
34
  });
package/src/config.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { resolve, join, relative } from 'path';
2
- import { readFile } from 'fs/promises';
2
+ import { readFile, access } from 'fs/promises';
3
+ import { constants } from 'fs';
3
4
  import {
4
5
  ClarinetAccounts,
5
6
  getClarinetAccounts,
@@ -9,52 +10,69 @@ import {
9
10
  export interface ConfigContract {
10
11
  address: string;
11
12
  file: string;
13
+ name: string;
12
14
  }
13
15
 
14
- export interface ConfigFileBase {
16
+ export interface ConfigFileContents {
15
17
  outputDir: string;
16
- }
17
-
18
- export interface ConfigFileWithClarinet extends ConfigFileBase {
19
18
  clarinet: string;
20
19
  }
21
20
 
22
- export interface ConfigFileRegular extends ConfigFileBase {
21
+ export interface ConfigFile extends ConfigFileContents {
23
22
  contractsDir: string;
24
23
  contracts: ConfigContract[];
24
+ accounts: ClarinetAccounts;
25
+ clarinet: string;
25
26
  }
26
27
 
27
- export type ConfigFileContents = ConfigFileRegular | ConfigFileWithClarinet;
28
+ export const defaultConfigFile: ConfigFileContents = {
29
+ outputDir: 'src/clarigen',
30
+ clarinet: '.',
31
+ };
28
32
 
29
- export interface ConfigFileWithClarinetInfo extends ConfigFileRegular {
30
- clarinet: string;
31
- accounts: ClarinetAccounts;
33
+ export function configFilePath(rootPath: string) {
34
+ return resolve(rootPath, 'clarigen.config.json');
32
35
  }
33
36
 
34
- export type ConfigFile = ConfigFileRegular | ConfigFileWithClarinetInfo;
35
-
36
- export async function getConfigFile(rootPath: string): Promise<ConfigFile> {
37
- const fullPath = resolve(rootPath, 'clarigen.config.json');
38
- const configContents = await readFile(fullPath, { encoding: 'utf-8' });
39
- const configFile: ConfigFileContents = JSON.parse(configContents);
40
- if (!configFile.outputDir) throw new Error('Config file missing "outputDir"');
41
- if ('clarinet' in configFile) {
42
- const clarinetPath = resolve(rootPath, configFile.clarinet);
43
- const accounts = await getClarinetAccounts(clarinetPath);
44
- const contracts = await getContractsFromClarinet(clarinetPath, accounts);
45
- const contractsDir = relative(
46
- process.cwd(),
47
- join(configFile.clarinet, 'contracts')
48
- );
37
+ export async function configFileExists(configPath: string): Promise<boolean> {
38
+ try {
39
+ await access(configPath, constants.R_OK);
40
+ return true;
41
+ } catch (error) {
42
+ return false;
43
+ }
44
+ }
45
+
46
+ export async function getConfigFile(
47
+ rootPath: string
48
+ ): Promise<ConfigFileContents> {
49
+ const fullPath = configFilePath(rootPath);
50
+ const exists = await configFileExists(fullPath);
51
+ if (exists) {
52
+ const configContents = await readFile(fullPath, { encoding: 'utf-8' });
53
+ const configFile: ConfigFileContents = JSON.parse(configContents);
49
54
  return {
55
+ ...defaultConfigFile,
50
56
  ...configFile,
51
- contracts,
52
- contractsDir,
53
- accounts,
54
57
  };
55
58
  }
56
- if (!configFile.contracts) throw new Error('Config file missing "contracts"');
57
- if (!configFile.contractsDir)
58
- throw new Error('Config file missing "contractDir"');
59
- return configFile;
59
+ return defaultConfigFile;
60
+ }
61
+
62
+ export async function getProjectConfig(rootPath: string): Promise<ConfigFile> {
63
+ const configFile = await getConfigFile(rootPath);
64
+ const clarinetPath = resolve(rootPath, configFile.clarinet || '.');
65
+ const accounts = await getClarinetAccounts(clarinetPath);
66
+ const contracts = await getContractsFromClarinet(clarinetPath, accounts);
67
+ const contractsDir = relative(
68
+ process.cwd(),
69
+ join(configFile.clarinet, 'contracts')
70
+ );
71
+ return {
72
+ ...configFile,
73
+ contracts,
74
+ contractsDir,
75
+ accounts,
76
+ clarinet: configFile.clarinet || '.',
77
+ };
60
78
  }
@@ -1,5 +1,4 @@
1
1
  import {
2
- ClarityAbiType,
3
2
  isClarityAbiBuffer,
4
3
  isClarityAbiList,
5
4
  isClarityAbiOptional,
@@ -8,44 +7,10 @@ import {
8
7
  isClarityAbiStringAscii,
9
8
  isClarityAbiStringUtf8,
10
9
  isClarityAbiTuple,
11
- } from '@stacks/transactions';
10
+ } from 'micro-stacks/transactions';
11
+ import { ClarityAbiFunction, ClarityAbiType } from 'micro-stacks/clarity';
12
12
  import { toCamelCase, ClarityAbi } from '@clarigen/core';
13
-
14
- export const cvFromType = (val: ClarityAbiType) => {
15
- if (isClarityAbiPrimitive(val)) {
16
- if (val === 'uint128') {
17
- return 'ClarityTypes.UIntCV';
18
- } else if (val === 'int128') {
19
- return 'ClarityTypes.IntCV';
20
- } else if (val === 'bool') {
21
- return 'ClarityTypes.BooleanCV';
22
- } else if (val === 'principal') {
23
- return 'ClarityTypes.PrincipalCV';
24
- } else if (val === 'none') {
25
- return 'ClarityTypes.NoneCV';
26
- } else {
27
- throw new Error(
28
- `Unexpected Clarity ABI type primitive: ${JSON.stringify(val)}`
29
- );
30
- }
31
- } else if (isClarityAbiBuffer(val)) {
32
- return 'ClarityTypes.BufferCV';
33
- } else if (isClarityAbiResponse(val)) {
34
- return 'ClarityTypes.ResponseCV';
35
- } else if (isClarityAbiOptional(val)) {
36
- return 'ClarityTypes.OptionalCV';
37
- } else if (isClarityAbiTuple(val)) {
38
- return 'ClarityTypes.TupleCV';
39
- } else if (isClarityAbiList(val)) {
40
- return 'ClarityTypes.ListCV';
41
- } else if (isClarityAbiStringAscii(val)) {
42
- return 'ClarityTypes.StringAsciiCV';
43
- } else if (isClarityAbiStringUtf8(val)) {
44
- return 'ClarityTypes.StringUtf8CV';
45
- } else {
46
- throw new Error(`Unexpected Clarity ABI type: ${JSON.stringify(val)}`);
47
- }
48
- };
13
+ import { check } from 'reserved-words';
49
14
 
50
15
  export const jsTypeFromAbiType = (
51
16
  val: ClarityAbiType,
@@ -72,7 +37,7 @@ export const jsTypeFromAbiType = (
72
37
  );
73
38
  }
74
39
  } else if (isClarityAbiBuffer(val)) {
75
- return 'Buffer';
40
+ return 'Uint8Array';
76
41
  } else if (isClarityAbiResponse(val)) {
77
42
  const ok: any = jsTypeFromAbiType(val.response.ok);
78
43
  const err: any = jsTypeFromAbiType(val.response.error);
@@ -103,38 +68,49 @@ export const jsTypeFromAbiType = (
103
68
  }
104
69
  };
105
70
 
106
- export const makeTypes = (abi: ClarityAbi) => {
71
+ // Check if it's a reserved word, and then camelCase
72
+ function getArgName(name: string) {
73
+ const camel = toCamelCase(name);
74
+ const prefix = check(camel, 6) ? '_' : '';
75
+ return `${prefix}${camel}`;
76
+ }
77
+
78
+ const accessToReturnType = {
79
+ public: 'Public',
80
+ read_only: 'ReadOnly',
81
+ private: 'Private',
82
+ } as const;
83
+
84
+ export function makePureTypes(abi: ClarityAbi) {
107
85
  let typings = '';
108
86
  abi.functions.forEach((func, index) => {
109
- if (func.access === 'private') return;
110
87
  let functionLine = `${toCamelCase(func.name)}: `;
111
88
  const args = func.args.map((arg) => {
112
- return `${toCamelCase(arg.name)}: ${jsTypeFromAbiType(arg.type, true)}`;
89
+ return `${getArgName(arg.name)}: ${jsTypeFromAbiType(arg.type, true)}`;
113
90
  });
114
91
  functionLine += `(${args.join(', ')}) => `;
92
+ const funcType = accessToReturnType[func.access];
93
+ functionLine += `ContractCalls.${funcType}<`;
115
94
  if (func.access === 'public') {
116
95
  const { type } = func.outputs;
117
96
  if (!isClarityAbiResponse(type))
118
97
  throw new Error('Expected response type for public function');
119
- functionLine += 'Transaction';
120
98
  const ok = jsTypeFromAbiType(type.response.ok);
121
99
  const err = jsTypeFromAbiType(type.response.error);
122
- functionLine += `<${ok}, ${err}>;`;
100
+ functionLine += `${ok}, ${err}>;`;
123
101
  } else {
124
- const jsType = jsTypeFromAbiType(func.outputs.type);
125
- functionLine += `Promise<${jsType}>;`;
126
- // const { type } = func.outputs;
127
- // if (isClarityAbiResponse(type)) {
128
- // const ok = jsTypeFromAbiType(type.response.ok);
129
- // const err = jsTypeFromAbiType(type.response.error);
130
- // functionLine += `Promise<ClarityTypes.Response<${ok}, ${err}>>;`;
131
- // } else {
132
- // const jsType = jsTypeFromAbiType(func.outputs.type);
133
- // functionLine += `Promise<${jsType}>;`;
134
- // }
102
+ const returnType = jsTypeFromAbiType(func.outputs.type);
103
+ functionLine += `${returnType}>;`;
135
104
  }
136
105
  typings += `${index === 0 ? '' : '\n'} ${functionLine}`;
137
106
  });
138
-
107
+ abi.maps.forEach((map) => {
108
+ let functionLine = `${toCamelCase(map.name)}: `;
109
+ const keyType = jsTypeFromAbiType(map.key, true);
110
+ const arg = `key: ${keyType}`;
111
+ const valType = jsTypeFromAbiType(map.value);
112
+ functionLine += `(${arg}) => ContractCalls.Map<${keyType}, ${valType}>;`;
113
+ typings += `\n ${functionLine}`;
114
+ });
139
115
  return typings;
140
- };
116
+ }
@@ -1,28 +1,20 @@
1
- import {
2
- NativeClarityBinProvider,
3
- createClarityBin,
4
- hasStdErr,
5
- } from '@clarigen/native-bin';
6
- import {
7
- ClarityAbi,
8
- toCamelCase,
9
- getContractNameFromPath,
10
- } from '@clarigen/core';
11
- import { makeTypes } from './declaration';
1
+ import { NativeClarityBinProvider, hasStdErr } from '@clarigen/native-bin';
2
+ import { ClarityAbi, toCamelCase } from '@clarigen/core';
12
3
  import { ConfigContract, ConfigFile } from '../config';
13
4
  import { dirname, resolve, join } from 'path';
5
+ import { makePureTypes } from '..';
14
6
 
15
7
  export const generateInterface = async ({
16
- provider: _provider,
8
+ provider,
17
9
  contractFile,
18
- contractAddress = 'S1G2081040G2081040G2081040G208105NK8PE5',
10
+ contractAddress,
11
+ contractName,
19
12
  }: {
20
13
  contractFile: string;
21
- provider?: NativeClarityBinProvider;
22
- contractAddress?: string;
14
+ provider: NativeClarityBinProvider;
15
+ contractAddress: string;
16
+ contractName: string;
23
17
  }): Promise<ClarityAbi> => {
24
- const provider = _provider || (await createClarityBin());
25
- const contractName = getContractNameFromPath(contractFile);
26
18
  const receipt = await provider.runCommand([
27
19
  'launch',
28
20
  `${contractAddress}.${contractName}`,
@@ -62,15 +54,15 @@ export const generateInterface = async ({
62
54
  };
63
55
 
64
56
  export const generateInterfaceFile = ({
65
- contractFile,
57
+ contractName,
66
58
  abi,
67
59
  }: {
68
- contractFile: string;
60
+ contractName: string;
69
61
  abi: ClarityAbi;
70
62
  }) => {
71
- const contractName = getContractNameFromPath(contractFile);
72
63
  const variableName = toCamelCase(contractName, true);
73
- const abiString = JSON.stringify(abi, null, 2);
64
+ const { clarity_version, ...rest } = abi;
65
+ const abiString = JSON.stringify(rest, null, 2);
74
66
 
75
67
  const fileContents = `import { ClarityAbi } from '@clarigen/core';
76
68
 
@@ -83,30 +75,37 @@ export const ${variableName}Interface: ClarityAbi = ${abiString};
83
75
 
84
76
  export const generateIndexFile = ({
85
77
  contractFile,
86
- address,
78
+ contractAddress,
79
+ contractName,
87
80
  }: {
88
81
  contractFile: string;
89
- address: string;
82
+ contractAddress: string;
83
+ contractName: string;
90
84
  }) => {
91
- const contractName = getContractNameFromPath(contractFile);
92
85
  const contractTitle = toCamelCase(contractName, true);
93
86
  const varName = toCamelCase(contractName);
94
87
  const contractType = `${contractTitle}Contract`;
88
+ const interfaceVar = `${contractTitle}Interface`;
95
89
 
96
- const fileContents = `import { proxy, BaseProvider, Contract } from '@clarigen/core';
90
+ const fileContents = `import { pureProxy, Contract } from '@clarigen/core';
97
91
  import type { ${contractType} } from './types';
98
- import { ${contractTitle}Interface } from './abi';
92
+ import { ${interfaceVar} } from './abi';
99
93
  export type { ${contractType} } from './types';
100
94
 
101
- export const ${varName}Contract = (provider: BaseProvider) => {
102
- const contract = proxy<${contractType}>(${contractTitle}Interface, provider);
103
- return contract;
104
- };
95
+ export function ${varName}Contract(contractAddress: string, contractName: string) {
96
+ return pureProxy<${contractType}>({
97
+ abi: ${interfaceVar},
98
+ contractAddress,
99
+ contractName,
100
+ });
101
+ }
105
102
 
106
103
  export const ${varName}Info: Contract<${contractType}> = {
107
104
  contract: ${varName}Contract,
108
- address: '${address}',
105
+ address: '${contractAddress}',
109
106
  contractFile: '${contractFile}',
107
+ name: '${contractName}',
108
+ abi: ${interfaceVar},
110
109
  };
111
110
  `;
112
111
 
@@ -115,8 +114,8 @@ export const ${varName}Info: Contract<${contractType}> = {
115
114
 
116
115
  export const generateTypesFile = (abi: ClarityAbi, contractName: string) => {
117
116
  const name = toCamelCase(contractName, true);
118
- const typings = makeTypes(abi);
119
- const fileContents = `import { ClarityTypes, Transaction } from '@clarigen/core';
117
+ const typings = makePureTypes(abi);
118
+ const fileContents = `import { ClarityTypes, ContractCalls } from '@clarigen/core';
120
119
 
121
120
  // prettier-ignore
122
121
  export interface ${name}Contract {
@@ -128,7 +127,9 @@ ${typings}
128
127
  };
129
128
 
130
129
  export const generateProjectIndexFile = (config: ConfigFile) => {
131
- const imports: string[] = [];
130
+ const imports: string[] = [
131
+ "import type { ContractInstances } from '@clarigen/core';",
132
+ ];
132
133
  const exports: string[] = [];
133
134
  const contractMap: string[] = [];
134
135
 
@@ -150,7 +151,7 @@ export const accounts = {
150
151
  }
151
152
 
152
153
  config.contracts.forEach((contract) => {
153
- const contractName = getContractNameFromPath(contract.file);
154
+ const contractName = contract.name;
154
155
  const contractVar = toCamelCase(contractName);
155
156
  const contractInfo = `${contractVar}Info`;
156
157
  const contractInterface = `${toCamelCase(contractName, true)}Contract`;
@@ -167,9 +168,11 @@ export const accounts = {
167
168
  contractMap.push(map);
168
169
  });
169
170
 
171
+ const contractsType = `\nexport type Contracts = ContractInstances<typeof contracts>;\n`;
172
+
170
173
  const file = `${imports.join('\n')}
171
174
  ${exports.join('\n')}
172
-
175
+ ${contractsType}
173
176
  export const contracts = {
174
177
  ${contractMap.join('\n ')}
175
178
  };${accounts}
package/src/utils.ts CHANGED
@@ -5,14 +5,13 @@ import {
5
5
  generateProjectIndexFile,
6
6
  generateTypesFile,
7
7
  } from './generate/files';
8
- import { getContractNameFromPath } from '@clarigen/core';
9
8
  import {
10
9
  NativeClarityBinProvider,
11
10
  createClarityBin,
12
11
  } from '@clarigen/native-bin';
13
12
  import { resolve, relative, dirname } from 'path';
14
13
  import { mkdir, writeFile } from 'fs/promises';
15
- import { getConfigFile } from './config';
14
+ import { getProjectConfig } from './config';
16
15
 
17
16
  export const generateFilesForContract = async ({
18
17
  contractFile: _contractFile,
@@ -20,33 +19,32 @@ export const generateFilesForContract = async ({
20
19
  provider,
21
20
  contractAddress,
22
21
  dirName,
22
+ contractName,
23
23
  }: {
24
24
  contractFile: string;
25
- outputFolder?: string;
26
- provider?: NativeClarityBinProvider;
27
- contractAddress?: string;
25
+ outputFolder: string;
26
+ provider: NativeClarityBinProvider;
27
+ contractAddress: string;
28
28
  dirName?: string;
29
+ contractName: string;
29
30
  }) => {
30
31
  const contractFile = resolve(process.cwd(), _contractFile);
31
- const contractName = getContractNameFromPath(contractFile);
32
32
 
33
33
  const abi = await generateInterface({
34
34
  contractFile,
35
35
  provider,
36
36
  contractAddress,
37
+ contractName,
37
38
  });
38
39
  const typesFile = generateTypesFile(abi, contractName);
39
- if (!contractAddress && process.env.NODE_ENV !== 'test') {
40
- console.warn('Please provide an address with every contract.');
41
- }
42
40
  const indexFile = generateIndexFile({
43
41
  contractFile: relative(process.cwd(), contractFile),
44
- address: contractAddress || '',
42
+ contractAddress: contractAddress,
43
+ contractName,
45
44
  });
46
- const abiFile = generateInterfaceFile({ contractFile, abi });
45
+ const abiFile = generateInterfaceFile({ contractName, abi });
47
46
 
48
- const baseDir = outputFolder || resolve(process.cwd(), `tmp/${contractName}`);
49
- const outputPath = resolve(baseDir, dirName || '.', contractName);
47
+ const outputPath = resolve(outputFolder, dirName || '.', contractName);
50
48
  await mkdir(outputPath, { recursive: true });
51
49
 
52
50
  await writeFile(resolve(outputPath, 'abi.ts'), abiFile);
@@ -55,7 +53,7 @@ export const generateFilesForContract = async ({
55
53
  };
56
54
 
57
55
  export const generateProject = async (projectPath: string) => {
58
- const configFile = await getConfigFile(projectPath);
56
+ const configFile = await getProjectConfig(projectPath);
59
57
  const { contractsDir, outputDir, contracts } = configFile;
60
58
  const outputFolder = resolve(projectPath, outputDir);
61
59
  const provider = await createClarityBin();
@@ -69,6 +67,7 @@ export const generateProject = async (projectPath: string) => {
69
67
  provider,
70
68
  contractAddress: contract.address,
71
69
  dirName,
70
+ contractName: contract.name,
72
71
  });
73
72
  }
74
73
 
@@ -1,33 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Contract = void 0;
4
- const command_1 = require("@oclif/command");
5
- const utils_1 = require("../utils");
6
- class Contract extends command_1.Command {
7
- async run() {
8
- const { argv, flags } = this.parse(Contract);
9
- const [contractFile] = argv;
10
- await utils_1.generateFilesForContract({
11
- contractFile,
12
- outputFolder: flags.output,
13
- });
14
- }
15
- }
16
- exports.Contract = Contract;
17
- Contract.description = `Generate files for a single contract`;
18
- Contract.strict = true;
19
- Contract.hidden = true;
20
- Contract.flags = {
21
- help: command_1.flags.help({ char: 'h' }),
22
- output: command_1.flags.string({
23
- char: 'o',
24
- description: 'Output destination folder',
25
- default: 'clarion',
26
- }),
27
- };
28
- Contract.args = [
29
- {
30
- name: 'contract',
31
- description: 'The file path for your contract',
32
- },
33
- ];
@@ -1,35 +0,0 @@
1
- import { Command, flags } from '@oclif/command';
2
- import { generateFilesForContract } from '../utils';
3
-
4
- export class Contract extends Command {
5
- static description = `Generate files for a single contract`;
6
- static strict = true;
7
- static hidden = true;
8
-
9
- static flags = {
10
- help: flags.help({ char: 'h' }),
11
- output: flags.string({
12
- char: 'o',
13
- description: 'Output destination folder',
14
- default: 'clarion',
15
- }),
16
- };
17
-
18
- static args = [
19
- {
20
- name: 'contract',
21
- description: 'The file path for your contract',
22
- },
23
- ];
24
-
25
- async run() {
26
- const { argv, flags } = this.parse(Contract);
27
-
28
- const [contractFile] = argv;
29
-
30
- await generateFilesForContract({
31
- contractFile,
32
- outputFolder: flags.output,
33
- });
34
- }
35
- }