@algorandfoundation/algokit-utils 10.0.0-alpha.31 → 10.0.0-alpha.32
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/account-manager.d.ts +448 -0
- package/account-manager.js +623 -0
- package/account-manager.js.map +1 -0
- package/account-manager.mjs +620 -0
- package/account-manager.mjs.map +1 -0
- package/account.d.ts +156 -0
- package/account.js +10 -0
- package/account.js.map +1 -0
- package/account.mjs +9 -0
- package/account.mjs.map +1 -0
- package/algorand-client-transaction-creator.d.ts +1103 -0
- package/algorand-client-transaction-creator.js +735 -0
- package/algorand-client-transaction-creator.js.map +1 -0
- package/algorand-client-transaction-creator.mjs +734 -0
- package/algorand-client-transaction-creator.mjs.map +1 -0
- package/algorand-client-transaction-sender.d.ts +1317 -0
- package/algorand-client-transaction-sender.js +933 -0
- package/algorand-client-transaction-sender.js.map +1 -0
- package/algorand-client-transaction-sender.mjs +932 -0
- package/algorand-client-transaction-sender.mjs.map +1 -0
- package/algorand-client.d.ts +246 -0
- package/algorand-client.js +325 -0
- package/algorand-client.js.map +1 -0
- package/algorand-client.mjs +325 -0
- package/algorand-client.mjs.map +1 -0
- package/amount.d.ts +46 -3
- package/amount.js +92 -13
- package/amount.js.map +1 -1
- package/amount.mjs +80 -3
- package/amount.mjs.map +1 -1
- package/app-client.d.ts +2130 -0
- package/app-client.js +909 -0
- package/app-client.js.map +1 -0
- package/app-client.mjs +908 -0
- package/app-client.mjs.map +1 -0
- package/app-deployer.d.ts +166 -0
- package/app-deployer.js +353 -0
- package/app-deployer.js.map +1 -0
- package/app-deployer.mjs +353 -0
- package/app-deployer.mjs.map +1 -0
- package/app-factory.d.ts +965 -0
- package/app-factory.js +448 -0
- package/app-factory.js.map +1 -0
- package/app-factory.mjs +448 -0
- package/app-factory.mjs.map +1 -0
- package/app-manager.d.ts +323 -0
- package/app-manager.js +468 -0
- package/app-manager.js.map +1 -0
- package/app-manager.mjs +468 -0
- package/app-manager.mjs.map +1 -0
- package/app-spec.d.ts +203 -0
- package/app-spec.js +137 -0
- package/app-spec.js.map +1 -0
- package/app-spec.mjs +137 -0
- package/app-spec.mjs.map +1 -0
- package/app.d.ts +257 -0
- package/app.js +49 -0
- package/app.js.map +1 -0
- package/app.mjs +42 -0
- package/app.mjs.map +1 -0
- package/asset-manager.d.ts +212 -0
- package/asset-manager.js +166 -0
- package/asset-manager.js.map +1 -0
- package/asset-manager.mjs +166 -0
- package/asset-manager.mjs.map +1 -0
- package/async-event-emitter.d.ts +16 -0
- package/async-event-emitter.js +38 -0
- package/async-event-emitter.js.map +1 -0
- package/async-event-emitter.mjs +37 -0
- package/async-event-emitter.mjs.map +1 -0
- package/client-manager.d.ts +475 -0
- package/client-manager.js +616 -0
- package/client-manager.js.map +1 -0
- package/client-manager.mjs +616 -0
- package/client-manager.mjs.map +1 -0
- package/composer.d.ts +947 -0
- package/composer.js +1584 -0
- package/composer.js.map +1 -0
- package/composer.mjs +1583 -0
- package/composer.mjs.map +1 -0
- package/config.d.ts +1 -1
- package/config.js +2 -2
- package/config.js.map +1 -1
- package/config.mjs +1 -1
- package/config.mjs.map +1 -1
- package/debugging.d.ts +47 -0
- package/debugging.js +20 -0
- package/debugging.js.map +1 -0
- package/debugging.mjs +15 -0
- package/debugging.mjs.map +1 -0
- package/dispenser-client.d.ts +90 -0
- package/dispenser-client.js +127 -0
- package/dispenser-client.js.map +1 -0
- package/dispenser-client.mjs +127 -0
- package/dispenser-client.mjs.map +1 -0
- package/expand.d.ts +2 -0
- package/expand.js +0 -0
- package/expand.mjs +0 -0
- package/index.d.ts +6 -5
- package/index.js +4 -3
- package/index.mjs +5 -5
- package/indexer-client/indexer-lookup.d.ts +1 -1
- package/indexer-client/indexer-lookup.js.map +1 -1
- package/indexer-client/indexer-lookup.mjs.map +1 -1
- package/indexer.d.ts +40 -0
- package/indexer.js +38 -0
- package/indexer.js.map +1 -0
- package/indexer.mjs +35 -0
- package/indexer.mjs.map +1 -0
- package/instance-of.d.ts +8 -0
- package/kmd-account-manager.d.ts +74 -0
- package/kmd-account-manager.js +167 -0
- package/kmd-account-manager.js.map +1 -0
- package/kmd-account-manager.mjs +165 -0
- package/kmd-account-manager.mjs.map +1 -0
- package/lifecycle-events.d.ts +14 -0
- package/lifecycle-events.js +11 -0
- package/lifecycle-events.js.map +1 -0
- package/lifecycle-events.mjs +10 -0
- package/lifecycle-events.mjs.map +1 -0
- package/logging.d.ts +13 -0
- package/logging.js +47 -0
- package/logging.js.map +1 -0
- package/logging.mjs +42 -0
- package/logging.mjs.map +1 -0
- package/logic-error.d.ts +39 -0
- package/logic-error.js +54 -0
- package/logic-error.js.map +1 -0
- package/logic-error.mjs +53 -0
- package/logic-error.mjs.map +1 -0
- package/network-client.d.ts +43 -0
- package/network-client.js +14 -0
- package/network-client.js.map +1 -0
- package/network-client.mjs +13 -0
- package/network-client.mjs.map +1 -0
- package/package.json +11 -1
- package/testing/account.d.ts +2 -2
- package/testing/account.js +1 -1
- package/testing/account.js.map +1 -1
- package/testing/account.mjs +1 -1
- package/testing/account.mjs.map +1 -1
- package/testing/fixtures/algokit-log-capture-fixture.d.ts +1 -1
- package/testing/fixtures/algokit-log-capture-fixture.js.map +1 -1
- package/testing/fixtures/algokit-log-capture-fixture.mjs.map +1 -1
- package/testing/fixtures/algorand-fixture.d.ts +2 -2
- package/testing/fixtures/algorand-fixture.js +2 -2
- package/testing/fixtures/algorand-fixture.js.map +1 -1
- package/testing/fixtures/algorand-fixture.mjs +2 -2
- package/testing/fixtures/algorand-fixture.mjs.map +1 -1
- package/testing/index.d.ts +2 -1
- package/testing/test-logger.d.ts +1 -1
- package/testing/test-logger.js.map +1 -1
- package/testing/test-logger.mjs.map +1 -1
- package/testing/types.d.ts +156 -0
- package/transaction/index.d.ts +4 -0
- package/transaction/index.js +9 -0
- package/transaction/index.mjs +4 -0
- package/transaction/perform-transaction-composer-simulate.d.ts +1 -1
- package/transaction/perform-transaction-composer-simulate.js.map +1 -1
- package/transaction/perform-transaction-composer-simulate.mjs.map +1 -1
- package/transaction/transaction.d.ts +2 -2
- package/transaction/transaction.js.map +1 -1
- package/transaction/transaction.mjs.map +1 -1
- package/transaction/types.d.ts +133 -0
- package/transactions/app-call.d.ts +1 -1
- package/transactions/app-call.js +1 -1
- package/transactions/app-call.js.map +1 -1
- package/transactions/app-call.mjs +1 -1
- package/transactions/app-call.mjs.map +1 -1
- package/transactions/common.d.ts +1 -1
- package/transactions/common.js.map +1 -1
- package/transactions/common.mjs.map +1 -1
- package/transactions/method-call.d.ts +1 -1
- package/transactions/method-call.js +1 -1
- package/transactions/method-call.js.map +1 -1
- package/transactions/method-call.mjs +1 -1
- package/transactions/method-call.mjs.map +1 -1
- package/transactions/payment.d.ts +1 -1
- package/transactions/payment.js.map +1 -1
- package/transactions/payment.mjs.map +1 -1
- package/types/account-manager.d.ts +11 -442
- package/types/account-manager.js +5 -616
- package/types/account-manager.js.map +1 -1
- package/types/account-manager.mjs +5 -614
- package/types/account-manager.mjs.map +1 -1
- package/types/account.d.ts +8 -150
- package/types/account.js +3 -4
- package/types/account.js.map +1 -1
- package/types/account.mjs +4 -4
- package/types/account.mjs.map +1 -1
- package/types/algorand-client-transaction-creator.d.ts +5 -1098
- package/types/algorand-client-transaction-creator.js +3 -729
- package/types/algorand-client-transaction-creator.js.map +1 -1
- package/types/algorand-client-transaction-creator.mjs +4 -729
- package/types/algorand-client-transaction-creator.mjs.map +1 -1
- package/types/algorand-client-transaction-sender.d.ts +5 -1312
- package/types/algorand-client-transaction-sender.js +3 -927
- package/types/algorand-client-transaction-sender.js.map +1 -1
- package/types/algorand-client-transaction-sender.mjs +3 -926
- package/types/algorand-client-transaction-sender.mjs.map +1 -1
- package/types/algorand-client.d.ts +5 -241
- package/types/algorand-client.js +3 -319
- package/types/algorand-client.js.map +1 -1
- package/types/algorand-client.mjs +3 -319
- package/types/algorand-client.mjs.map +1 -1
- package/types/amount.d.ts +6 -45
- package/types/amount.js +3 -79
- package/types/amount.js.map +1 -1
- package/types/amount.mjs +4 -79
- package/types/amount.mjs.map +1 -1
- package/types/app-client.d.ts +75 -2125
- package/types/app-client.js +3 -903
- package/types/app-client.js.map +1 -1
- package/types/app-client.mjs +3 -902
- package/types/app-client.mjs.map +1 -1
- package/types/app-deployer.d.ts +21 -161
- package/types/app-deployer.js +3 -347
- package/types/app-deployer.js.map +1 -1
- package/types/app-deployer.mjs +3 -347
- package/types/app-deployer.mjs.map +1 -1
- package/types/app-factory.d.ts +21 -960
- package/types/app-factory.js +3 -442
- package/types/app-factory.js.map +1 -1
- package/types/app-factory.mjs +3 -442
- package/types/app-factory.mjs.map +1 -1
- package/types/app-manager.d.ts +15 -318
- package/types/app-manager.js +3 -462
- package/types/app-manager.js.map +1 -1
- package/types/app-manager.mjs +3 -462
- package/types/app-manager.mjs.map +1 -1
- package/types/app-spec.d.ts +39 -198
- package/types/app-spec.js +3 -131
- package/types/app-spec.js.map +1 -1
- package/types/app-spec.mjs +3 -131
- package/types/app-spec.mjs.map +1 -1
- package/types/app.d.ts +62 -247
- package/types/app.js +15 -37
- package/types/app.js.map +1 -1
- package/types/app.mjs +16 -37
- package/types/app.mjs.map +1 -1
- package/types/asset-manager.d.ts +9 -207
- package/types/asset-manager.js +3 -160
- package/types/asset-manager.js.map +1 -1
- package/types/asset-manager.mjs +3 -160
- package/types/asset-manager.mjs.map +1 -1
- package/types/async-event-emitter.d.ts +7 -11
- package/types/async-event-emitter.js +3 -32
- package/types/async-event-emitter.js.map +1 -1
- package/types/async-event-emitter.mjs +4 -32
- package/types/async-event-emitter.mjs.map +1 -1
- package/types/client-manager.d.ts +27 -470
- package/types/client-manager.js +3 -610
- package/types/client-manager.js.map +1 -1
- package/types/client-manager.mjs +3 -610
- package/types/client-manager.mjs.map +1 -1
- package/types/composer.d.ts +79 -943
- package/types/composer.js +3 -1578
- package/types/composer.js.map +1 -1
- package/types/composer.mjs +3 -1577
- package/types/composer.mjs.map +1 -1
- package/types/config.d.ts +7 -52
- package/types/config.js +3 -74
- package/types/config.js.map +1 -1
- package/types/config.mjs +3 -74
- package/types/config.mjs.map +1 -1
- package/types/debugging.d.ts +12 -37
- package/types/debugging.js +11 -10
- package/types/debugging.js.map +1 -1
- package/types/debugging.mjs +12 -10
- package/types/debugging.mjs.map +1 -1
- package/types/dispenser-client.d.ts +11 -85
- package/types/dispenser-client.js +3 -121
- package/types/dispenser-client.js.map +1 -1
- package/types/dispenser-client.mjs +3 -121
- package/types/dispenser-client.mjs.map +1 -1
- package/types/expand.d.ts +8 -2
- package/types/indexer.d.ts +16 -36
- package/types/indexer.js +7 -30
- package/types/indexer.js.map +1 -1
- package/types/indexer.mjs +8 -30
- package/types/indexer.mjs.map +1 -1
- package/types/instance-of.d.ts +4 -4
- package/types/kmd-account-manager.d.ts +5 -69
- package/types/kmd-account-manager.js +3 -161
- package/types/kmd-account-manager.js.map +1 -1
- package/types/kmd-account-manager.mjs +3 -159
- package/types/kmd-account-manager.mjs.map +1 -1
- package/types/lifecycle-events.d.ts +7 -9
- package/types/lifecycle-events.js +3 -5
- package/types/lifecycle-events.js.map +1 -1
- package/types/lifecycle-events.mjs +4 -5
- package/types/lifecycle-events.mjs.map +1 -1
- package/types/logging.d.ts +14 -9
- package/types/logging.js +11 -37
- package/types/logging.js.map +1 -1
- package/types/logging.mjs +12 -37
- package/types/logging.mjs.map +1 -1
- package/types/logic-error.d.ts +8 -35
- package/types/logic-error.js +3 -48
- package/types/logic-error.js.map +1 -1
- package/types/logic-error.mjs +4 -48
- package/types/logic-error.mjs.map +1 -1
- package/types/network-client.d.ts +10 -39
- package/types/network-client.js +3 -8
- package/types/network-client.js.map +1 -1
- package/types/network-client.mjs +4 -8
- package/types/network-client.mjs.map +1 -1
- package/types/testing.d.ts +13 -151
- package/types/transaction.d.ts +33 -128
- package/updatable-config.d.ts +57 -0
- package/updatable-config.js +80 -0
- package/updatable-config.js.map +1 -0
- package/updatable-config.mjs +80 -0
- package/updatable-config.mjs.map +1 -0
- package/util.js +1 -1
- package/util.js.map +1 -1
- package/util.mjs +1 -1
- package/util.mjs.map +1 -1
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.js');
|
|
2
|
+
const require_address = require('./packages/common/src/address.js');
|
|
3
|
+
const require_amount = require('./amount.js');
|
|
4
|
+
const require_config = require('./config.js');
|
|
5
|
+
const require_signer = require('./packages/transact/src/signer.js');
|
|
6
|
+
const require_composer = require('./composer.js');
|
|
7
|
+
const require_client_manager = require('./client-manager.js');
|
|
8
|
+
let tweetnacl = require("tweetnacl");
|
|
9
|
+
tweetnacl = require_rolldown_runtime.__toESM(tweetnacl);
|
|
10
|
+
|
|
11
|
+
//#region src/kmd-account-manager.ts
|
|
12
|
+
/** Provides abstractions over a [KMD](https://github.com/algorand/go-algorand/blob/master/daemon/kmd/README.md) instance
|
|
13
|
+
* that makes it easier to get and manage accounts using KMD. */
|
|
14
|
+
var KmdAccountManager = class {
|
|
15
|
+
_clientManager;
|
|
16
|
+
_kmd;
|
|
17
|
+
/**
|
|
18
|
+
* Create a new KMD manager.
|
|
19
|
+
* @param clientManager A ClientManager client to use for algod and kmd clients
|
|
20
|
+
*/
|
|
21
|
+
constructor(clientManager) {
|
|
22
|
+
this._clientManager = clientManager;
|
|
23
|
+
try {
|
|
24
|
+
this._kmd = clientManager.kmd;
|
|
25
|
+
} catch {
|
|
26
|
+
this._kmd = void 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async kmd() {
|
|
30
|
+
if (this._kmd === void 0) {
|
|
31
|
+
if (await this._clientManager.isLocalNet()) {
|
|
32
|
+
const { kmdConfig } = require_client_manager.ClientManager.getConfigFromEnvironmentOrLocalNet();
|
|
33
|
+
if (kmdConfig) {
|
|
34
|
+
this._kmd = require_client_manager.ClientManager.getKmdClient(kmdConfig);
|
|
35
|
+
return this._kmd;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
this._kmd = null;
|
|
39
|
+
}
|
|
40
|
+
if (!this._kmd) throw new Error("Attempt to use Kmd client in AlgoKit instance with no Kmd configured");
|
|
41
|
+
return this._kmd;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Returns an Algorand signing account with private key loaded from the given KMD wallet (identified by name).
|
|
45
|
+
*
|
|
46
|
+
* @param walletName The name of the wallet to retrieve an account from
|
|
47
|
+
* @param predicate An optional filter to use to find the account (otherwise it will return a random account from the wallet)
|
|
48
|
+
* @param sender The optional sender address to use this signer for (aka a rekeyed account)
|
|
49
|
+
* @example Get default funded account in a LocalNet
|
|
50
|
+
*
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const defaultDispenserAccount = await kmdAccountManager.getWalletAccount(
|
|
53
|
+
* 'unencrypted-default-wallet',
|
|
54
|
+
* a => a.status !== 'Offline' && a.amount > 1_000_000_000
|
|
55
|
+
* )
|
|
56
|
+
* ```
|
|
57
|
+
* @returns The signing account (with private key loaded) or undefined if no matching wallet or account was found
|
|
58
|
+
*/
|
|
59
|
+
async getWalletAccount(walletName, predicate, sender) {
|
|
60
|
+
return this.findWalletAccount(walletName, predicate, sender);
|
|
61
|
+
}
|
|
62
|
+
async findWalletAccount(walletName, predicateOrAddress, sender) {
|
|
63
|
+
const kmd = await this.kmd();
|
|
64
|
+
const wallet = (await kmd.listWallets()).wallets.filter((w) => w.name === walletName);
|
|
65
|
+
if (wallet.length === 0) return;
|
|
66
|
+
const walletHandle = (await kmd.initWalletHandle({
|
|
67
|
+
walletId: wallet[0].id,
|
|
68
|
+
walletPassword: ""
|
|
69
|
+
})).walletHandleToken;
|
|
70
|
+
let matchedAddress = void 0;
|
|
71
|
+
if (predicateOrAddress && typeof predicateOrAddress === "string") matchedAddress = require_address.Address.fromString(predicateOrAddress);
|
|
72
|
+
else {
|
|
73
|
+
const addresses = (await kmd.listKeysInWallet({ walletHandleToken: walletHandle })).addresses;
|
|
74
|
+
if (addresses.length > 0) if (predicateOrAddress && typeof predicateOrAddress === "function") {
|
|
75
|
+
for (let i = 0; i < addresses.length; i++) if (predicateOrAddress(await this._clientManager.algod.accountInformation(addresses[i]))) {
|
|
76
|
+
matchedAddress = addresses[i];
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
} else matchedAddress = addresses[0];
|
|
80
|
+
}
|
|
81
|
+
if (!matchedAddress) return;
|
|
82
|
+
const accountKey = (await kmd.exportKey({
|
|
83
|
+
walletHandleToken: walletHandle,
|
|
84
|
+
address: matchedAddress
|
|
85
|
+
})).privateKey;
|
|
86
|
+
const keys = tweetnacl.default.sign.keyPair.fromSecretKey(accountKey);
|
|
87
|
+
const rawSigner = async (bytesToSign) => {
|
|
88
|
+
return tweetnacl.default.sign.detached(bytesToSign, keys.secretKey);
|
|
89
|
+
};
|
|
90
|
+
return require_signer.generateAddressWithSigners({
|
|
91
|
+
ed25519Pubkey: keys.publicKey,
|
|
92
|
+
sendingAddress: require_address.getOptionalAddress(sender),
|
|
93
|
+
rawEd25519Signer: rawSigner
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Gets an account with private key loaded from a KMD wallet of the given name, or alternatively creates one with funds in it via a KMD wallet of the given name.
|
|
98
|
+
*
|
|
99
|
+
* This is useful to get idempotent accounts from LocalNet without having to specify the private key (which will change when resetting the LocalNet).
|
|
100
|
+
*
|
|
101
|
+
* This significantly speeds up local dev time and improves experience since you can write code that *just works* first go without manual config in a fresh LocalNet.
|
|
102
|
+
*
|
|
103
|
+
* If this is used via `mnemonicAccountFromEnvironment`, then you can even use the same code that runs on production without changes for local development!
|
|
104
|
+
*
|
|
105
|
+
* @param name The name of the wallet to retrieve / create
|
|
106
|
+
* @param fundWith The number of Algo to fund the account with when it gets created, if not specified then 1000 ALGO will be funded from the dispenser account
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* // Idempotently get (if exists) or create (if it doesn't exist yet) an account by name using KMD
|
|
111
|
+
* // if creating it then fund it with 2 ALGO from the default dispenser account
|
|
112
|
+
* const newAccount = await kmdAccountManager.getOrCreateWalletAccount('account1', (2).algo())
|
|
113
|
+
* // This will return the same account as above since the name matches
|
|
114
|
+
* const existingAccount = await kmdAccountManager.getOrCreateWalletAccount('account1')
|
|
115
|
+
* ```
|
|
116
|
+
*
|
|
117
|
+
* @returns An Algorand account with private key loaded - either one that already existed in the given KMD wallet, or a new one that is funded for you
|
|
118
|
+
*/
|
|
119
|
+
async getOrCreateWalletAccount(name, fundWith) {
|
|
120
|
+
const existing = await this.getWalletAccount(name);
|
|
121
|
+
if (existing) return existing;
|
|
122
|
+
const kmd = await this.kmd();
|
|
123
|
+
const walletId = (await kmd.createWallet({
|
|
124
|
+
walletName: name,
|
|
125
|
+
walletPassword: ""
|
|
126
|
+
})).wallet.id;
|
|
127
|
+
const walletHandle = (await kmd.initWalletHandle({
|
|
128
|
+
walletId,
|
|
129
|
+
walletPassword: ""
|
|
130
|
+
})).walletHandleToken;
|
|
131
|
+
await kmd.generateKey({ walletHandleToken: walletHandle });
|
|
132
|
+
const account = await this.getWalletAccount(name);
|
|
133
|
+
require_config.Config.logger.info(`LocalNet account '${name}' doesn't yet exist; created account ${account.addr} with keys stored in KMD and funding with ${fundWith?.algo ?? 1e3} ALGO`);
|
|
134
|
+
const dispenser = await this.getLocalNetDispenserAccount();
|
|
135
|
+
await new require_composer.TransactionComposer({
|
|
136
|
+
algod: this._clientManager.algod,
|
|
137
|
+
getSigner: () => dispenser.signer,
|
|
138
|
+
getSuggestedParams: () => this._clientManager.algod.suggestedParams()
|
|
139
|
+
}).addPayment({
|
|
140
|
+
amount: fundWith ?? require_amount.AlgoAmount.Algo(1e3),
|
|
141
|
+
receiver: account.addr,
|
|
142
|
+
sender: dispenser.addr
|
|
143
|
+
}).send();
|
|
144
|
+
return account;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Returns an Algorand account with private key loaded for the default LocalNet dispenser account (that can be used to fund other accounts).
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* const dispenser = await kmdAccountManager.getLocalNetDispenserAccount()
|
|
151
|
+
* ```
|
|
152
|
+
* @returns The default LocalNet dispenser account
|
|
153
|
+
*/
|
|
154
|
+
async getLocalNetDispenserAccount() {
|
|
155
|
+
if (!await this._clientManager.isLocalNet()) throw new Error("Can't get LocalNet dispenser account from non LocalNet network");
|
|
156
|
+
const dispenserAddresses = (await this._clientManager.algod.genesis()).alloc.filter((a) => a.comment === "Wallet1").map((a) => a.addr);
|
|
157
|
+
if (dispenserAddresses.length > 0) {
|
|
158
|
+
const dispenser = await this.findWalletAccount("unencrypted-default-wallet", dispenserAddresses[0]);
|
|
159
|
+
if (dispenser) return dispenser;
|
|
160
|
+
}
|
|
161
|
+
throw new Error("Error retrieving LocalNet dispenser account; couldn't find the default account in KMD");
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
//#endregion
|
|
166
|
+
exports.KmdAccountManager = KmdAccountManager;
|
|
167
|
+
//# sourceMappingURL=kmd-account-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kmd-account-manager.js","names":["ClientManager","matchedAddress: Address | undefined","Address","nacl","generateAddressWithSigners","getOptionalAddress","TransactionComposer","AlgoAmount"],"sources":["../src/kmd-account-manager.ts"],"sourcesContent":["import { Account } from '@algorandfoundation/algokit-algod-client'\nimport { Address, getOptionalAddress } from '@algorandfoundation/algokit-common'\nimport { KmdClient } from '@algorandfoundation/algokit-kmd-client'\nimport { AddressWithTransactionSigner, generateAddressWithSigners } from '@algorandfoundation/algokit-transact'\nimport nacl from 'tweetnacl'\nimport { AlgoAmount } from './amount'\nimport { ClientManager } from './client-manager'\nimport { TransactionComposer } from './composer'\nimport { Config } from './config'\n\n/** Provides abstractions over a [KMD](https://github.com/algorand/go-algorand/blob/master/daemon/kmd/README.md) instance\n * that makes it easier to get and manage accounts using KMD. */\nexport class KmdAccountManager {\n private _clientManager: Omit<ClientManager, 'kmd'>\n private _kmd?: KmdClient | null\n\n /**\n * Create a new KMD manager.\n * @param clientManager A ClientManager client to use for algod and kmd clients\n */\n constructor(clientManager: ClientManager) {\n this._clientManager = clientManager\n try {\n this._kmd = clientManager.kmd\n } catch {\n this._kmd = undefined\n }\n }\n\n async kmd(): Promise<KmdClient> {\n if (this._kmd === undefined) {\n if (await this._clientManager.isLocalNet()) {\n const { kmdConfig } = ClientManager.getConfigFromEnvironmentOrLocalNet()\n if (kmdConfig) {\n this._kmd = ClientManager.getKmdClient(kmdConfig)\n return this._kmd\n }\n }\n this._kmd = null\n }\n\n if (!this._kmd) {\n throw new Error('Attempt to use Kmd client in AlgoKit instance with no Kmd configured')\n }\n\n return this._kmd\n }\n\n /**\n * Returns an Algorand signing account with private key loaded from the given KMD wallet (identified by name).\n *\n * @param walletName The name of the wallet to retrieve an account from\n * @param predicate An optional filter to use to find the account (otherwise it will return a random account from the wallet)\n * @param sender The optional sender address to use this signer for (aka a rekeyed account)\n * @example Get default funded account in a LocalNet\n *\n * ```typescript\n * const defaultDispenserAccount = await kmdAccountManager.getWalletAccount(\n * 'unencrypted-default-wallet',\n * a => a.status !== 'Offline' && a.amount > 1_000_000_000\n * )\n * ```\n * @returns The signing account (with private key loaded) or undefined if no matching wallet or account was found\n */\n public async getWalletAccount(\n walletName: string,\n predicate?: (account: Account) => boolean,\n sender?: string | Address,\n ): Promise<AddressWithTransactionSigner | undefined> {\n return this.findWalletAccount(walletName, predicate, sender)\n }\n\n private async findWalletAccount(\n walletName: string,\n predicateOrAddress?: ((account: Account) => boolean) | string,\n sender?: string | Address,\n ): Promise<AddressWithTransactionSigner | undefined> {\n const kmd = await this.kmd()\n const walletsResponse = await kmd.listWallets()\n const wallet = walletsResponse.wallets.filter((w) => w.name === walletName)\n if (wallet.length === 0) {\n return undefined\n }\n const walletId = wallet[0].id\n const walletHandle = (await kmd.initWalletHandle({ walletId, walletPassword: '' })).walletHandleToken\n\n let matchedAddress: Address | undefined = undefined\n if (predicateOrAddress && typeof predicateOrAddress === 'string') {\n matchedAddress = Address.fromString(predicateOrAddress)\n } else {\n const addresses = (await kmd.listKeysInWallet({ walletHandleToken: walletHandle })).addresses\n if (addresses.length > 0) {\n if (predicateOrAddress && typeof predicateOrAddress === 'function') {\n for (let i = 0; i < addresses.length; i++) {\n const account = await this._clientManager.algod.accountInformation(addresses[i])\n if (predicateOrAddress(account)) {\n matchedAddress = addresses[i]\n break\n }\n }\n } else {\n matchedAddress = addresses[0]\n }\n }\n }\n\n if (!matchedAddress) {\n return undefined\n }\n\n const accountKey = (await kmd.exportKey({ walletHandleToken: walletHandle, address: matchedAddress })).privateKey\n const keys = nacl.sign.keyPair.fromSecretKey(accountKey)\n const rawSigner = async (bytesToSign: Uint8Array): Promise<Uint8Array> => {\n return nacl.sign.detached(bytesToSign, keys.secretKey)\n }\n\n return generateAddressWithSigners({\n ed25519Pubkey: keys.publicKey,\n sendingAddress: getOptionalAddress(sender),\n rawEd25519Signer: rawSigner,\n })\n }\n\n /**\n * Gets an account with private key loaded from a KMD wallet of the given name, or alternatively creates one with funds in it via a KMD wallet of the given name.\n *\n * This is useful to get idempotent accounts from LocalNet without having to specify the private key (which will change when resetting the LocalNet).\n *\n * This significantly speeds up local dev time and improves experience since you can write code that *just works* first go without manual config in a fresh LocalNet.\n *\n * If this is used via `mnemonicAccountFromEnvironment`, then you can even use the same code that runs on production without changes for local development!\n *\n * @param name The name of the wallet to retrieve / create\n * @param fundWith The number of Algo to fund the account with when it gets created, if not specified then 1000 ALGO will be funded from the dispenser account\n *\n * @example\n * ```typescript\n * // Idempotently get (if exists) or create (if it doesn't exist yet) an account by name using KMD\n * // if creating it then fund it with 2 ALGO from the default dispenser account\n * const newAccount = await kmdAccountManager.getOrCreateWalletAccount('account1', (2).algo())\n * // This will return the same account as above since the name matches\n * const existingAccount = await kmdAccountManager.getOrCreateWalletAccount('account1')\n * ```\n *\n * @returns An Algorand account with private key loaded - either one that already existed in the given KMD wallet, or a new one that is funded for you\n */\n public async getOrCreateWalletAccount(name: string, fundWith?: AlgoAmount): Promise<AddressWithTransactionSigner> {\n // Get an existing account from the KMD wallet\n const existing = await this.getWalletAccount(name)\n if (existing) {\n return existing\n }\n\n const kmd = await this.kmd()\n\n // None existed: create the KMD wallet instead\n const walletId = (await kmd.createWallet({ walletName: name, walletPassword: '' })).wallet.id\n const walletHandle = (await kmd.initWalletHandle({ walletId, walletPassword: '' })).walletHandleToken\n await kmd.generateKey({ walletHandleToken: walletHandle })\n\n // Get the account from the new KMD wallet\n const account = (await this.getWalletAccount(name))!\n\n Config.logger.info(\n `LocalNet account '${name}' doesn't yet exist; created account ${account.addr} with keys stored in KMD and funding with ${\n fundWith?.algo ?? 1000\n } ALGO`,\n )\n\n // Fund the account from the dispenser\n const dispenser = await this.getLocalNetDispenserAccount()\n await new TransactionComposer({\n algod: this._clientManager.algod,\n getSigner: () => dispenser.signer,\n getSuggestedParams: () => this._clientManager.algod.suggestedParams(),\n })\n .addPayment({ amount: fundWith ?? AlgoAmount.Algo(1000), receiver: account.addr, sender: dispenser.addr })\n .send()\n\n return account\n }\n\n /**\n * Returns an Algorand account with private key loaded for the default LocalNet dispenser account (that can be used to fund other accounts).\n * @example\n * ```typescript\n * const dispenser = await kmdAccountManager.getLocalNetDispenserAccount()\n * ```\n * @returns The default LocalNet dispenser account\n */\n public async getLocalNetDispenserAccount() {\n if (!(await this._clientManager.isLocalNet())) {\n throw new Error(\"Can't get LocalNet dispenser account from non LocalNet network\")\n }\n const genesisResponse = await this._clientManager.algod.genesis()\n const dispenserAddresses = genesisResponse.alloc.filter((a) => a.comment === 'Wallet1').map((a) => a.addr)\n if (dispenserAddresses.length > 0) {\n const dispenser = await this.findWalletAccount('unencrypted-default-wallet', dispenserAddresses[0])\n if (dispenser) {\n return dispenser\n }\n }\n\n throw new Error(\"Error retrieving LocalNet dispenser account; couldn't find the default account in KMD\")\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { Address, getOptionalAddress } from "./packages/common/src/address.mjs";
|
|
2
|
+
import { AlgoAmount } from "./amount.mjs";
|
|
3
|
+
import { Config } from "./config.mjs";
|
|
4
|
+
import { generateAddressWithSigners } from "./packages/transact/src/signer.mjs";
|
|
5
|
+
import { TransactionComposer } from "./composer.mjs";
|
|
6
|
+
import { ClientManager } from "./client-manager.mjs";
|
|
7
|
+
import nacl from "tweetnacl";
|
|
8
|
+
|
|
9
|
+
//#region src/kmd-account-manager.ts
|
|
10
|
+
/** Provides abstractions over a [KMD](https://github.com/algorand/go-algorand/blob/master/daemon/kmd/README.md) instance
|
|
11
|
+
* that makes it easier to get and manage accounts using KMD. */
|
|
12
|
+
var KmdAccountManager = class {
|
|
13
|
+
_clientManager;
|
|
14
|
+
_kmd;
|
|
15
|
+
/**
|
|
16
|
+
* Create a new KMD manager.
|
|
17
|
+
* @param clientManager A ClientManager client to use for algod and kmd clients
|
|
18
|
+
*/
|
|
19
|
+
constructor(clientManager) {
|
|
20
|
+
this._clientManager = clientManager;
|
|
21
|
+
try {
|
|
22
|
+
this._kmd = clientManager.kmd;
|
|
23
|
+
} catch {
|
|
24
|
+
this._kmd = void 0;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async kmd() {
|
|
28
|
+
if (this._kmd === void 0) {
|
|
29
|
+
if (await this._clientManager.isLocalNet()) {
|
|
30
|
+
const { kmdConfig } = ClientManager.getConfigFromEnvironmentOrLocalNet();
|
|
31
|
+
if (kmdConfig) {
|
|
32
|
+
this._kmd = ClientManager.getKmdClient(kmdConfig);
|
|
33
|
+
return this._kmd;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
this._kmd = null;
|
|
37
|
+
}
|
|
38
|
+
if (!this._kmd) throw new Error("Attempt to use Kmd client in AlgoKit instance with no Kmd configured");
|
|
39
|
+
return this._kmd;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Returns an Algorand signing account with private key loaded from the given KMD wallet (identified by name).
|
|
43
|
+
*
|
|
44
|
+
* @param walletName The name of the wallet to retrieve an account from
|
|
45
|
+
* @param predicate An optional filter to use to find the account (otherwise it will return a random account from the wallet)
|
|
46
|
+
* @param sender The optional sender address to use this signer for (aka a rekeyed account)
|
|
47
|
+
* @example Get default funded account in a LocalNet
|
|
48
|
+
*
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const defaultDispenserAccount = await kmdAccountManager.getWalletAccount(
|
|
51
|
+
* 'unencrypted-default-wallet',
|
|
52
|
+
* a => a.status !== 'Offline' && a.amount > 1_000_000_000
|
|
53
|
+
* )
|
|
54
|
+
* ```
|
|
55
|
+
* @returns The signing account (with private key loaded) or undefined if no matching wallet or account was found
|
|
56
|
+
*/
|
|
57
|
+
async getWalletAccount(walletName, predicate, sender) {
|
|
58
|
+
return this.findWalletAccount(walletName, predicate, sender);
|
|
59
|
+
}
|
|
60
|
+
async findWalletAccount(walletName, predicateOrAddress, sender) {
|
|
61
|
+
const kmd = await this.kmd();
|
|
62
|
+
const wallet = (await kmd.listWallets()).wallets.filter((w) => w.name === walletName);
|
|
63
|
+
if (wallet.length === 0) return;
|
|
64
|
+
const walletHandle = (await kmd.initWalletHandle({
|
|
65
|
+
walletId: wallet[0].id,
|
|
66
|
+
walletPassword: ""
|
|
67
|
+
})).walletHandleToken;
|
|
68
|
+
let matchedAddress = void 0;
|
|
69
|
+
if (predicateOrAddress && typeof predicateOrAddress === "string") matchedAddress = Address.fromString(predicateOrAddress);
|
|
70
|
+
else {
|
|
71
|
+
const addresses = (await kmd.listKeysInWallet({ walletHandleToken: walletHandle })).addresses;
|
|
72
|
+
if (addresses.length > 0) if (predicateOrAddress && typeof predicateOrAddress === "function") {
|
|
73
|
+
for (let i = 0; i < addresses.length; i++) if (predicateOrAddress(await this._clientManager.algod.accountInformation(addresses[i]))) {
|
|
74
|
+
matchedAddress = addresses[i];
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
} else matchedAddress = addresses[0];
|
|
78
|
+
}
|
|
79
|
+
if (!matchedAddress) return;
|
|
80
|
+
const accountKey = (await kmd.exportKey({
|
|
81
|
+
walletHandleToken: walletHandle,
|
|
82
|
+
address: matchedAddress
|
|
83
|
+
})).privateKey;
|
|
84
|
+
const keys = nacl.sign.keyPair.fromSecretKey(accountKey);
|
|
85
|
+
const rawSigner = async (bytesToSign) => {
|
|
86
|
+
return nacl.sign.detached(bytesToSign, keys.secretKey);
|
|
87
|
+
};
|
|
88
|
+
return generateAddressWithSigners({
|
|
89
|
+
ed25519Pubkey: keys.publicKey,
|
|
90
|
+
sendingAddress: getOptionalAddress(sender),
|
|
91
|
+
rawEd25519Signer: rawSigner
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Gets an account with private key loaded from a KMD wallet of the given name, or alternatively creates one with funds in it via a KMD wallet of the given name.
|
|
96
|
+
*
|
|
97
|
+
* This is useful to get idempotent accounts from LocalNet without having to specify the private key (which will change when resetting the LocalNet).
|
|
98
|
+
*
|
|
99
|
+
* This significantly speeds up local dev time and improves experience since you can write code that *just works* first go without manual config in a fresh LocalNet.
|
|
100
|
+
*
|
|
101
|
+
* If this is used via `mnemonicAccountFromEnvironment`, then you can even use the same code that runs on production without changes for local development!
|
|
102
|
+
*
|
|
103
|
+
* @param name The name of the wallet to retrieve / create
|
|
104
|
+
* @param fundWith The number of Algo to fund the account with when it gets created, if not specified then 1000 ALGO will be funded from the dispenser account
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* // Idempotently get (if exists) or create (if it doesn't exist yet) an account by name using KMD
|
|
109
|
+
* // if creating it then fund it with 2 ALGO from the default dispenser account
|
|
110
|
+
* const newAccount = await kmdAccountManager.getOrCreateWalletAccount('account1', (2).algo())
|
|
111
|
+
* // This will return the same account as above since the name matches
|
|
112
|
+
* const existingAccount = await kmdAccountManager.getOrCreateWalletAccount('account1')
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* @returns An Algorand account with private key loaded - either one that already existed in the given KMD wallet, or a new one that is funded for you
|
|
116
|
+
*/
|
|
117
|
+
async getOrCreateWalletAccount(name, fundWith) {
|
|
118
|
+
const existing = await this.getWalletAccount(name);
|
|
119
|
+
if (existing) return existing;
|
|
120
|
+
const kmd = await this.kmd();
|
|
121
|
+
const walletId = (await kmd.createWallet({
|
|
122
|
+
walletName: name,
|
|
123
|
+
walletPassword: ""
|
|
124
|
+
})).wallet.id;
|
|
125
|
+
const walletHandle = (await kmd.initWalletHandle({
|
|
126
|
+
walletId,
|
|
127
|
+
walletPassword: ""
|
|
128
|
+
})).walletHandleToken;
|
|
129
|
+
await kmd.generateKey({ walletHandleToken: walletHandle });
|
|
130
|
+
const account = await this.getWalletAccount(name);
|
|
131
|
+
Config.logger.info(`LocalNet account '${name}' doesn't yet exist; created account ${account.addr} with keys stored in KMD and funding with ${fundWith?.algo ?? 1e3} ALGO`);
|
|
132
|
+
const dispenser = await this.getLocalNetDispenserAccount();
|
|
133
|
+
await new TransactionComposer({
|
|
134
|
+
algod: this._clientManager.algod,
|
|
135
|
+
getSigner: () => dispenser.signer,
|
|
136
|
+
getSuggestedParams: () => this._clientManager.algod.suggestedParams()
|
|
137
|
+
}).addPayment({
|
|
138
|
+
amount: fundWith ?? AlgoAmount.Algo(1e3),
|
|
139
|
+
receiver: account.addr,
|
|
140
|
+
sender: dispenser.addr
|
|
141
|
+
}).send();
|
|
142
|
+
return account;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Returns an Algorand account with private key loaded for the default LocalNet dispenser account (that can be used to fund other accounts).
|
|
146
|
+
* @example
|
|
147
|
+
* ```typescript
|
|
148
|
+
* const dispenser = await kmdAccountManager.getLocalNetDispenserAccount()
|
|
149
|
+
* ```
|
|
150
|
+
* @returns The default LocalNet dispenser account
|
|
151
|
+
*/
|
|
152
|
+
async getLocalNetDispenserAccount() {
|
|
153
|
+
if (!await this._clientManager.isLocalNet()) throw new Error("Can't get LocalNet dispenser account from non LocalNet network");
|
|
154
|
+
const dispenserAddresses = (await this._clientManager.algod.genesis()).alloc.filter((a) => a.comment === "Wallet1").map((a) => a.addr);
|
|
155
|
+
if (dispenserAddresses.length > 0) {
|
|
156
|
+
const dispenser = await this.findWalletAccount("unencrypted-default-wallet", dispenserAddresses[0]);
|
|
157
|
+
if (dispenser) return dispenser;
|
|
158
|
+
}
|
|
159
|
+
throw new Error("Error retrieving LocalNet dispenser account; couldn't find the default account in KMD");
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
//#endregion
|
|
164
|
+
export { KmdAccountManager };
|
|
165
|
+
//# sourceMappingURL=kmd-account-manager.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kmd-account-manager.mjs","names":["matchedAddress: Address | undefined"],"sources":["../src/kmd-account-manager.ts"],"sourcesContent":["import { Account } from '@algorandfoundation/algokit-algod-client'\nimport { Address, getOptionalAddress } from '@algorandfoundation/algokit-common'\nimport { KmdClient } from '@algorandfoundation/algokit-kmd-client'\nimport { AddressWithTransactionSigner, generateAddressWithSigners } from '@algorandfoundation/algokit-transact'\nimport nacl from 'tweetnacl'\nimport { AlgoAmount } from './amount'\nimport { ClientManager } from './client-manager'\nimport { TransactionComposer } from './composer'\nimport { Config } from './config'\n\n/** Provides abstractions over a [KMD](https://github.com/algorand/go-algorand/blob/master/daemon/kmd/README.md) instance\n * that makes it easier to get and manage accounts using KMD. */\nexport class KmdAccountManager {\n private _clientManager: Omit<ClientManager, 'kmd'>\n private _kmd?: KmdClient | null\n\n /**\n * Create a new KMD manager.\n * @param clientManager A ClientManager client to use for algod and kmd clients\n */\n constructor(clientManager: ClientManager) {\n this._clientManager = clientManager\n try {\n this._kmd = clientManager.kmd\n } catch {\n this._kmd = undefined\n }\n }\n\n async kmd(): Promise<KmdClient> {\n if (this._kmd === undefined) {\n if (await this._clientManager.isLocalNet()) {\n const { kmdConfig } = ClientManager.getConfigFromEnvironmentOrLocalNet()\n if (kmdConfig) {\n this._kmd = ClientManager.getKmdClient(kmdConfig)\n return this._kmd\n }\n }\n this._kmd = null\n }\n\n if (!this._kmd) {\n throw new Error('Attempt to use Kmd client in AlgoKit instance with no Kmd configured')\n }\n\n return this._kmd\n }\n\n /**\n * Returns an Algorand signing account with private key loaded from the given KMD wallet (identified by name).\n *\n * @param walletName The name of the wallet to retrieve an account from\n * @param predicate An optional filter to use to find the account (otherwise it will return a random account from the wallet)\n * @param sender The optional sender address to use this signer for (aka a rekeyed account)\n * @example Get default funded account in a LocalNet\n *\n * ```typescript\n * const defaultDispenserAccount = await kmdAccountManager.getWalletAccount(\n * 'unencrypted-default-wallet',\n * a => a.status !== 'Offline' && a.amount > 1_000_000_000\n * )\n * ```\n * @returns The signing account (with private key loaded) or undefined if no matching wallet or account was found\n */\n public async getWalletAccount(\n walletName: string,\n predicate?: (account: Account) => boolean,\n sender?: string | Address,\n ): Promise<AddressWithTransactionSigner | undefined> {\n return this.findWalletAccount(walletName, predicate, sender)\n }\n\n private async findWalletAccount(\n walletName: string,\n predicateOrAddress?: ((account: Account) => boolean) | string,\n sender?: string | Address,\n ): Promise<AddressWithTransactionSigner | undefined> {\n const kmd = await this.kmd()\n const walletsResponse = await kmd.listWallets()\n const wallet = walletsResponse.wallets.filter((w) => w.name === walletName)\n if (wallet.length === 0) {\n return undefined\n }\n const walletId = wallet[0].id\n const walletHandle = (await kmd.initWalletHandle({ walletId, walletPassword: '' })).walletHandleToken\n\n let matchedAddress: Address | undefined = undefined\n if (predicateOrAddress && typeof predicateOrAddress === 'string') {\n matchedAddress = Address.fromString(predicateOrAddress)\n } else {\n const addresses = (await kmd.listKeysInWallet({ walletHandleToken: walletHandle })).addresses\n if (addresses.length > 0) {\n if (predicateOrAddress && typeof predicateOrAddress === 'function') {\n for (let i = 0; i < addresses.length; i++) {\n const account = await this._clientManager.algod.accountInformation(addresses[i])\n if (predicateOrAddress(account)) {\n matchedAddress = addresses[i]\n break\n }\n }\n } else {\n matchedAddress = addresses[0]\n }\n }\n }\n\n if (!matchedAddress) {\n return undefined\n }\n\n const accountKey = (await kmd.exportKey({ walletHandleToken: walletHandle, address: matchedAddress })).privateKey\n const keys = nacl.sign.keyPair.fromSecretKey(accountKey)\n const rawSigner = async (bytesToSign: Uint8Array): Promise<Uint8Array> => {\n return nacl.sign.detached(bytesToSign, keys.secretKey)\n }\n\n return generateAddressWithSigners({\n ed25519Pubkey: keys.publicKey,\n sendingAddress: getOptionalAddress(sender),\n rawEd25519Signer: rawSigner,\n })\n }\n\n /**\n * Gets an account with private key loaded from a KMD wallet of the given name, or alternatively creates one with funds in it via a KMD wallet of the given name.\n *\n * This is useful to get idempotent accounts from LocalNet without having to specify the private key (which will change when resetting the LocalNet).\n *\n * This significantly speeds up local dev time and improves experience since you can write code that *just works* first go without manual config in a fresh LocalNet.\n *\n * If this is used via `mnemonicAccountFromEnvironment`, then you can even use the same code that runs on production without changes for local development!\n *\n * @param name The name of the wallet to retrieve / create\n * @param fundWith The number of Algo to fund the account with when it gets created, if not specified then 1000 ALGO will be funded from the dispenser account\n *\n * @example\n * ```typescript\n * // Idempotently get (if exists) or create (if it doesn't exist yet) an account by name using KMD\n * // if creating it then fund it with 2 ALGO from the default dispenser account\n * const newAccount = await kmdAccountManager.getOrCreateWalletAccount('account1', (2).algo())\n * // This will return the same account as above since the name matches\n * const existingAccount = await kmdAccountManager.getOrCreateWalletAccount('account1')\n * ```\n *\n * @returns An Algorand account with private key loaded - either one that already existed in the given KMD wallet, or a new one that is funded for you\n */\n public async getOrCreateWalletAccount(name: string, fundWith?: AlgoAmount): Promise<AddressWithTransactionSigner> {\n // Get an existing account from the KMD wallet\n const existing = await this.getWalletAccount(name)\n if (existing) {\n return existing\n }\n\n const kmd = await this.kmd()\n\n // None existed: create the KMD wallet instead\n const walletId = (await kmd.createWallet({ walletName: name, walletPassword: '' })).wallet.id\n const walletHandle = (await kmd.initWalletHandle({ walletId, walletPassword: '' })).walletHandleToken\n await kmd.generateKey({ walletHandleToken: walletHandle })\n\n // Get the account from the new KMD wallet\n const account = (await this.getWalletAccount(name))!\n\n Config.logger.info(\n `LocalNet account '${name}' doesn't yet exist; created account ${account.addr} with keys stored in KMD and funding with ${\n fundWith?.algo ?? 1000\n } ALGO`,\n )\n\n // Fund the account from the dispenser\n const dispenser = await this.getLocalNetDispenserAccount()\n await new TransactionComposer({\n algod: this._clientManager.algod,\n getSigner: () => dispenser.signer,\n getSuggestedParams: () => this._clientManager.algod.suggestedParams(),\n })\n .addPayment({ amount: fundWith ?? AlgoAmount.Algo(1000), receiver: account.addr, sender: dispenser.addr })\n .send()\n\n return account\n }\n\n /**\n * Returns an Algorand account with private key loaded for the default LocalNet dispenser account (that can be used to fund other accounts).\n * @example\n * ```typescript\n * const dispenser = await kmdAccountManager.getLocalNetDispenserAccount()\n * ```\n * @returns The default LocalNet dispenser account\n */\n public async getLocalNetDispenserAccount() {\n if (!(await this._clientManager.isLocalNet())) {\n throw new Error(\"Can't get LocalNet dispenser account from non LocalNet network\")\n }\n const genesisResponse = await this._clientManager.algod.genesis()\n const dispenserAddresses = genesisResponse.alloc.filter((a) => a.comment === 'Wallet1').map((a) => a.addr)\n if (dispenserAddresses.length > 0) {\n const dispenser = await this.findWalletAccount('unencrypted-default-wallet', dispenserAddresses[0])\n if (dispenser) {\n return dispenser\n }\n }\n\n throw new Error(\"Error retrieving LocalNet dispenser account; couldn't find the default account in KMD\")\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AVMTracesEventData, TealSourcesDebugEventData } from "./debugging.js";
|
|
2
|
+
|
|
3
|
+
//#region src/lifecycle-events.d.ts
|
|
4
|
+
declare enum EventType {
|
|
5
|
+
TxnGroupSimulated = "TxnGroupSimulated",
|
|
6
|
+
AppCompiled = "AppCompiled",
|
|
7
|
+
}
|
|
8
|
+
type EventDataMap = {
|
|
9
|
+
[EventType.TxnGroupSimulated]: AVMTracesEventData;
|
|
10
|
+
[EventType.AppCompiled]: TealSourcesDebugEventData;
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { EventDataMap, EventType };
|
|
14
|
+
//# sourceMappingURL=lifecycle-events.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/lifecycle-events.ts
|
|
3
|
+
let EventType = /* @__PURE__ */ function(EventType$1) {
|
|
4
|
+
EventType$1["TxnGroupSimulated"] = "TxnGroupSimulated";
|
|
5
|
+
EventType$1["AppCompiled"] = "AppCompiled";
|
|
6
|
+
return EventType$1;
|
|
7
|
+
}({});
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
exports.EventType = EventType;
|
|
11
|
+
//# sourceMappingURL=lifecycle-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle-events.js","names":[],"sources":["../src/lifecycle-events.ts"],"sourcesContent":["import { AVMTracesEventData, TealSourcesDebugEventData } from './debugging'\n\nexport enum EventType {\n TxnGroupSimulated = 'TxnGroupSimulated',\n AppCompiled = 'AppCompiled',\n}\n\nexport type EventDataMap = {\n [EventType.TxnGroupSimulated]: AVMTracesEventData\n [EventType.AppCompiled]: TealSourcesDebugEventData\n}\n"],"mappings":";;AAEA,IAAY,kDAAL;AACL;AACA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/lifecycle-events.ts
|
|
2
|
+
let EventType = /* @__PURE__ */ function(EventType$1) {
|
|
3
|
+
EventType$1["TxnGroupSimulated"] = "TxnGroupSimulated";
|
|
4
|
+
EventType$1["AppCompiled"] = "AppCompiled";
|
|
5
|
+
return EventType$1;
|
|
6
|
+
}({});
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
export { EventType };
|
|
10
|
+
//# sourceMappingURL=lifecycle-events.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle-events.mjs","names":[],"sources":["../src/lifecycle-events.ts"],"sourcesContent":["import { AVMTracesEventData, TealSourcesDebugEventData } from './debugging'\n\nexport enum EventType {\n TxnGroupSimulated = 'TxnGroupSimulated',\n AppCompiled = 'AppCompiled',\n}\n\nexport type EventDataMap = {\n [EventType.TxnGroupSimulated]: AVMTracesEventData\n [EventType.AppCompiled]: TealSourcesDebugEventData\n}\n"],"mappings":";AAEA,IAAY,kDAAL;AACL;AACA"}
|
package/logging.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Logger } from "./packages/common/src/logger.js";
|
|
2
|
+
|
|
3
|
+
//#region src/logging.d.ts
|
|
4
|
+
/** A logger implementation that writes to console */
|
|
5
|
+
declare const consoleLogger: Logger;
|
|
6
|
+
declare const infoConsoleLogger: Logger;
|
|
7
|
+
declare const verboseConsoleLogger: Logger;
|
|
8
|
+
declare const warningConsoleLogger: Logger;
|
|
9
|
+
/** A logger implementation that does nothing */
|
|
10
|
+
declare const nullLogger: Logger;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { type Logger, consoleLogger, infoConsoleLogger, nullLogger, verboseConsoleLogger, warningConsoleLogger };
|
|
13
|
+
//# sourceMappingURL=logging.d.ts.map
|
package/logging.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/logging.ts
|
|
3
|
+
/** A logger implementation that writes to console */
|
|
4
|
+
const consoleLogger = {
|
|
5
|
+
error: console.error,
|
|
6
|
+
warn: console.warn,
|
|
7
|
+
info: console.info,
|
|
8
|
+
verbose: () => {},
|
|
9
|
+
debug: console.debug
|
|
10
|
+
};
|
|
11
|
+
const infoConsoleLogger = {
|
|
12
|
+
error: console.error,
|
|
13
|
+
warn: console.warn,
|
|
14
|
+
info: console.info,
|
|
15
|
+
verbose: () => {},
|
|
16
|
+
debug: () => {}
|
|
17
|
+
};
|
|
18
|
+
const verboseConsoleLogger = {
|
|
19
|
+
error: console.error,
|
|
20
|
+
warn: console.warn,
|
|
21
|
+
info: console.info,
|
|
22
|
+
verbose: console.trace,
|
|
23
|
+
debug: console.debug
|
|
24
|
+
};
|
|
25
|
+
const warningConsoleLogger = {
|
|
26
|
+
error: console.error,
|
|
27
|
+
warn: console.warn,
|
|
28
|
+
info: () => {},
|
|
29
|
+
verbose: () => {},
|
|
30
|
+
debug: () => {}
|
|
31
|
+
};
|
|
32
|
+
/** A logger implementation that does nothing */
|
|
33
|
+
const nullLogger = {
|
|
34
|
+
error: function(message, ...optionalParams) {},
|
|
35
|
+
warn: function(message, ...optionalParams) {},
|
|
36
|
+
info: function(message, ...optionalParams) {},
|
|
37
|
+
verbose: function(message, ...optionalParams) {},
|
|
38
|
+
debug: function(message, ...optionalParams) {}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
exports.consoleLogger = consoleLogger;
|
|
43
|
+
exports.infoConsoleLogger = infoConsoleLogger;
|
|
44
|
+
exports.nullLogger = nullLogger;
|
|
45
|
+
exports.verboseConsoleLogger = verboseConsoleLogger;
|
|
46
|
+
exports.warningConsoleLogger = warningConsoleLogger;
|
|
47
|
+
//# sourceMappingURL=logging.js.map
|
package/logging.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.js","names":["consoleLogger: Logger","infoConsoleLogger: Logger","verboseConsoleLogger: Logger","warningConsoleLogger: Logger","nullLogger: Logger"],"sources":["../src/logging.ts"],"sourcesContent":["/* eslint-disable unused-imports/no-unused-vars */\n/* eslint-disable no-console */\n\nimport type { Logger } from '@algorandfoundation/algokit-common'\nexport type { Logger } from '@algorandfoundation/algokit-common'\n\n/** A logger implementation that writes to console */\nexport const consoleLogger: Logger = {\n error: console.error,\n warn: console.warn,\n info: console.info,\n verbose: () => {},\n debug: console.debug,\n}\n\nexport const infoConsoleLogger: Logger = {\n error: console.error,\n warn: console.warn,\n info: console.info,\n verbose: () => {},\n debug: () => {},\n}\n\nexport const verboseConsoleLogger: Logger = {\n error: console.error,\n warn: console.warn,\n info: console.info,\n verbose: console.trace,\n debug: console.debug,\n}\n\nexport const warningConsoleLogger: Logger = {\n error: console.error,\n warn: console.warn,\n info: () => {},\n verbose: () => {},\n debug: () => {},\n}\n\n/** A logger implementation that does nothing */\nexport const nullLogger: Logger = {\n error: function (message: string, ...optionalParams: unknown[]): void {},\n warn: function (message: string, ...optionalParams: unknown[]): void {},\n info: function (message: string, ...optionalParams: unknown[]): void {},\n verbose: function (message: string, ...optionalParams: unknown[]): void {},\n debug: function (message: string, ...optionalParams: unknown[]): void {},\n}\n"],"mappings":";;;AAOA,MAAaA,gBAAwB;CACnC,OAAO,QAAQ;CACf,MAAM,QAAQ;CACd,MAAM,QAAQ;CACd,eAAe;CACf,OAAO,QAAQ;CAChB;AAED,MAAaC,oBAA4B;CACvC,OAAO,QAAQ;CACf,MAAM,QAAQ;CACd,MAAM,QAAQ;CACd,eAAe;CACf,aAAa;CACd;AAED,MAAaC,uBAA+B;CAC1C,OAAO,QAAQ;CACf,MAAM,QAAQ;CACd,MAAM,QAAQ;CACd,SAAS,QAAQ;CACjB,OAAO,QAAQ;CAChB;AAED,MAAaC,uBAA+B;CAC1C,OAAO,QAAQ;CACf,MAAM,QAAQ;CACd,YAAY;CACZ,eAAe;CACf,aAAa;CACd;;AAGD,MAAaC,aAAqB;CAChC,OAAO,SAAU,SAAiB,GAAG,gBAAiC;CACtE,MAAM,SAAU,SAAiB,GAAG,gBAAiC;CACrE,MAAM,SAAU,SAAiB,GAAG,gBAAiC;CACrE,SAAS,SAAU,SAAiB,GAAG,gBAAiC;CACxE,OAAO,SAAU,SAAiB,GAAG,gBAAiC;CACvE"}
|
package/logging.mjs
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/logging.ts
|
|
2
|
+
/** A logger implementation that writes to console */
|
|
3
|
+
const consoleLogger = {
|
|
4
|
+
error: console.error,
|
|
5
|
+
warn: console.warn,
|
|
6
|
+
info: console.info,
|
|
7
|
+
verbose: () => {},
|
|
8
|
+
debug: console.debug
|
|
9
|
+
};
|
|
10
|
+
const infoConsoleLogger = {
|
|
11
|
+
error: console.error,
|
|
12
|
+
warn: console.warn,
|
|
13
|
+
info: console.info,
|
|
14
|
+
verbose: () => {},
|
|
15
|
+
debug: () => {}
|
|
16
|
+
};
|
|
17
|
+
const verboseConsoleLogger = {
|
|
18
|
+
error: console.error,
|
|
19
|
+
warn: console.warn,
|
|
20
|
+
info: console.info,
|
|
21
|
+
verbose: console.trace,
|
|
22
|
+
debug: console.debug
|
|
23
|
+
};
|
|
24
|
+
const warningConsoleLogger = {
|
|
25
|
+
error: console.error,
|
|
26
|
+
warn: console.warn,
|
|
27
|
+
info: () => {},
|
|
28
|
+
verbose: () => {},
|
|
29
|
+
debug: () => {}
|
|
30
|
+
};
|
|
31
|
+
/** A logger implementation that does nothing */
|
|
32
|
+
const nullLogger = {
|
|
33
|
+
error: function(message, ...optionalParams) {},
|
|
34
|
+
warn: function(message, ...optionalParams) {},
|
|
35
|
+
info: function(message, ...optionalParams) {},
|
|
36
|
+
verbose: function(message, ...optionalParams) {},
|
|
37
|
+
debug: function(message, ...optionalParams) {}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
export { consoleLogger, infoConsoleLogger, nullLogger, verboseConsoleLogger, warningConsoleLogger };
|
|
42
|
+
//# sourceMappingURL=logging.mjs.map
|
package/logging.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.mjs","names":["consoleLogger: Logger","infoConsoleLogger: Logger","verboseConsoleLogger: Logger","warningConsoleLogger: Logger","nullLogger: Logger"],"sources":["../src/logging.ts"],"sourcesContent":["/* eslint-disable unused-imports/no-unused-vars */\n/* eslint-disable no-console */\n\nimport type { Logger } from '@algorandfoundation/algokit-common'\nexport type { Logger } from '@algorandfoundation/algokit-common'\n\n/** A logger implementation that writes to console */\nexport const consoleLogger: Logger = {\n error: console.error,\n warn: console.warn,\n info: console.info,\n verbose: () => {},\n debug: console.debug,\n}\n\nexport const infoConsoleLogger: Logger = {\n error: console.error,\n warn: console.warn,\n info: console.info,\n verbose: () => {},\n debug: () => {},\n}\n\nexport const verboseConsoleLogger: Logger = {\n error: console.error,\n warn: console.warn,\n info: console.info,\n verbose: console.trace,\n debug: console.debug,\n}\n\nexport const warningConsoleLogger: Logger = {\n error: console.error,\n warn: console.warn,\n info: () => {},\n verbose: () => {},\n debug: () => {},\n}\n\n/** A logger implementation that does nothing */\nexport const nullLogger: Logger = {\n error: function (message: string, ...optionalParams: unknown[]): void {},\n warn: function (message: string, ...optionalParams: unknown[]): void {},\n info: function (message: string, ...optionalParams: unknown[]): void {},\n verbose: function (message: string, ...optionalParams: unknown[]): void {},\n debug: function (message: string, ...optionalParams: unknown[]): void {},\n}\n"],"mappings":";;AAOA,MAAaA,gBAAwB;CACnC,OAAO,QAAQ;CACf,MAAM,QAAQ;CACd,MAAM,QAAQ;CACd,eAAe;CACf,OAAO,QAAQ;CAChB;AAED,MAAaC,oBAA4B;CACvC,OAAO,QAAQ;CACf,MAAM,QAAQ;CACd,MAAM,QAAQ;CACd,eAAe;CACf,aAAa;CACd;AAED,MAAaC,uBAA+B;CAC1C,OAAO,QAAQ;CACf,MAAM,QAAQ;CACd,MAAM,QAAQ;CACd,SAAS,QAAQ;CACjB,OAAO,QAAQ;CAChB;AAED,MAAaC,uBAA+B;CAC1C,OAAO,QAAQ;CACf,MAAM,QAAQ;CACd,YAAY;CACZ,eAAe;CACf,aAAa;CACd;;AAGD,MAAaC,aAAqB;CAChC,OAAO,SAAU,SAAiB,GAAG,gBAAiC;CACtE,MAAM,SAAU,SAAiB,GAAG,gBAAiC;CACrE,MAAM,SAAU,SAAiB,GAAG,gBAAiC;CACrE,SAAS,SAAU,SAAiB,GAAG,gBAAiC;CACxE,OAAO,SAAU,SAAiB,GAAG,gBAAiC;CACvE"}
|
package/logic-error.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/logic-error.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Details about a smart contract logic error
|
|
4
|
+
*/
|
|
5
|
+
interface LogicErrorDetails {
|
|
6
|
+
/** The ID of the transaction with the logic error */
|
|
7
|
+
txId: string;
|
|
8
|
+
/** The program counter where the error was */
|
|
9
|
+
pc: number;
|
|
10
|
+
/** The error message */
|
|
11
|
+
msg: string;
|
|
12
|
+
/** The full error description */
|
|
13
|
+
desc: string;
|
|
14
|
+
/** Any trace information included in the error */
|
|
15
|
+
traces: Record<string, unknown>[];
|
|
16
|
+
}
|
|
17
|
+
/** Wraps key functionality around processing logic errors */
|
|
18
|
+
declare class LogicError extends Error {
|
|
19
|
+
/** Takes an error message and parses out the details of any logic errors in there.
|
|
20
|
+
* @param error The error message to parse
|
|
21
|
+
* @returns The logic error details if any, or undefined
|
|
22
|
+
*/
|
|
23
|
+
static parseLogicError(error: any): LogicErrorDetails | undefined;
|
|
24
|
+
led: LogicErrorDetails;
|
|
25
|
+
program: string[];
|
|
26
|
+
lines: number;
|
|
27
|
+
teal_line: number;
|
|
28
|
+
stack?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Create a new logic error object.
|
|
31
|
+
* @param errorDetails The details of the logic error
|
|
32
|
+
* @param program The TEAL source code, split by line
|
|
33
|
+
* @param getLineForPc The source map of the TEAL source code
|
|
34
|
+
*/
|
|
35
|
+
constructor(errorDetails: LogicErrorDetails, program: string[], getLineForPc: (pc: number) => number | undefined);
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { LogicError, LogicErrorDetails };
|
|
39
|
+
//# sourceMappingURL=logic-error.d.ts.map
|
package/logic-error.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/logic-error.ts
|
|
3
|
+
const LOGIC_ERROR = /transaction ([A-Z0-9]+): logic eval error: (.*). Details: .*pc=([0-9]+).*/;
|
|
4
|
+
const INNER_LOGIC_ERROR = /inner tx (\d+) failed:.*?pc=([0-9]+)/;
|
|
5
|
+
/** Wraps key functionality around processing logic errors */
|
|
6
|
+
var LogicError = class extends Error {
|
|
7
|
+
/** Takes an error message and parses out the details of any logic errors in there.
|
|
8
|
+
* @param error The error message to parse
|
|
9
|
+
* @returns The logic error details if any, or undefined
|
|
10
|
+
*/
|
|
11
|
+
static parseLogicError(error) {
|
|
12
|
+
const errorMessage = error.message;
|
|
13
|
+
const res = LOGIC_ERROR.exec(errorMessage);
|
|
14
|
+
const innerRes = INNER_LOGIC_ERROR.exec(errorMessage);
|
|
15
|
+
if (res === null || res.length <= 3) return void 0;
|
|
16
|
+
return {
|
|
17
|
+
txId: res[1],
|
|
18
|
+
msg: res[2],
|
|
19
|
+
desc: errorMessage,
|
|
20
|
+
pc: parseInt(innerRes?.[2] ?? res[3] ?? "0"),
|
|
21
|
+
traces: error.traces
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
led;
|
|
25
|
+
program;
|
|
26
|
+
lines = 5;
|
|
27
|
+
teal_line = 0;
|
|
28
|
+
stack;
|
|
29
|
+
/**
|
|
30
|
+
* Create a new logic error object.
|
|
31
|
+
* @param errorDetails The details of the logic error
|
|
32
|
+
* @param program The TEAL source code, split by line
|
|
33
|
+
* @param getLineForPc The source map of the TEAL source code
|
|
34
|
+
*/
|
|
35
|
+
constructor(errorDetails, program, getLineForPc) {
|
|
36
|
+
super();
|
|
37
|
+
this.led = errorDetails;
|
|
38
|
+
this.program = program;
|
|
39
|
+
const line = getLineForPc(errorDetails.pc);
|
|
40
|
+
this.teal_line = line === void 0 ? 0 : line;
|
|
41
|
+
this.message = `${this.led.msg}. at:${line}. ${this.led.desc}`;
|
|
42
|
+
if (this.teal_line > 0) {
|
|
43
|
+
const start = this.teal_line > this.lines ? this.teal_line - this.lines : 0;
|
|
44
|
+
const stop = program.length > this.teal_line + this.lines ? this.teal_line + this.lines : program.length;
|
|
45
|
+
const stack_lines = program.slice(start, stop);
|
|
46
|
+
stack_lines[stack_lines.length / 2] += " <--- Error";
|
|
47
|
+
this.stack = stack_lines.join("\n");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
exports.LogicError = LogicError;
|
|
54
|
+
//# sourceMappingURL=logic-error.js.map
|