@taqueria/plugin-taquito 0.21.30 → 0.23.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/originate.ts CHANGED
@@ -1,65 +1,42 @@
1
1
  import {
2
- getAccountPrivateKey,
3
2
  getCurrentEnvironment,
4
3
  getCurrentEnvironmentConfig,
5
- getDefaultAccount,
6
4
  getInitialStorage,
7
- getNetworkConfig,
8
- getSandboxAccountConfig,
9
- getSandboxAccountNames,
10
- getSandboxConfig,
11
- newGetInitialStorage,
12
5
  sendAsyncErr,
13
- sendErr,
14
6
  sendJsonRes,
15
- sendRes,
16
7
  updateAddressAlias,
17
8
  } from '@taqueria/node-sdk';
18
- import { Protocol, RequestArgs } from '@taqueria/node-sdk/types';
19
9
  import { OperationContentsAndResultOrigination } from '@taquito/rpc';
20
- import { importKey, InMemorySigner } from '@taquito/signer';
21
10
  import { TezosToolkit, WalletOperationBatch } from '@taquito/taquito';
22
11
  import { BatchWalletOperation } from '@taquito/taquito/dist/types/wallet/batch-operation';
23
- import glob from 'fast-glob';
24
12
  import { readFile } from 'fs/promises';
25
13
  import { basename, extname, join } from 'path';
26
-
27
- interface Opts extends RequestArgs.t {
14
+ import {
15
+ configureToolKitForNetwork,
16
+ configureToolKitForSandbox,
17
+ getEnvTypeAndNodeConfig,
18
+ handleOpsError,
19
+ OriginateOpts as Opts,
20
+ } from './common';
21
+
22
+ type ContractInfo = {
28
23
  contract: string;
29
- storage: string;
30
- alias?: string;
31
- }
32
-
33
- interface ContractStorageMapping {
34
- filename: string;
35
- storage?: unknown;
36
- }
24
+ code: string;
25
+ initStorage: string;
26
+ mutezTransfer: number;
27
+ };
37
28
 
