@leather.io/stacks 1.19.3 → 1.19.4
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/dist/index.d.ts +246 -169
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +434 -690
- package/dist/index.js.map +1 -1
- package/package.json +15 -9
package/dist/index.js
CHANGED
|
@@ -1,826 +1,570 @@
|
|
|
1
|
-
|
|
2
|
-
import { bytesToHex } from "@noble/hashes/utils";
|
|
1
|
+
import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
|
|
3
2
|
import { hashMessage } from "@stacks/encryption";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "@stacks/
|
|
3
|
+
import { BytesReader, ClarityType, MEMO_MAX_LENGTH_BYTES, Pc, TransactionSigner, bufferCVFromString, codeBodyString, compressPrivateKey, createAddress, createMemoString, createStacksPublicKey, deserializeCV, deserializePostConditionWire, getAddressFromPrivateKey, makeRandomPrivKey, makeUnsignedContractCall, makeUnsignedContractDeploy, makeUnsignedSTXTokenTransfer, noneCV, postConditionToWire, privateKeyToPublic, publicKeyToAddressSingleSig, serializeCV, serializePayload, signMessageHashRsv, signStructuredData, someCV, standardPrincipalCVFromAddress, uintCV } from "@stacks/transactions";
|
|
4
|
+
import { DerivationPathDepth, createDescriptor, createKeyOriginPath, decomposeDescriptor, deriveRootKeychainFromMnemonic, extractAddressIndexFromPath, extractKeyFromDescriptor } from "@leather.io/crypto";
|
|
5
|
+
import { ChainId } from "@stacks/network";
|
|
6
|
+
import { assertIsTruthy, assertUnreachable, isDefined, isEmptyString, isString, isUndefined, stxToMicroStx, toHexString } from "@leather.io/utils";
|
|
7
|
+
import { bytesToHex as bytesToHex$1 } from "@stacks/common";
|
|
8
|
+
import BigNumber from "bignumber.js";
|
|
9
|
+
import { c32addressDecode } from "c32check";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { ChainId as ChainId$1 } from "@leather.io/models";
|
|
12
|
+
|
|
13
|
+
//#region src/message-signing.ts
|
|
9
14
|
function signMessage(message, privateKey) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
return {
|
|
16
|
+
signature: signMessageHashRsv({
|
|
17
|
+
privateKey,
|
|
18
|
+
messageHash: bytesToHex(hashMessage(message))
|
|
19
|
+
}),
|
|
20
|
+
publicKey: privateKeyToPublic(privateKey)
|
|
21
|
+
};
|
|
15
22
|
}
|
|
16
23
|
function signStructuredDataMessage(message, domain, privateKey) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
24
|
+
return {
|
|
25
|
+
signature: signStructuredData({
|
|
26
|
+
message,
|
|
27
|
+
domain,
|
|
28
|
+
privateKey
|
|
29
|
+
}),
|
|
30
|
+
publicKey: privateKeyToPublic(privateKey)
|
|
31
|
+
};
|
|
26
32
|
}
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/mocks/mocks.ts
|
|
36
|
+
const TEST_ACCOUNT_1_STX_ADDRESS = "SPS8CKF63P16J28AYF7PXW9E5AACH0NZNTEFWSFE";
|
|
37
|
+
const TEST_ACCOUNT_2_STX_ADDRESS = "SPXH3HNBPM5YP15VH16ZXZ9AX6CK289K3MCXRKCB";
|
|
38
|
+
const TEST_TESTNET_ACCOUNT_2_STX_ADDRESS = "STXH3HNBPM5YP15VH16ZXZ9AX6CK289K3NVR9T1P";
|
|
39
|
+
const TEST_ACCOUNT_1_STX_ADDRESS_SM = "SM3FBR6RDNZYC5K4TZWV9VZJ6NGA4VX3YBQ8X2PQ";
|
|
40
|
+
const TEST_TESTNET_ACCOUNT_2_STX_ADDRESS_SN = "SNXH3HNBPM5YP15VH16ZXZ9AX6CK289K3NVR9T1P";
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
createStacksPublicKey,
|
|
39
|
-
publicKeyToAddressSingleSig
|
|
40
|
-
} from "@stacks/transactions";
|
|
41
|
-
import {
|
|
42
|
-
decomposeDescriptor,
|
|
43
|
-
deriveRootKeychainFromMnemonic,
|
|
44
|
-
extractKeyFromDescriptor
|
|
45
|
-
} from "@leather.io/crypto";
|
|
46
|
-
|
|
47
|
-
// src/stacks.utils.ts
|
|
48
|
-
import { ChainId } from "@stacks/network";
|
|
49
|
-
import {
|
|
50
|
-
compressPrivateKey,
|
|
51
|
-
privateKeyToPublic as privateKeyToPublic2
|
|
52
|
-
} from "@stacks/transactions";
|
|
53
|
-
import {
|
|
54
|
-
DerivationPathDepth,
|
|
55
|
-
createDescriptor,
|
|
56
|
-
createKeyOriginPath,
|
|
57
|
-
extractAddressIndexFromPath
|
|
58
|
-
} from "@leather.io/crypto";
|
|
59
|
-
import { assertIsTruthy, isString, toHexString } from "@leather.io/utils";
|
|
60
|
-
var stxDerivationWithAccount = `m/44'/5757'/0'/0/{account}`;
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/stacks.utils.ts
|
|
44
|
+
const stxDerivationWithAccount = `m/44'/5757'/0'/0/{account}`;
|
|
61
45
|
function makeAccountIndexDerivationPathFactory(derivationPath) {
|
|
62
|
-
|
|
46
|
+
return (account) => derivationPath.replace("{account}", account.toString());
|
|
63
47
|
}
|
|
64
48
|
function extractStacksDerivationPathAccountIndex(path) {
|
|
65
|
-
|
|
66
|
-
|
|
49
|
+
if (!path.includes("5757")) throw new Error("Not a valid Stacks derivation path: " + path);
|
|
50
|
+
return extractAddressIndexFromPath(path);
|
|
67
51
|
}
|
|
68
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Stacks accounts always use the same derivation path, regardless of network
|
|
54
|
+
*/
|
|
55
|
+
const makeStxDerivationPath = makeAccountIndexDerivationPathFactory(stxDerivationWithAccount);
|
|
69
56
|
function stacksChainIdToCoreNetworkMode(chainId) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
57
|
+
return whenStacksChainId(chainId)({
|
|
58
|
+
[ChainId.Mainnet]: "mainnet",
|
|
59
|
+
[ChainId.Testnet]: "testnet"
|
|
60
|
+
});
|
|
74
61
|
}
|
|
75
62
|
function whenStacksChainId(chainId) {
|
|
76
|
-
|
|
63
|
+
return (chainIdMap) => chainIdMap[chainId];
|
|
77
64
|
}
|
|
78
65
|
function deriveStxPrivateKey({ keychain, index }) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
66
|
+
if (keychain.depth !== DerivationPathDepth.Root) throw new Error("Root keychain must be depth 0");
|
|
67
|
+
const accountKeychain = keychain.derive(makeStxDerivationPath(index));
|
|
68
|
+
assertIsTruthy(accountKeychain.privateKey);
|
|
69
|
+
return compressPrivateKey(accountKeychain.privateKey);
|
|
83
70
|
}
|
|
84
|
-
function deriveStxPublicKey({
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
71
|
+
function deriveStxPublicKey({ keychain, index }) {
|
|
72
|
+
return privateKeyToPublic(deriveStxPrivateKey({
|
|
73
|
+
keychain,
|
|
74
|
+
index
|
|
75
|
+
}));
|
|
89
76
|
}
|
|
90
77
|
function stacksRootKeychainToAccountDescriptor(keychain, accountIndex) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
78
|
+
const fingerprint = toHexString(keychain.fingerprint);
|
|
79
|
+
const publicKey = deriveStxPublicKey({
|
|
80
|
+
keychain,
|
|
81
|
+
index: accountIndex
|
|
82
|
+
});
|
|
83
|
+
return createDescriptor(createKeyOriginPath(fingerprint, makeStxDerivationPath(accountIndex)), publicKey);
|
|
97
84
|
}
|
|
98
85
|
function getStacksBurnAddress(chainIdChainId) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return "ST000000000000000000002AMW42H";
|
|
105
|
-
}
|
|
86
|
+
switch (chainIdChainId) {
|
|
87
|
+
case ChainId.Mainnet: return "SP00000000000003SCNSJTCSE62ZF4MSE";
|
|
88
|
+
case ChainId.Testnet:
|
|
89
|
+
default: return "ST000000000000000000002AMW42H";
|
|
90
|
+
}
|
|
106
91
|
}
|
|
107
92
|
function cleanHex(hexWithMaybePrefix) {
|
|
108
|
-
|
|
109
|
-
|
|
93
|
+
if (!isString(hexWithMaybePrefix)) return hexWithMaybePrefix;
|
|
94
|
+
return hexWithMaybePrefix.startsWith("0x") ? hexWithMaybePrefix.replace("0x", "") : hexWithMaybePrefix;
|
|
110
95
|
}
|
|
111
96
|
function getPrincipalFromAssetString(assetString) {
|
|
112
|
-
|
|
97
|
+
return assetString.split("::")[0];
|
|
113
98
|
}
|
|
114
99
|
function formatContractId(address, name) {
|
|
115
|
-
|
|
100
|
+
return `${address}.${name}`;
|
|
116
101
|
}
|
|
117
|
-
function formatAssetString({
|
|
118
|
-
|
|
119
|
-
contractName,
|
|
120
|
-
assetName
|
|
121
|
-
}) {
|
|
122
|
-
return `${contractAddress}.${contractName}::${assetName}`;
|
|
102
|
+
function formatAssetString({ contractAddress, contractName, assetName }) {
|
|
103
|
+
return `${contractAddress}.${contractName}::${assetName}`;
|
|
123
104
|
}
|
|
124
|
-
function formatContractIdString({
|
|
125
|
-
|
|
126
|
-
contractName
|
|
127
|
-
}) {
|
|
128
|
-
return `${contractAddress}.${contractName}`;
|
|
105
|
+
function formatContractIdString({ contractAddress, contractName }) {
|
|
106
|
+
return `${contractAddress}.${contractName}`;
|
|
129
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Gets the contract name.
|
|
110
|
+
*
|
|
111
|
+
* @param identifier - [principal].[contract-name] or [principal].[contract-name]::[asset-name]
|
|
112
|
+
*/
|
|
130
113
|
function getStacksContractName(identifier) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
114
|
+
if (identifier.includes(".")) {
|
|
115
|
+
const parts = identifier?.split(".");
|
|
116
|
+
if (identifier.includes("::")) return parts[1].split("::")[0];
|
|
117
|
+
return parts[1];
|
|
118
|
+
}
|
|
119
|
+
return identifier;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Gets the asset name.
|
|
123
|
+
*
|
|
124
|
+
* @param identifier - [principal].[contract-name]::[asset-name]
|
|
125
|
+
*/
|
|
140
126
|
function getStacksContractAssetName(identifier) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
127
|
+
if (!identifier.includes("::")) return identifier;
|
|
128
|
+
return identifier.split("::")[1];
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Gets the parts that make up a fully qualified name of an asset.
|
|
132
|
+
*
|
|
133
|
+
* @param identifier - [principal].[contract-name]::[asset-name]
|
|
134
|
+
*/
|
|
144
135
|
function getStacksAssetStringParts(identifier) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return {
|
|
156
|
-
contractAddress,
|
|
157
|
-
contractAssetName,
|
|
158
|
-
contractName
|
|
159
|
-
};
|
|
136
|
+
if (!identifier.includes(".") && !identifier.includes("::")) return {
|
|
137
|
+
contractAddress: identifier,
|
|
138
|
+
contractAssetName: identifier,
|
|
139
|
+
contractName: identifier
|
|
140
|
+
};
|
|
141
|
+
return {
|
|
142
|
+
contractAddress: identifier.split(".")[0],
|
|
143
|
+
contractAssetName: getStacksContractAssetName(identifier),
|
|
144
|
+
contractName: getStacksContractName(identifier)
|
|
145
|
+
};
|
|
160
146
|
}
|
|
161
147
|
|
|
162
|
-
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region src/signer/signer.ts
|
|
163
150
|
function signStacksTransaction(tx, privateKey) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
return tx;
|
|
151
|
+
new TransactionSigner(tx).signOrigin(privateKey);
|
|
152
|
+
return tx;
|
|
167
153
|
}
|
|
168
154
|
async function getPrivateKey(keyOrigin, getMnemonicFn) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
});
|
|
155
|
+
const { mnemonic, passphrase } = await getMnemonicFn();
|
|
156
|
+
return deriveStxPrivateKey({
|
|
157
|
+
keychain: await deriveRootKeychainFromMnemonic(mnemonic, passphrase),
|
|
158
|
+
index: extractStacksDerivationPathAccountIndex(keyOrigin)
|
|
159
|
+
});
|
|
175
160
|
}
|
|
176
161
|
function createSignFnFromMnemonic(keyOrigin, getMnemonicFn) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
};
|
|
162
|
+
return async (tx) => {
|
|
163
|
+
return signStacksTransaction(tx, await getPrivateKey(keyOrigin, getMnemonicFn));
|
|
164
|
+
};
|
|
181
165
|
}
|
|
182
166
|
function createSignMessageFnFromMnemonic(keyOrigin, getMnemonicFn) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
};
|
|
167
|
+
return async (message) => {
|
|
168
|
+
return signMessage(message, await getPrivateKey(keyOrigin, getMnemonicFn));
|
|
169
|
+
};
|
|
187
170
|
}
|
|
188
171
|
function createSignStructuredDataMessageFnFromMnemonic(keyOrigin, getMnemonicFn) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
};
|
|
172
|
+
return async (message, domain) => {
|
|
173
|
+
return signStructuredDataMessage(message, domain, await getPrivateKey(keyOrigin, getMnemonicFn));
|
|
174
|
+
};
|
|
193
175
|
}
|
|
194
176
|
function initalizeStacksSigner(args) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
};
|
|
177
|
+
const { descriptor, network, signFn, signMessageFn, signStructuredMessageFn } = args;
|
|
178
|
+
const publicKey = createStacksPublicKey(extractKeyFromDescriptor(descriptor)).data;
|
|
179
|
+
return {
|
|
180
|
+
...decomposeDescriptor(descriptor),
|
|
181
|
+
accountIndex: extractStacksDerivationPathAccountIndex(descriptor),
|
|
182
|
+
publicKey,
|
|
183
|
+
network,
|
|
184
|
+
address: publicKeyToAddressSingleSig(publicKey, network),
|
|
185
|
+
sign: signFn,
|
|
186
|
+
signMessage: signMessageFn,
|
|
187
|
+
signStructuredMessage: signStructuredMessageFn
|
|
188
|
+
};
|
|
208
189
|
}
|
|
209
190
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
import { Pc, serializeCV } from "@stacks/transactions";
|
|
213
|
-
|
|
214
|
-
// src/transactions/generate-unsigned-transaction.ts
|
|
215
|
-
import { hexToBytes as hexToBytes2 } from "@noble/hashes/utils";
|
|
216
|
-
import {
|
|
217
|
-
deserializeCV,
|
|
218
|
-
makeUnsignedContractCall,
|
|
219
|
-
makeUnsignedContractDeploy,
|
|
220
|
-
makeUnsignedSTXTokenTransfer
|
|
221
|
-
} from "@stacks/transactions";
|
|
222
|
-
import BigNumber from "bignumber.js";
|
|
223
|
-
import { assertUnreachable } from "@leather.io/utils";
|
|
224
|
-
|
|
225
|
-
// src/transactions/post-condition.utils.ts
|
|
226
|
-
import { hexToBytes } from "@noble/hashes/utils";
|
|
227
|
-
import {
|
|
228
|
-
BytesReader,
|
|
229
|
-
deserializePostConditionWire,
|
|
230
|
-
postConditionToWire
|
|
231
|
-
} from "@stacks/transactions";
|
|
232
|
-
import { isString as isString2 } from "@leather.io/utils";
|
|
191
|
+
//#endregion
|
|
192
|
+
//#region src/transactions/post-condition.utils.ts
|
|
233
193
|
function getPostConditionFromString(postCondition) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
194
|
+
try {
|
|
195
|
+
return deserializePostConditionWire(new BytesReader(hexToBytes(postCondition)));
|
|
196
|
+
} catch {
|
|
197
|
+
throw new Error("Not a serialized post condition");
|
|
198
|
+
}
|
|
240
199
|
}
|
|
241
200
|
function ensurePostConditionWireFormat(postCondition) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
201
|
+
if (isString(postCondition)) return getPostConditionFromString(postCondition);
|
|
202
|
+
if ("conditionType" in postCondition) return postCondition;
|
|
203
|
+
return postConditionToWire(postCondition);
|
|
245
204
|
}
|
|
246
205
|
function getPostCondition(postCondition) {
|
|
247
|
-
|
|
206
|
+
return isString(postCondition) ? getPostConditionFromString(postCondition) : ensurePostConditionWireFormat(postCondition);
|
|
248
207
|
}
|
|
249
208
|
function getPostConditions(postConditions) {
|
|
250
|
-
|
|
209
|
+
return postConditions?.map(getPostCondition);
|
|
251
210
|
}
|
|
252
211
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
212
|
+
//#endregion
|
|
213
|
+
//#region src/transactions/transaction.types.ts
|
|
214
|
+
let TransactionTypes = /* @__PURE__ */ function(TransactionTypes$1) {
|
|
215
|
+
TransactionTypes$1["ContractCall"] = "contract_call";
|
|
216
|
+
TransactionTypes$1["ContractDeploy"] = "smart_contract";
|
|
217
|
+
TransactionTypes$1["StxTokenTransfer"] = "token_transfer";
|
|
218
|
+
return TransactionTypes$1;
|
|
219
|
+
}({});
|
|
260
220
|
function isTransactionTypeSupported(txType) {
|
|
261
|
-
|
|
221
|
+
return txType === TransactionTypes.ContractCall || txType === TransactionTypes.ContractDeploy || txType === TransactionTypes.StxTokenTransfer;
|
|
262
222
|
}
|
|
263
223
|
|
|
264
|
-
|
|
224
|
+
//#endregion
|
|
225
|
+
//#region src/transactions/generate-unsigned-transaction.ts
|
|
265
226
|
function initNonce(nonce) {
|
|
266
|
-
|
|
227
|
+
return new BigNumber(nonce, 10);
|
|
267
228
|
}
|
|
268
229
|
function getUnsignedContractCallParsedOptions(options) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
230
|
+
return {
|
|
231
|
+
...options,
|
|
232
|
+
fee: options.fee.amount.toString(),
|
|
233
|
+
functionArgs: options.functionArgs.map((arg) => deserializeCV(hexToBytes(cleanHex(arg)))),
|
|
234
|
+
nonce: initNonce(options.nonce).toString(),
|
|
235
|
+
postConditions: options.postConditions
|
|
236
|
+
};
|
|
276
237
|
}
|
|
277
238
|
function getUnsignedContractDeployParsedOptions(options) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
)
|
|
285
|
-
};
|
|
239
|
+
return {
|
|
240
|
+
...options,
|
|
241
|
+
fee: options.fee.amount.toString(),
|
|
242
|
+
nonce: initNonce(options.nonce).toString(),
|
|
243
|
+
postConditions: getPostConditions(options.postConditions?.map((pc) => ensurePostConditionWireFormat(pc)))
|
|
244
|
+
};
|
|
286
245
|
}
|
|
287
246
|
function getUnsignedStxTokenTransferParsedOptions(options) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
247
|
+
return {
|
|
248
|
+
...options,
|
|
249
|
+
amount: options.amount.amount.toString(),
|
|
250
|
+
fee: options.fee.amount.toString(),
|
|
251
|
+
nonce: initNonce(options.nonce).toString()
|
|
252
|
+
};
|
|
294
253
|
}
|
|
295
254
|
function generateStacksUnsignedTransaction(options) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
case "smart_contract" /* ContractDeploy */:
|
|
305
|
-
return makeUnsignedContractDeploy(getUnsignedContractDeployParsedOptions(options));
|
|
306
|
-
default:
|
|
307
|
-
assertUnreachable(txType);
|
|
308
|
-
}
|
|
255
|
+
const { txType } = options;
|
|
256
|
+
if (!isTransactionTypeSupported(txType)) throw new Error(`Invalid Transaction Type: ${txType}`);
|
|
257
|
+
switch (txType) {
|
|
258
|
+
case TransactionTypes.StxTokenTransfer: return makeUnsignedSTXTokenTransfer(getUnsignedStxTokenTransferParsedOptions(options));
|
|
259
|
+
case TransactionTypes.ContractCall: return makeUnsignedContractCall(getUnsignedContractCallParsedOptions(options));
|
|
260
|
+
case TransactionTypes.ContractDeploy: return makeUnsignedContractDeploy(getUnsignedContractDeployParsedOptions(options));
|
|
261
|
+
default: assertUnreachable(txType);
|
|
262
|
+
}
|
|
309
263
|
}
|
|
310
264
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
function
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
const fnArgs = [
|
|
328
|
-
uintCV(amount),
|
|
329
|
-
standardPrincipalCVFromAddress(createAddress(senderStacksAddress)),
|
|
330
|
-
standardPrincipalCVFromAddress(createAddress(recipientStacksAddress)),
|
|
331
|
-
memo && memo !== "" ? someCV(bufferCVFromString(memo)) : noneCV()
|
|
332
|
-
];
|
|
333
|
-
return fnArgs;
|
|
334
|
-
}
|
|
335
|
-
function createSip9FnArgs({
|
|
336
|
-
assetId,
|
|
337
|
-
senderStacksAddress,
|
|
338
|
-
recipientStacksAddress
|
|
339
|
-
}) {
|
|
340
|
-
const fnArgs = [
|
|
341
|
-
deserializeCV2(assetId),
|
|
342
|
-
standardPrincipalCVFromAddress(createAddress(senderStacksAddress)),
|
|
343
|
-
standardPrincipalCVFromAddress(createAddress(recipientStacksAddress))
|
|
344
|
-
];
|
|
345
|
-
return fnArgs;
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/transactions/get-contract-fn-args.ts
|
|
267
|
+
function createSip10FnArgs({ amount, senderStacksAddress, recipientStacksAddress, memo }) {
|
|
268
|
+
return [
|
|
269
|
+
uintCV(amount),
|
|
270
|
+
standardPrincipalCVFromAddress(createAddress(senderStacksAddress)),
|
|
271
|
+
standardPrincipalCVFromAddress(createAddress(recipientStacksAddress)),
|
|
272
|
+
memo && memo !== "" ? someCV(bufferCVFromString(memo)) : noneCV()
|
|
273
|
+
];
|
|
274
|
+
}
|
|
275
|
+
function createSip9FnArgs({ assetId, senderStacksAddress, recipientStacksAddress }) {
|
|
276
|
+
return [
|
|
277
|
+
deserializeCV(assetId),
|
|
278
|
+
standardPrincipalCVFromAddress(createAddress(senderStacksAddress)),
|
|
279
|
+
standardPrincipalCVFromAddress(createAddress(recipientStacksAddress))
|
|
280
|
+
];
|
|
346
281
|
}
|
|
347
282
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
nonce,
|
|
374
|
-
fee,
|
|
375
|
-
postConditions: [
|
|
376
|
-
Pc.principal(currentStacksAddress).willSendEq(amount).ft(formatContractIdString({ contractAddress, contractName }), contractAssetName)
|
|
377
|
-
]
|
|
378
|
-
});
|
|
379
|
-
const txHex = tx.serialize();
|
|
380
|
-
return txHex;
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/transactions/create-tx-hex.ts
|
|
285
|
+
async function createTransferSip10TxHex({ signer, assetId, recipient, amount, nonce, fee, memo }) {
|
|
286
|
+
const { contractAddress, contractAssetName, contractName } = getStacksAssetStringParts(assetId);
|
|
287
|
+
const currentStacksAddress = signer.address;
|
|
288
|
+
const fnArgs = createSip10FnArgs({
|
|
289
|
+
amount,
|
|
290
|
+
senderStacksAddress: currentStacksAddress,
|
|
291
|
+
recipientStacksAddress: recipient,
|
|
292
|
+
memo
|
|
293
|
+
});
|
|
294
|
+
return (await generateStacksUnsignedTransaction({
|
|
295
|
+
txType: TransactionTypes.ContractCall,
|
|
296
|
+
publicKey: bytesToHex$1(signer.publicKey),
|
|
297
|
+
contractAddress,
|
|
298
|
+
contractName,
|
|
299
|
+
functionArgs: fnArgs.map((arg) => serializeCV(arg)),
|
|
300
|
+
functionName: "transfer",
|
|
301
|
+
nonce,
|
|
302
|
+
fee,
|
|
303
|
+
postConditions: [Pc.principal(currentStacksAddress).willSendEq(amount).ft(formatContractIdString({
|
|
304
|
+
contractAddress,
|
|
305
|
+
contractName
|
|
306
|
+
}), contractAssetName)]
|
|
307
|
+
})).serialize();
|
|
381
308
|
}
|
|
382
309
|
|
|
383
|
-
|
|
310
|
+
//#endregion
|
|
311
|
+
//#region src/transactions/get-error-message.ts
|
|
384
312
|
function getErrorMessage(reason) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
return "Not enough funds";
|
|
412
|
-
case "PoisonMicroblocksDoNotConflict":
|
|
413
|
-
return "Microblock conflict";
|
|
414
|
-
case "PoisonMicroblockHasUnknownPubKeyHash":
|
|
415
|
-
return "No anchor block with public key hash";
|
|
416
|
-
case "PoisonMicroblockIsInvalid":
|
|
417
|
-
return "Invalid microblock";
|
|
418
|
-
case "Serialization":
|
|
419
|
-
return "Serialization failure";
|
|
420
|
-
case "ServerFailureDatabase":
|
|
421
|
-
return "Database error";
|
|
422
|
-
case "ServerFailureNoSuchChainTip":
|
|
423
|
-
return "No such chain tip";
|
|
424
|
-
case "ServerFailureOther":
|
|
425
|
-
return "Server failure";
|
|
426
|
-
case "SignatureValidation":
|
|
427
|
-
return "Failed to validate signature";
|
|
428
|
-
case "TransferAmountMustBePositive":
|
|
429
|
-
return "Transfer amount must be positive";
|
|
430
|
-
case "TransferRecipientCannotEqualSender":
|
|
431
|
-
return "Cannot transfer STX to yourself";
|
|
432
|
-
default:
|
|
433
|
-
return "Something went wrong";
|
|
434
|
-
}
|
|
313
|
+
switch (reason) {
|
|
314
|
+
case "BadAddressVersionByte": return "Incorrect address";
|
|
315
|
+
case "BadFunctionArgument": return "Incorrect function argument";
|
|
316
|
+
case "BadNonce": return "Incorrect nonce";
|
|
317
|
+
case "BadTransactionVersion": return "Incorrect transaction";
|
|
318
|
+
case "ConflictingNonceInMempool": return "Nonce conflict";
|
|
319
|
+
case "ContractAlreadyExists": return "Contract already exists";
|
|
320
|
+
case "Deserialization": return "Deserialization failure";
|
|
321
|
+
case "EstimatorError": return "Estimator error";
|
|
322
|
+
case "FeeTooLow": return "Fee too low";
|
|
323
|
+
case "NoCoinbaseViaMempool": return "No coinbase via mempool";
|
|
324
|
+
case "NoSuchContract": return "Contract does not exist";
|
|
325
|
+
case "NoSuchPublicFunction": return "Function does not exist";
|
|
326
|
+
case "NotEnoughFunds": return "Not enough funds";
|
|
327
|
+
case "PoisonMicroblocksDoNotConflict": return "Microblock conflict";
|
|
328
|
+
case "PoisonMicroblockHasUnknownPubKeyHash": return "No anchor block with public key hash";
|
|
329
|
+
case "PoisonMicroblockIsInvalid": return "Invalid microblock";
|
|
330
|
+
case "Serialization": return "Serialization failure";
|
|
331
|
+
case "ServerFailureDatabase": return "Database error";
|
|
332
|
+
case "ServerFailureNoSuchChainTip": return "No such chain tip";
|
|
333
|
+
case "ServerFailureOther": return "Server failure";
|
|
334
|
+
case "SignatureValidation": return "Failed to validate signature";
|
|
335
|
+
case "TransferAmountMustBePositive": return "Transfer amount must be positive";
|
|
336
|
+
case "TransferRecipientCannotEqualSender": return "Cannot transfer STX to yourself";
|
|
337
|
+
default: return "Something went wrong";
|
|
338
|
+
}
|
|
435
339
|
}
|
|
436
340
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
ClarityType
|
|
440
|
-
} from "@stacks/transactions";
|
|
341
|
+
//#endregion
|
|
342
|
+
//#region src/transactions/sip-10-contract-call.utils.ts
|
|
441
343
|
function isSip10TransferContactCall(tx) {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
}
|
|
462
|
-
function
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
})
|
|
467
|
-
|
|
468
|
-
return Number(functionArgs[0].value);
|
|
469
|
-
}
|
|
470
|
-
return null;
|
|
471
|
-
}
|
|
472
|
-
function getSip10TransferRecipient({
|
|
473
|
-
functionName,
|
|
474
|
-
functionArgs,
|
|
475
|
-
contractInterfaceData
|
|
476
|
-
}) {
|
|
477
|
-
if (isSip10Transfer({ functionName, contractInterfaceData }) && functionArgs[2]?.type === ClarityType.PrincipalStandard) {
|
|
478
|
-
return functionArgs[2].value;
|
|
479
|
-
}
|
|
480
|
-
return null;
|
|
344
|
+
if (tx.payload && "functionName" in tx.payload) {
|
|
345
|
+
if (tx.payload.functionName.content === "transfer" && (tx.payload.functionArgs.length === 3 || tx.payload.functionArgs.length === 4)) {
|
|
346
|
+
if (tx.payload.functionArgs[0].type === ClarityType.UInt && tx.payload.functionArgs[1].type === ClarityType.PrincipalStandard && tx.payload.functionArgs[2].type === ClarityType.PrincipalStandard) return true;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
function isSip10Transfer({ functionName, contractInterfaceData }) {
|
|
352
|
+
if (functionName !== "transfer") return false;
|
|
353
|
+
const functionInterface = contractInterfaceData?.functions.find((f) => f.name === functionName);
|
|
354
|
+
if (functionInterface?.args[0]?.name === "amount" && functionInterface?.args[1]?.name === "sender" && functionInterface?.args[2]?.name === "recipient" && functionInterface?.args[3]?.name === "memo") return true;
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
function getSip10TransferAmount({ functionName, functionArgs, contractInterfaceData }) {
|
|
358
|
+
if (isSip10Transfer({
|
|
359
|
+
functionName,
|
|
360
|
+
contractInterfaceData
|
|
361
|
+
}) && functionArgs[0]?.type === ClarityType.UInt) return Number(functionArgs[0].value);
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
function getSip10TransferRecipient({ functionName, functionArgs, contractInterfaceData }) {
|
|
365
|
+
if (isSip10Transfer({
|
|
366
|
+
functionName,
|
|
367
|
+
contractInterfaceData
|
|
368
|
+
}) && functionArgs[2]?.type === ClarityType.PrincipalStandard) return functionArgs[2].value;
|
|
369
|
+
return null;
|
|
481
370
|
}
|
|
482
371
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
ClarityType as ClarityType2
|
|
486
|
-
} from "@stacks/transactions";
|
|
372
|
+
//#endregion
|
|
373
|
+
//#region src/transactions/sip-9-contract-call.utils.ts
|
|
487
374
|
function isSip9TransferContactCall(tx) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
}
|
|
508
|
-
function getSip9TransferRecipient({
|
|
509
|
-
functionName,
|
|
510
|
-
functionArgs,
|
|
511
|
-
contractInterfaceData
|
|
512
|
-
}) {
|
|
513
|
-
if (isSip9Transfer({ functionName, contractInterfaceData }) && functionArgs[2]?.type === ClarityType2.PrincipalStandard) {
|
|
514
|
-
return functionArgs[2].value;
|
|
515
|
-
}
|
|
516
|
-
return null;
|
|
375
|
+
if (tx.payload && "functionName" in tx.payload) {
|
|
376
|
+
if (tx.payload.functionName.content === "transfer" && tx.payload.functionArgs.length === 3) {
|
|
377
|
+
if (tx.payload.functionArgs[0].type === ClarityType.UInt && tx.payload.functionArgs[1].type === ClarityType.PrincipalStandard && tx.payload.functionArgs[2].type === ClarityType.PrincipalStandard) return true;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
function isSip9Transfer({ functionName, contractInterfaceData }) {
|
|
383
|
+
if (functionName !== "transfer") return false;
|
|
384
|
+
const functionInterface = contractInterfaceData?.functions.find((f) => f.name === functionName);
|
|
385
|
+
if (functionInterface?.args[0]?.name === "id" && functionInterface?.args[1]?.name === "from" && functionInterface?.args[2]?.name === "to") return true;
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
function getSip9TransferRecipient({ functionName, functionArgs, contractInterfaceData }) {
|
|
389
|
+
if (isSip9Transfer({
|
|
390
|
+
functionName,
|
|
391
|
+
contractInterfaceData
|
|
392
|
+
}) && functionArgs[2]?.type === ClarityType.PrincipalStandard) return functionArgs[2].value;
|
|
393
|
+
return null;
|
|
517
394
|
}
|
|
518
395
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
import { z } from "zod";
|
|
522
|
-
import { ChainId as ChainId2 } from "@leather.io/models";
|
|
523
|
-
import { isEmptyString, isString as isString3, isUndefined } from "@leather.io/utils";
|
|
396
|
+
//#endregion
|
|
397
|
+
//#region src/validation/address-validation.ts
|
|
524
398
|
function isValidStacksAddress(address) {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
return false;
|
|
533
|
-
}
|
|
399
|
+
if (isUndefined(address) || isEmptyString(address)) return false;
|
|
400
|
+
try {
|
|
401
|
+
c32addressDecode(address);
|
|
402
|
+
return true;
|
|
403
|
+
} catch {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
534
406
|
}
|
|
535
407
|
function isValidAddressChain(address, chainId) {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
case ChainId2.Testnet:
|
|
544
|
-
return prefix === "SN" || prefix === "ST";
|
|
545
|
-
default:
|
|
546
|
-
return false;
|
|
547
|
-
}
|
|
408
|
+
if (!address) return false;
|
|
409
|
+
const prefix = address.slice(0, 2);
|
|
410
|
+
switch (chainId) {
|
|
411
|
+
case ChainId$1.Mainnet: return prefix === "SM" || prefix === "SP";
|
|
412
|
+
case ChainId$1.Testnet: return prefix === "SN" || prefix === "ST";
|
|
413
|
+
default: return false;
|
|
414
|
+
}
|
|
548
415
|
}
|
|
549
416
|
function validatePayerNotRecipient(senderAddress, recipientAddress) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
if (parts.length !== 2) return false;
|
|
568
|
-
const [address, contractName] = parts;
|
|
569
|
-
if (!isValidStacksAddress(address)) return false;
|
|
570
|
-
const contractNameRegex = /^[a-zA-Z0-9_-]{1,128}$/;
|
|
571
|
-
return contractNameRegex.test(contractName);
|
|
572
|
-
},
|
|
573
|
-
{ message: "Invalid contract principal (must be address.contract-name format)" }
|
|
574
|
-
);
|
|
575
|
-
var principalSchema = z.union([standardPrincipalSchema, contractPrincipalSchema]);
|
|
417
|
+
if (!senderAddress || !recipientAddress) return false;
|
|
418
|
+
return senderAddress !== recipientAddress;
|
|
419
|
+
}
|
|
420
|
+
const standardPrincipalSchema = z.string().refine((address) => {
|
|
421
|
+
if (!isString(address)) return false;
|
|
422
|
+
if (!isValidStacksAddress(address)) return false;
|
|
423
|
+
return !address.includes(".");
|
|
424
|
+
}, { message: "Invalid standard Stacks principal address" });
|
|
425
|
+
const contractPrincipalSchema = z.string().refine((principal) => {
|
|
426
|
+
if (!isString(principal)) return false;
|
|
427
|
+
const parts = principal.split(".");
|
|
428
|
+
if (parts.length !== 2) return false;
|
|
429
|
+
const [address, contractName] = parts;
|
|
430
|
+
if (!isValidStacksAddress(address)) return false;
|
|
431
|
+
return /^[a-zA-Z0-9_-]{1,128}$/.test(contractName);
|
|
432
|
+
}, { message: "Invalid contract principal (must be address.contract-name format)" });
|
|
433
|
+
const principalSchema = z.union([standardPrincipalSchema, contractPrincipalSchema]);
|
|
576
434
|
|
|
577
|
-
|
|
578
|
-
|
|
435
|
+
//#endregion
|
|
436
|
+
//#region src/validation/memo-validation.ts
|
|
579
437
|
function exceedsMaxLengthBytes(value, maxLengthBytes) {
|
|
580
|
-
|
|
438
|
+
return value ? Buffer.from(value).length > maxLengthBytes : false;
|
|
581
439
|
}
|
|
582
440
|
function isValidStacksMemo(memo) {
|
|
583
|
-
|
|
441
|
+
return !exceedsMaxLengthBytes(memo, MEMO_MAX_LENGTH_BYTES);
|
|
584
442
|
}
|
|
585
443
|
|
|
586
|
-
|
|
444
|
+
//#endregion
|
|
445
|
+
//#region src/validation/stacks-error.ts
|
|
587
446
|
var StacksError = class extends Error {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
447
|
+
message;
|
|
448
|
+
constructor(message) {
|
|
449
|
+
super(message);
|
|
450
|
+
this.name = "StacksError";
|
|
451
|
+
this.message = message;
|
|
452
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
453
|
+
}
|
|
595
454
|
};
|
|
596
455
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
import { isDefined, stxToMicroStx } from "@leather.io/utils";
|
|
456
|
+
//#endregion
|
|
457
|
+
//#region src/validation/amount-validation.ts
|
|
600
458
|
function isMoneyAmountValid(amount) {
|
|
601
|
-
|
|
459
|
+
return amount && isDefined(amount.amount) && amount.amount;
|
|
602
460
|
}
|
|
603
461
|
function isStxAmountValid({ availableBalance, amount, fee }) {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
availableBalance: { amount: availableBalanceAmount },
|
|
617
|
-
amount: { amount: desiredSpend },
|
|
618
|
-
fee: { amount: feeAmount }
|
|
619
|
-
}) {
|
|
620
|
-
const fee = new BigNumber2(stxToMicroStx(feeAmount));
|
|
621
|
-
if (!availableBalanceAmount) {
|
|
622
|
-
throw new StacksError("UnknownBalance");
|
|
623
|
-
}
|
|
624
|
-
if (!fee.isFinite()) {
|
|
625
|
-
throw new StacksError("UnknownFee");
|
|
626
|
-
}
|
|
627
|
-
const availableBalance = new BigNumber2(stxToMicroStx(availableBalanceAmount));
|
|
628
|
-
const spendableAmount = availableBalance.minus(fee);
|
|
629
|
-
const amount = new BigNumber2(stxToMicroStx(desiredSpend));
|
|
630
|
-
return spendableAmount.isGreaterThanOrEqualTo(amount);
|
|
462
|
+
if (!isMoneyAmountValid(amount)) throw new StacksError("InvalidAmount");
|
|
463
|
+
if (!isMoneyAmountValid(availableBalance)) throw new StacksError("UnknownBalance");
|
|
464
|
+
if (!isMoneyAmountValid(fee)) throw new StacksError("UnknownFee");
|
|
465
|
+
return true;
|
|
466
|
+
}
|
|
467
|
+
function isStxBalanceSufficient({ availableBalance: { amount: availableBalanceAmount }, amount: { amount: desiredSpend }, fee: { amount: feeAmount } }) {
|
|
468
|
+
const fee = new BigNumber(stxToMicroStx(feeAmount));
|
|
469
|
+
if (!availableBalanceAmount) throw new StacksError("UnknownBalance");
|
|
470
|
+
if (!fee.isFinite()) throw new StacksError("UnknownFee");
|
|
471
|
+
const spendableAmount = new BigNumber(stxToMicroStx(availableBalanceAmount)).minus(fee);
|
|
472
|
+
const amount = new BigNumber(stxToMicroStx(desiredSpend));
|
|
473
|
+
return spendableAmount.isGreaterThanOrEqualTo(amount);
|
|
631
474
|
}
|
|
632
475
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
}
|
|
651
|
-
if (!isStxAmountValid({ availableBalance, amount, fee })) {
|
|
652
|
-
throw new StacksError("InvalidAmount");
|
|
653
|
-
}
|
|
654
|
-
if (!isStxBalanceSufficient({ availableBalance, amount, fee })) {
|
|
655
|
-
throw new StacksError("InsufficientFunds");
|
|
656
|
-
}
|
|
657
|
-
return true;
|
|
476
|
+
//#endregion
|
|
477
|
+
//#region src/validation/transaction-validation.ts
|
|
478
|
+
function isValidStacksTransaction({ amount, availableBalance, fee, payer, recipient, chainId }) {
|
|
479
|
+
if (!isValidStacksAddress(payer) || !isValidStacksAddress(recipient)) throw new StacksError("InvalidAddress");
|
|
480
|
+
if (!isValidAddressChain(payer, chainId) || !isValidAddressChain(recipient, chainId)) throw new StacksError("InvalidNetworkAddress");
|
|
481
|
+
if (!validatePayerNotRecipient(payer, recipient)) throw new StacksError("InvalidSameAddress");
|
|
482
|
+
if (!isStxAmountValid({
|
|
483
|
+
availableBalance,
|
|
484
|
+
amount,
|
|
485
|
+
fee
|
|
486
|
+
})) throw new StacksError("InvalidAmount");
|
|
487
|
+
if (!isStxBalanceSufficient({
|
|
488
|
+
availableBalance,
|
|
489
|
+
amount,
|
|
490
|
+
fee
|
|
491
|
+
})) throw new StacksError("InsufficientFunds");
|
|
492
|
+
return true;
|
|
658
493
|
}
|
|
659
494
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
import { z as z2 } from "zod";
|
|
495
|
+
//#endregion
|
|
496
|
+
//#region src/schemas/clarity-contract.schema.ts
|
|
663
497
|
function isValidContractLength(contract) {
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
message: "ContractExceedsMaxLength"
|
|
673
|
-
});
|
|
498
|
+
try {
|
|
499
|
+
codeBodyString(contract);
|
|
500
|
+
return true;
|
|
501
|
+
} catch (_e) {
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const clarityContractSchema = z.string().refine((contract) => isValidContractLength(contract), { message: "ContractExceedsMaxLength" });
|
|
674
506
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
}
|
|
686
|
-
},
|
|
687
|
-
{ message: "Invalid memo string" }
|
|
688
|
-
);
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region src/schemas/memo.schema.ts
|
|
509
|
+
const stacksMemoSchema = z.string().refine((value) => {
|
|
510
|
+
try {
|
|
511
|
+
createMemoString(value);
|
|
512
|
+
return true;
|
|
513
|
+
} catch {
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
}, { message: "Invalid memo string" });
|
|
689
517
|
|
|
690
|
-
|
|
691
|
-
|
|
518
|
+
//#endregion
|
|
519
|
+
//#region src/transactions/serialization.ts
|
|
692
520
|
function getEstimatedUnsignedStacksTxByteLength(transaction) {
|
|
693
|
-
|
|
521
|
+
return transaction.serializeBytes().byteLength;
|
|
694
522
|
}
|
|
695
523
|
function getSerializedUnsignedStacksTxPayload(transaction) {
|
|
696
|
-
|
|
524
|
+
return serializePayload(transaction.payload);
|
|
697
525
|
}
|
|
698
526
|
|
|
699
|
-
|
|
700
|
-
|
|
527
|
+
//#endregion
|
|
528
|
+
//#region src/addresses.ts
|
|
701
529
|
function generateRandomStacksAddress() {
|
|
702
|
-
|
|
703
|
-
const privateKeyString = randomPrivateKey;
|
|
704
|
-
const randomAddress = getAddressFromPrivateKey(privateKeyString);
|
|
705
|
-
return randomAddress;
|
|
530
|
+
return getAddressFromPrivateKey(makeRandomPrivKey());
|
|
706
531
|
}
|
|
707
532
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
ClarityType as ClarityType3
|
|
711
|
-
} from "@stacks/transactions";
|
|
533
|
+
//#endregion
|
|
534
|
+
//#region src/clarity.ts
|
|
712
535
|
function parseClarityUintResponse(response) {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
return BigInt(response.value);
|
|
717
|
-
}
|
|
718
|
-
throw new Error("Invalid Clarity response format");
|
|
536
|
+
if (response.type === ClarityType.ResponseOk && response.value.type === ClarityType.UInt) return BigInt(response.value.value);
|
|
537
|
+
else if (response.type === ClarityType.UInt) return BigInt(response.value);
|
|
538
|
+
throw new Error("Invalid Clarity response format");
|
|
719
539
|
}
|
|
720
540
|
function isClarityTuple(cv) {
|
|
721
|
-
|
|
541
|
+
return cv.type === ClarityType.Tuple;
|
|
722
542
|
}
|
|
723
543
|
function isClarityResponseOk(cv) {
|
|
724
|
-
|
|
544
|
+
return cv.type === ClarityType.ResponseOk;
|
|
725
545
|
}
|
|
726
546
|
function isClarityResponseError(cv) {
|
|
727
|
-
|
|
547
|
+
return cv.type === ClarityType.ResponseErr;
|
|
728
548
|
}
|
|
729
549
|
function isClarityUInt(cv) {
|
|
730
|
-
|
|
550
|
+
return cv.type === ClarityType.UInt;
|
|
731
551
|
}
|
|
732
552
|
function isClarityList(cv) {
|
|
733
|
-
|
|
553
|
+
return cv.type === ClarityType.List;
|
|
734
554
|
}
|
|
735
555
|
function isClarityPrincipal(cv) {
|
|
736
|
-
|
|
556
|
+
return cv.type === ClarityType.PrincipalStandard || cv.type === ClarityType.PrincipalContract;
|
|
737
557
|
}
|
|
738
558
|
function isClarityOptionalNone(cv) {
|
|
739
|
-
|
|
559
|
+
return cv.type === ClarityType.OptionalNone;
|
|
740
560
|
}
|
|
741
561
|
function isClarityOptionalSome(cv) {
|
|
742
|
-
|
|
562
|
+
return cv.type === ClarityType.OptionalSome;
|
|
743
563
|
}
|
|
744
564
|
function getClarityPrincipal(cv) {
|
|
745
|
-
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
TEST_ACCOUNT_1_STX_ADDRESS_SM,
|
|
751
|
-
TEST_ACCOUNT_2_STX_ADDRESS,
|
|
752
|
-
TEST_TESTNET_ACCOUNT_2_STX_ADDRESS,
|
|
753
|
-
TEST_TESTNET_ACCOUNT_2_STX_ADDRESS_SN,
|
|
754
|
-
TransactionTypes,
|
|
755
|
-
clarityContractSchema,
|
|
756
|
-
cleanHex,
|
|
757
|
-
contractPrincipalSchema,
|
|
758
|
-
createSignFnFromMnemonic,
|
|
759
|
-
createSignMessageFnFromMnemonic,
|
|
760
|
-
createSignStructuredDataMessageFnFromMnemonic,
|
|
761
|
-
createSip10FnArgs,
|
|
762
|
-
createSip9FnArgs,
|
|
763
|
-
createTransferSip10TxHex,
|
|
764
|
-
deriveStxPrivateKey,
|
|
765
|
-
deriveStxPublicKey,
|
|
766
|
-
ensurePostConditionWireFormat,
|
|
767
|
-
extractStacksDerivationPathAccountIndex,
|
|
768
|
-
formatAssetString,
|
|
769
|
-
formatContractId,
|
|
770
|
-
formatContractIdString,
|
|
771
|
-
generateRandomStacksAddress,
|
|
772
|
-
generateStacksUnsignedTransaction,
|
|
773
|
-
getClarityPrincipal,
|
|
774
|
-
getErrorMessage,
|
|
775
|
-
getEstimatedUnsignedStacksTxByteLength,
|
|
776
|
-
getPostCondition,
|
|
777
|
-
getPostConditionFromString,
|
|
778
|
-
getPostConditions,
|
|
779
|
-
getPrincipalFromAssetString,
|
|
780
|
-
getSerializedUnsignedStacksTxPayload,
|
|
781
|
-
getSip10TransferAmount,
|
|
782
|
-
getSip10TransferRecipient,
|
|
783
|
-
getSip9TransferRecipient,
|
|
784
|
-
getStacksAssetStringParts,
|
|
785
|
-
getStacksBurnAddress,
|
|
786
|
-
getStacksContractAssetName,
|
|
787
|
-
getStacksContractName,
|
|
788
|
-
getUnsignedContractCallParsedOptions,
|
|
789
|
-
getUnsignedContractDeployParsedOptions,
|
|
790
|
-
getUnsignedStxTokenTransferParsedOptions,
|
|
791
|
-
initNonce,
|
|
792
|
-
initalizeStacksSigner,
|
|
793
|
-
isClarityList,
|
|
794
|
-
isClarityOptionalNone,
|
|
795
|
-
isClarityOptionalSome,
|
|
796
|
-
isClarityPrincipal,
|
|
797
|
-
isClarityResponseError,
|
|
798
|
-
isClarityResponseOk,
|
|
799
|
-
isClarityTuple,
|
|
800
|
-
isClarityUInt,
|
|
801
|
-
isSip10Transfer,
|
|
802
|
-
isSip10TransferContactCall,
|
|
803
|
-
isSip9Transfer,
|
|
804
|
-
isSip9TransferContactCall,
|
|
805
|
-
isTransactionTypeSupported,
|
|
806
|
-
isValidAddressChain,
|
|
807
|
-
isValidContractLength,
|
|
808
|
-
isValidStacksAddress,
|
|
809
|
-
isValidStacksMemo,
|
|
810
|
-
isValidStacksTransaction,
|
|
811
|
-
makeAccountIndexDerivationPathFactory,
|
|
812
|
-
makeStxDerivationPath,
|
|
813
|
-
parseClarityUintResponse,
|
|
814
|
-
principalSchema,
|
|
815
|
-
signMessage,
|
|
816
|
-
signStacksTransaction,
|
|
817
|
-
signStructuredDataMessage,
|
|
818
|
-
stacksChainIdToCoreNetworkMode,
|
|
819
|
-
stacksMemoSchema,
|
|
820
|
-
stacksRootKeychainToAccountDescriptor,
|
|
821
|
-
standardPrincipalSchema,
|
|
822
|
-
stxDerivationWithAccount,
|
|
823
|
-
validatePayerNotRecipient,
|
|
824
|
-
whenStacksChainId
|
|
825
|
-
};
|
|
565
|
+
return cv.value;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
//#endregion
|
|
569
|
+
export { StacksError, TEST_ACCOUNT_1_STX_ADDRESS, TEST_ACCOUNT_1_STX_ADDRESS_SM, TEST_ACCOUNT_2_STX_ADDRESS, TEST_TESTNET_ACCOUNT_2_STX_ADDRESS, TEST_TESTNET_ACCOUNT_2_STX_ADDRESS_SN, TransactionTypes, clarityContractSchema, cleanHex, contractPrincipalSchema, createSignFnFromMnemonic, createSignMessageFnFromMnemonic, createSignStructuredDataMessageFnFromMnemonic, createSip10FnArgs, createSip9FnArgs, createTransferSip10TxHex, deriveStxPrivateKey, deriveStxPublicKey, ensurePostConditionWireFormat, extractStacksDerivationPathAccountIndex, formatAssetString, formatContractId, formatContractIdString, generateRandomStacksAddress, generateStacksUnsignedTransaction, getClarityPrincipal, getErrorMessage, getEstimatedUnsignedStacksTxByteLength, getPostCondition, getPostConditionFromString, getPostConditions, getPrincipalFromAssetString, getSerializedUnsignedStacksTxPayload, getSip10TransferAmount, getSip10TransferRecipient, getSip9TransferRecipient, getStacksAssetStringParts, getStacksBurnAddress, getStacksContractAssetName, getStacksContractName, getUnsignedContractCallParsedOptions, getUnsignedContractDeployParsedOptions, getUnsignedStxTokenTransferParsedOptions, initNonce, initalizeStacksSigner, isClarityList, isClarityOptionalNone, isClarityOptionalSome, isClarityPrincipal, isClarityResponseError, isClarityResponseOk, isClarityTuple, isClarityUInt, isSip10Transfer, isSip10TransferContactCall, isSip9Transfer, isSip9TransferContactCall, isTransactionTypeSupported, isValidAddressChain, isValidContractLength, isValidStacksAddress, isValidStacksMemo, isValidStacksTransaction, makeAccountIndexDerivationPathFactory, makeStxDerivationPath, parseClarityUintResponse, principalSchema, signMessage, signStacksTransaction, signStructuredDataMessage, stacksChainIdToCoreNetworkMode, stacksMemoSchema, stacksRootKeychainToAccountDescriptor, standardPrincipalSchema, stxDerivationWithAccount, validatePayerNotRecipient, whenStacksChainId };
|
|
826
570
|
//# sourceMappingURL=index.js.map
|