38
- interface OriginationResult {
29
+ type TableRow = {
39
30
  contract: string;
40
31
  address: string;
41
32
  alias: string;
33
+ balanceInMutez: string;
42
34
  destination: string;
43
- }
44
-
45
- const getFirstAccountAlias = (sandboxName: string, opts: Opts) => {
46
- const aliases = getSandboxAccountNames(opts)(sandboxName);
47
- return aliases.shift();
48
35
  };
49
36
 
50
- const getContractAbspath = (contractFilename: string, parsedArgs: Opts) =>
37
+ const getContractPath = (parsedArgs: Opts, contractFilename: string) =>
51
38
  join(parsedArgs.config.artifactsDir, /\.tz$/.test(contractFilename) ? contractFilename : `${contractFilename}.tz`);
52
39
 
53
- const addOrigination = (parsedArgs: Opts, batch: Promise<WalletOperationBatch>) =>
54
- async (mapping: ContractStorageMapping) => {
55
- const contractAbspath = getContractAbspath(mapping.filename, parsedArgs);
56
- const contractData = await readFile(contractAbspath, 'utf-8');
57
- return (await batch).withOrigination({
58
- code: contractData,
59
- init: mapping.storage as any,
60
- });
61
- };
62
-
63
40
  const getDefaultStorageFilename = (contractName: string): string => {
64
41
  const baseFilename = basename(contractName, extname(contractName));
65
42
  const extFilename = extname(contractName);
@@ -67,264 +44,99 @@ const getDefaultStorageFilename = (contractName: string): string => {
67
44
  return defaultStorage;
68
45
  };
69
46
 
70
- // TODO: temporary quick solution. May refactor this to only deal with one contract later
71
- const getValidContracts = async (parsedArgs: Opts) => {
72
- const contracts = [parsedArgs.contract];
73
- const storageFilename = parsedArgs.storage ?? getDefaultStorageFilename(contracts[0]);
74
-
75
- return contracts.reduce(
76
- async (retval, filename) => {
77
- const storage = await newGetInitialStorage(parsedArgs, storageFilename);
78
- if (storage === undefined || storage === null) {
79
- sendErr(
80
- `❌ No initial storage file was found for ${filename}\nStorage must be specified in a file as a Michelson expression and will automatically be linked to this contract if specified with the name "${
81
- getDefaultStorageFilename(contracts[0])
82
- }" in the artifacts directory\nYou can also manually pass a storage file to the deploy task using the --storage STORAGE_FILE_NAME option\n`,
83
- );
84
- // sendErr(
85
- // `Michelson artifact ${filename} has no initial storage specified for the target environment.\nStorage is expected to be specified in .taq/config.json at JSON path: environment.${
86
- // getCurrentEnvironment(parsedArgs)
87
- // }.storage["${filename}"]\nThe value of the above JSON key should be the name of the file (absolute path or relative path with respect to the root of the Taqueria project) that contains the actual value of the storage, as a Michelson expression.\n`,
88
- // );
89
- return retval;
90
- }
91
- return [...(await retval), { filename, storage }];
92
- },
93
- Promise.resolve([] as ContractStorageMapping[]),
94
- );
95
- };
96
-
97
- const mapOpToContract = async (
98
- parsedArgs: Opts,
99
- contracts: ContractStorageMapping[],
100
- op: BatchWalletOperation,
101
- destination: string,
102
- ) => {
103
- const results = await op.operationResults();
104
- const originationResults = results.filter(result => result.kind === 'origination')
105
- .map(result => result as OperationContentsAndResultOrigination);
106
-
107
- return contracts.reduce(
108
- (retval, contract) => {
109
- // If initial storage was provided for the contract
110
- // then we submitted an operation to originate that contract
111
- if (contract.storage) {
112
- // WARNING - using side effect here.
113
- // For each iteration of reduce, results array is being modified-in-place.
114
- // TODO: Adjust to use recursion to avoid side-effect.
115
- const result = originationResults.shift();
116
- const address = result && result.metadata.operation_result.originated_contracts
117
- ? result.metadata.operation_result.originated_contracts.join(',')
118
- : 'Error';
47
+ const getContractInfo = async (parsedArgs: Opts): Promise<ContractInfo> => {
48
+ const contract = parsedArgs.contract;
119
49
 
120
- const alias = parsedArgs.alias ?? basename(contract.filename, extname(contract.filename));
121
- if (address !== 'Error') updateAddressAlias(parsedArgs, alias, address);
50
+ const contractPath = getContractPath(parsedArgs, contract);
51
+ const contractCode = await readFile(contractPath, 'utf-8');
122
52
 
123
- return [
124
- ...retval,
125
- {
126
- contract: contract.filename,
127
- address,
128
- alias: address !== 'Error' ? alias : 'N/A',
129
- destination,
130
- },
131
- ];
132
- }
133
-
134
- return [
135
- ...retval,
136
- {
137
- contract: contract.filename,
138
- address: 'Error',
139
- alias: 'N/A',
140
- destination,
141
- },
142
- ];
143
- },
144
- [] as OriginationResult[],
145
- );
146
- };
147
-
148
- const createBatch = async (parsedArgs: Opts, tezos: TezosToolkit, destination: string) => {
149
- const contracts = await getValidContracts(parsedArgs);
150
- if (!contracts.length) {
151
- return undefined;
53
+ const storageFilename = parsedArgs.storage ?? getDefaultStorageFilename(contract);
54
+ const contractInitStorage = await getInitialStorage(parsedArgs, storageFilename);
55
+ if (contractInitStorage === undefined) {
56
+ return sendAsyncErr(
57
+ `❌ No initial storage file was found for ${contract}\nStorage must be specified in a file as a Michelson expression and will automatically be linked to this contract if specified with the name "${
58
+ getDefaultStorageFilename(contract)
59
+ }" in the artifacts directory\nYou can also manually pass a storage file to the originate task using the --storage STORAGE_FILE_NAME option\n`,
60
+ );
152
61
  }
153
62
 
154
- const batch = await contracts.reduce(
155
- (batch, contractMapping) =>
156
- contractMapping.storage
157
- ? addOrigination(parsedArgs, batch)(contractMapping)
158
- : batch,
159
- Promise.resolve(tezos.wallet.batch()),
160
- );
63
+ return {
64
+ contract,
65
+ code: contractCode,
66
+ initStorage: contractInitStorage,
67
+ mutezTransfer: parseInt(parsedArgs.mutez ?? '0'),
68
+ };
69
+ };
161
70
 
71
+ const createBatchForOriginate = (tezos: TezosToolkit, contractsInfo: ContractInfo[]): WalletOperationBatch =>
72
+ contractsInfo.reduce((acc, contractInfo) =>
73
+ acc.withOrigination({
74
+ code: contractInfo.code,
75
+ init: contractInfo.initStorage,
76
+ balance: contractInfo.mutezTransfer.toString(),
77
+ mutez: true,
78
+ }), tezos.wallet.batch());
79
+
80
+ export const performOriginateOps = async (
81
+ tezos: TezosToolkit,
82
+ env: string,
83
+ contractsInfo: ContractInfo[],
84
+ ): Promise<BatchWalletOperation> => {
85
+ const batch = createBatchForOriginate(tezos, contractsInfo);
162
86
  try {
163
87
  const op = await batch.send();
164
- const confirmed = await op.confirmation();
165
- return await mapOpToContract(parsedArgs, contracts, op, destination);
88
+ await op.confirmation();
89
+ return op;
166
90
  } catch (err) {
167
- const error = (err as { message: string });
168
- if (error.message) {
169
- const msg = error.message;
170
- if (/ENOTFOUND/.test(msg)) {
171
- sendErr(msg + ' - The RPC URL may be invalid. Check ./taq/config.json.\n');
172
- } else if (/ECONNREFUSED/.test(msg)) {
173
- sendErr(msg + ' - The RPC URL may be down or the sandbox is not running.');
174
- } else if (/empty_implicit_contract/.test(msg)) {
175
- const result = msg.match(/(?<="implicit":")tz[^"]+(?=")/);
176
- const publicKeyHash = result ? result[0] : undefined;
177
- if (!publicKeyHash) sendErr(msg);
178
- else {
179
- sendErr(
180
- `The account ${publicKeyHash} for the target environment, "${
181
- getCurrentEnvironment(parsedArgs)
182
- }", may not be funded\nTo fund this account:\n1. Go to https://teztnets.xyz and click "Faucet" of the target testnet\n2. Copy and paste the above key into the 'wallet address field\n3. Request some Tez (Note that you might need to wait for a few seconds for the network to register the funds)`,
183
- );
184
- }
185
- } else {
186
- sendErr(
187
- msg
188
- + " - There was a problem communicating with the chain. Check the RPC URL of the network or sandbox you're targeting in config.json.\n",
189
- );
190
- }
191
- }
192
- return undefined;
91
+ return handleOpsError(err, env);
193
92
  }
194
93
  };
195
94
 
196
- /**
197
- * @description Import a key to sign operation with the side-effect of setting the Tezos instance to use the InMemorySigner provider
198
- *
199
- * @param toolkit The toolkit instance to attach a signer
200
- * @param privateKeyOrEmail Key to load in memory
201
- * @param passphrase If the key is encrypted passphrase to decrypt it
202
- * @param mnemonic Faucet mnemonic
203
- * @param secret Faucet secret
204
- */
205
- export async function importFaucet(
206
- toolkit: TezosToolkit,
207
- privateKeyOrEmail?: string,
208
- passphrase?: string,
209
- mnemonic?: string,
210
- secret?: string,
211
- ) {
212
- if (privateKeyOrEmail && passphrase && mnemonic && secret) {
213
- return await importKey(toolkit, privateKeyOrEmail, passphrase, mnemonic, secret);
214
- } else if (mnemonic) {
215
- const signer = InMemorySigner.fromFundraiser(privateKeyOrEmail ?? '', passphrase ?? '', mnemonic);
216
- toolkit.setProvider({ signer });
217
- const pkh = await signer.publicKeyHash();
218
- let op;
219
- try {
220
- op = await toolkit.tz.activate(pkh, secret ?? '');
221
- if (op) {
222
- await op.confirmation();
223
- }
224
- } catch (ex: any) {
225
- }
226
- } else if (privateKeyOrEmail) {
227
- // Fallback to regular import
228
- const signer = await InMemorySigner.fromSecretKey(privateKeyOrEmail, passphrase);
229
- toolkit.setProvider({ signer });
230
- }
231
- }
232
-
233
- const originateToNetworks = (parsedArgs: Opts, currentEnv: Protocol.Environment.t) =>
234
- currentEnv.networks
235
- ? currentEnv.networks.reduce(
236
- (retval, networkName) => {
237
- const network = getNetworkConfig(parsedArgs)(networkName);
238
- if (network) {
239
- if (network.rpcUrl) {
240
- const result = (async () => {
241
- const tezos = new TezosToolkit(network.rpcUrl as string);
242
- const key = await getAccountPrivateKey(parsedArgs, network, 'taqRootAccount');
243
- await importKey(tezos, key);
244
- return await createBatch(parsedArgs, tezos, networkName);
245
- })();
246
-
247
- return [...retval, result];
248
- } else sendErr(`Network "${networkName}" is missing an RPC url in config.json.`);
249
- } else {
250
- sendErr(
251
- `The current environment is configured to use a network called '${networkName}'; however, no network of this name has been configured in .taq/config.json.`,
252
- );
253
- }
254
-
255
- return retval;
256
- },
257
- [] as Promise<OriginationResult[] | undefined>[],
258
- )
259
- : [];
95
+ const prepContractInfoForDisplay = async (
96
+ parsedArgs: Opts,
97
+ tezos: TezosToolkit,
98
+ contractInfo: ContractInfo,
99
+ op: BatchWalletOperation,
100
+ ): Promise<TableRow> => {
101
+ const operationResults = await op.operationResults();
102
+ const originationResults = operationResults
103
+ .filter(result => result.kind === 'origination')
104
+ .map(result => result as OperationContentsAndResultOrigination);
260
105
 
261
- const originateToSandboxes = (parsedArgs: Opts, currentEnv: Protocol.Environment.t) =>
262
- currentEnv.sandboxes
263
- ? currentEnv.sandboxes.reduce(
264
- (retval, sandboxName) => {
265
- const sandbox = getSandboxConfig(parsedArgs)(sandboxName);
266
- if (sandbox) {
267
- if (sandbox.rpcUrl) {
268
- let defaultAccount = getDefaultAccount(parsedArgs)(sandboxName);
269
- if (!defaultAccount) {
270
- const first = getFirstAccountAlias(sandboxName, parsedArgs);
271
- if (first) {
272
- defaultAccount = getSandboxAccountConfig(parsedArgs)(sandboxName)(first);
273
- // TODO: The error should be a warning, not an error. Descriptive string should not begin with 'Warning:'
274
- sendErr(
275
- `Warning: A default origination account has not been specified for sandbox ${sandboxName}. Taqueria will use the account ${first} for this origination.\nA default account can be specified in .taq/config.json at JSON path: sandbox.${sandboxName}.accounts.default\n`,
276
- );
277
- }
278
- }
279
- if (defaultAccount) {
280
- const secretKey = defaultAccount.secretKey;
281
- const result = (async () => {
282
- const tezos = new TezosToolkit(sandbox.rpcUrl as string);
283
- tezos.setProvider({
284
- signer: new InMemorySigner(secretKey.replace(/^unencrypted:/, '')),
285
- });
286
- return await createBatch(parsedArgs, tezos, sandboxName);
287
- })();
106
+ // Length should be 1 since we are batching originate operations into one
107
+ const result = originationResults.length === 1 ? originationResults[0] : undefined;
108
+ const address = result?.metadata?.operation_result?.originated_contracts?.join(',');
288
109
 
289
- return [...retval, result];
290
- } else sendErr(`No accounts are available for the sandbox called ${sandboxName} to perform origination.`);
291
- } else sendErr(`Sandbox "${sandboxName} is missing an RPC url in config.json."`);
292
- } else {
293
- sendErr(
294
- `The current environment is configured to use a sandbox called '${sandboxName}'; however, no sandbox of this name has been configured in .taq/config.json.`,
295
- );
296
- }
110
+ const alias = parsedArgs.alias ?? basename(contractInfo.contract, extname(contractInfo.contract));
111
+ if (address) await updateAddressAlias(parsedArgs, alias, address);
297
112
 
298
- return retval;
299
- },
300
- [] as Promise<OriginationResult[] | undefined>[],
301
- )
302
- : [];
113
+ return {
114
+ contract: contractInfo.contract,
115
+ address: address ?? 'Something went wrong during origination',
116
+ alias: address ? alias : 'N/A',
117
+ balanceInMutez: contractInfo.mutezTransfer.toString(),
118
+ destination: tezos.rpc.getRpcUrl(),
119
+ };
120
+ };
303
121
 
304
- export const originate = <T>(parsedArgs: Opts) => {
122
+ const originate = async (parsedArgs: Opts): Promise<void> => {
305
123
  const env = getCurrentEnvironmentConfig(parsedArgs);
124
+ if (!env) return sendAsyncErr(`There is no environment called ${parsedArgs.env} in your config.json`);
125
+ try {
126
+ const [envType, nodeConfig] = await getEnvTypeAndNodeConfig(parsedArgs, env);
127
+ const tezos = await (envType === 'Network'
128
+ ? configureToolKitForNetwork(parsedArgs, nodeConfig, parsedArgs.sender)
129
+ : configureToolKitForSandbox(nodeConfig, parsedArgs.sender));
306
130
 
307
- if (!env) {
308
- return sendAsyncErr(`There is no environment called ${parsedArgs.env} in your config.json.`);
309
- }
131
+ const contractInfo = await getContractInfo(parsedArgs);
310
132
 
311
- const jobs = [
312
- ...originateToNetworks(parsedArgs, env),
313
- ...originateToSandboxes(parsedArgs, env),
314
- ];
133
+ const op = await performOriginateOps(tezos, getCurrentEnvironment(parsedArgs), [contractInfo]);
315
134
 
316
- return Promise.all(jobs)
317
- .then(jobs =>
318
- jobs.reduce(
319
- (retval, originations) => {
320
- return originations
321
- ? [...retval as OriginationResult[], ...originations]
322
- : retval;
323
- },
324
- [],
325
- )
326
- )
327
- .then(results => results && results.length > 0 ? sendJsonRes(results) : sendErr(`No contracts originated.`));
135
+ const contractInfoForDisplay = await prepContractInfoForDisplay(parsedArgs, tezos, contractInfo, op);
136
+ return sendJsonRes([contractInfoForDisplay]);
137
+ } catch {
138
+ return sendAsyncErr('No operations performed');
139
+ }
328
140
  };
329
141
 
330
142
  export default originate;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taqueria/plugin-taquito",
3
- "version": "0.21.30",
3
+ "version": "0.23.0-rc.1",
4
4
  "description": "A taqueria plugin for originating smart contracts using Taquito",
5
5
  "targets": {
6
6
  "default": {
@@ -46,7 +46,7 @@
46
46
  "typescript": "^4.7.2"
47
47
  },
48
48
  "dependencies": {
49
- "@taqueria/node-sdk": "^0.21.30",
49
+ "@taqueria/node-sdk": "^0.23.0-rc.1",
50
50
  "@taquito/michel-codec": "^13.0.1",
51
51
  "@taquito/signer": "^13.0.1",
52
52
  "@taquito/taquito": "^13.0.1",
package/taquito.ts CHANGED
@@ -1,28 +1,20 @@
1
1
  import { sendAsyncErr } from '@taqueria/node-sdk';
2
- import { RequestArgs } from '@taqueria/node-sdk/types';
2
+ import { IntersectionOpts as Opts } from './common';
3
+ import fund from './fund';
4
+ import instantiate_account from './instantiate_account';
3
5
  import originate from './originate';
4
6
  import transfer from './transfer';
5
7
 
6
- interface Opts extends RequestArgs.ProxyRequestArgs {
7
- // from originate.ts
8
- storage: string;
9
- alias?: string;
10
- // from transfer.ts
11
- tez?: string;
12
- param?: string;
13
- entrypoint?: string;
14
- // from originate.ts and transfer.ts
15
- contract: string;
16
- }
17
-
18
8
  export const taquito = (parsedArgs: Opts): Promise<void> => {
19
9
  switch (parsedArgs.task) {
20
- case 'originate':
21
10
  case 'deploy':
22
11
  return originate(parsedArgs);
23
12
  case 'transfer':
24
- case 'call':
25
13
  return transfer(parsedArgs);
14
+ case 'instantiate-account':
15
+ return instantiate_account(parsedArgs);
16
+ case 'fund':
17
+ return fund(parsedArgs);
26
18
  default:
27
19
  return sendAsyncErr(`${parsedArgs.task} is not an understood task by the Taquito plugin`);
28
20
  }