@kaspacom/kcc20-tx-builder 0.1.0
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/LICENSE +201 -0
- package/README.md +104 -0
- package/artifacts/KCC20.placeholder.json +77479 -0
- package/artifacts/KCC20FeeTicket.placeholder.json +16846 -0
- package/artifacts/KCC20Orderbook.placeholder.json +78001 -0
- package/artifacts/KCC20Vesting.placeholder.json +4298 -0
- package/artifacts/KCC20Wrapper.placeholder.json +12246 -0
- package/dist/abi.d.ts +44 -0
- package/dist/abi.d.ts.map +1 -0
- package/dist/abi.js +336 -0
- package/dist/abi.js.map +1 -0
- package/dist/action-source-resolver.d.ts +80 -0
- package/dist/action-source-resolver.d.ts.map +1 -0
- package/dist/action-source-resolver.js +412 -0
- package/dist/action-source-resolver.js.map +1 -0
- package/dist/artifacts.d.ts +14 -0
- package/dist/artifacts.d.ts.map +1 -0
- package/dist/artifacts.js +44 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/builder.d.ts +12 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +18 -0
- package/dist/builder.js.map +1 -0
- package/dist/cjs/abi.d.ts +43 -0
- package/dist/cjs/abi.js +361 -0
- package/dist/cjs/abi.js.map +1 -0
- package/dist/cjs/action-source-resolver.d.ts +79 -0
- package/dist/cjs/action-source-resolver.js +435 -0
- package/dist/cjs/action-source-resolver.js.map +1 -0
- package/dist/cjs/artifacts.d.ts +13 -0
- package/dist/cjs/artifacts.js +51 -0
- package/dist/cjs/artifacts.js.map +1 -0
- package/dist/cjs/builder.d.ts +11 -0
- package/dist/cjs/builder.js +22 -0
- package/dist/cjs/builder.js.map +1 -0
- package/dist/cjs/deploy-operation.d.ts +103 -0
- package/dist/cjs/deploy-operation.js +335 -0
- package/dist/cjs/deploy-operation.js.map +1 -0
- package/dist/cjs/encoding.d.ts +5 -0
- package/dist/cjs/encoding.js +51 -0
- package/dist/cjs/encoding.js.map +1 -0
- package/dist/cjs/engine.d.ts +40 -0
- package/dist/cjs/engine.js +8972 -0
- package/dist/cjs/engine.js.map +1 -0
- package/dist/cjs/errors.d.ts +7 -0
- package/dist/cjs/errors.js +23 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/fee-ticket-operation.d.ts +204 -0
- package/dist/cjs/fee-ticket-operation.js +327 -0
- package/dist/cjs/fee-ticket-operation.js.map +1 -0
- package/dist/cjs/index.d.ts +27 -0
- package/dist/cjs/index.js +45 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/ladder-limit-orders.d.ts +41 -0
- package/dist/cjs/ladder-limit-orders.js +129 -0
- package/dist/cjs/ladder-limit-orders.js.map +1 -0
- package/dist/cjs/mint-availability-operation.d.ts +56 -0
- package/dist/cjs/mint-availability-operation.js +95 -0
- package/dist/cjs/mint-availability-operation.js.map +1 -0
- package/dist/cjs/models.d.ts +90 -0
- package/dist/cjs/models.js +6 -0
- package/dist/cjs/models.js.map +1 -0
- package/dist/cjs/operations.d.ts +6 -0
- package/dist/cjs/operations.js +41 -0
- package/dist/cjs/operations.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/paid-mint-amount.d.ts +69 -0
- package/dist/cjs/paid-mint-amount.js +281 -0
- package/dist/cjs/paid-mint-amount.js.map +1 -0
- package/dist/cjs/protocol.d.ts +21 -0
- package/dist/cjs/protocol.js +25 -0
- package/dist/cjs/protocol.js.map +1 -0
- package/dist/cjs/runtime.d.ts +27 -0
- package/dist/cjs/runtime.js +3 -0
- package/dist/cjs/runtime.js.map +1 -0
- package/dist/cjs/sale-common.d.ts +287 -0
- package/dist/cjs/sale-common.js +928 -0
- package/dist/cjs/sale-common.js.map +1 -0
- package/dist/cjs/source-provider.d.ts +11 -0
- package/dist/cjs/source-provider.js +3 -0
- package/dist/cjs/source-provider.js.map +1 -0
- package/dist/cjs/source-validation.d.ts +9 -0
- package/dist/cjs/source-validation.js +33 -0
- package/dist/cjs/source-validation.js.map +1 -0
- package/dist/cjs/token-amount.d.ts +31 -0
- package/dist/cjs/token-amount.js +252 -0
- package/dist/cjs/token-amount.js.map +1 -0
- package/dist/cjs/token-operation.d.ts +135 -0
- package/dist/cjs/token-operation.js +236 -0
- package/dist/cjs/token-operation.js.map +1 -0
- package/dist/cjs/trade-fee.d.ts +60 -0
- package/dist/cjs/trade-fee.js +185 -0
- package/dist/cjs/trade-fee.js.map +1 -0
- package/dist/cjs/trading-operation.d.ts +212 -0
- package/dist/cjs/trading-operation.js +587 -0
- package/dist/cjs/trading-operation.js.map +1 -0
- package/dist/cjs/verify-operation.d.ts +79 -0
- package/dist/cjs/verify-operation.js +246 -0
- package/dist/cjs/verify-operation.js.map +1 -0
- package/dist/cjs/wallet-operation.d.ts +52 -0
- package/dist/cjs/wallet-operation.js +58 -0
- package/dist/cjs/wallet-operation.js.map +1 -0
- package/dist/cjs/wasm-provider.d.ts +15 -0
- package/dist/cjs/wasm-provider.js +20 -0
- package/dist/cjs/wasm-provider.js.map +1 -0
- package/dist/cjs/wrapper-operation.d.ts +196 -0
- package/dist/cjs/wrapper-operation.js +317 -0
- package/dist/cjs/wrapper-operation.js.map +1 -0
- package/dist/deploy-operation.d.ts +104 -0
- package/dist/deploy-operation.d.ts.map +1 -0
- package/dist/deploy-operation.js +327 -0
- package/dist/deploy-operation.js.map +1 -0
- package/dist/encoding.d.ts +6 -0
- package/dist/encoding.d.ts.map +1 -0
- package/dist/encoding.js +44 -0
- package/dist/encoding.js.map +1 -0
- package/dist/engine.d.ts +41 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +8969 -0
- package/dist/engine.js.map +1 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -0
- package/dist/fee-ticket-operation.d.ts +205 -0
- package/dist/fee-ticket-operation.d.ts.map +1 -0
- package/dist/fee-ticket-operation.js +320 -0
- package/dist/fee-ticket-operation.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/ladder-limit-orders.d.ts +42 -0
- package/dist/ladder-limit-orders.d.ts.map +1 -0
- package/dist/ladder-limit-orders.js +121 -0
- package/dist/ladder-limit-orders.js.map +1 -0
- package/dist/mint-availability-operation.d.ts +57 -0
- package/dist/mint-availability-operation.d.ts.map +1 -0
- package/dist/mint-availability-operation.js +91 -0
- package/dist/mint-availability-operation.js.map +1 -0
- package/dist/models.d.ts +91 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +3 -0
- package/dist/models.js.map +1 -0
- package/dist/operations.d.ts +7 -0
- package/dist/operations.d.ts.map +1 -0
- package/dist/operations.js +36 -0
- package/dist/operations.js.map +1 -0
- package/dist/paid-mint-amount.d.ts +70 -0
- package/dist/paid-mint-amount.d.ts.map +1 -0
- package/dist/paid-mint-amount.js +268 -0
- package/dist/paid-mint-amount.js.map +1 -0
- package/dist/protocol.d.ts +22 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +22 -0
- package/dist/protocol.js.map +1 -0
- package/dist/runtime.d.ts +28 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +2 -0
- package/dist/runtime.js.map +1 -0
- package/dist/sale-common.d.ts +288 -0
- package/dist/sale-common.d.ts.map +1 -0
- package/dist/sale-common.js +844 -0
- package/dist/sale-common.js.map +1 -0
- package/dist/source-provider.d.ts +12 -0
- package/dist/source-provider.d.ts.map +1 -0
- package/dist/source-provider.js +2 -0
- package/dist/source-provider.js.map +1 -0
- package/dist/source-validation.d.ts +10 -0
- package/dist/source-validation.d.ts.map +1 -0
- package/dist/source-validation.js +28 -0
- package/dist/source-validation.js.map +1 -0
- package/dist/token-amount.d.ts +32 -0
- package/dist/token-amount.d.ts.map +1 -0
- package/dist/token-amount.js +237 -0
- package/dist/token-amount.js.map +1 -0
- package/dist/token-operation.d.ts +136 -0
- package/dist/token-operation.d.ts.map +1 -0
- package/dist/token-operation.js +231 -0
- package/dist/token-operation.js.map +1 -0
- package/dist/trade-fee.d.ts +61 -0
- package/dist/trade-fee.d.ts.map +1 -0
- package/dist/trade-fee.js +173 -0
- package/dist/trade-fee.js.map +1 -0
- package/dist/trading-operation.d.ts +213 -0
- package/dist/trading-operation.d.ts.map +1 -0
- package/dist/trading-operation.js +580 -0
- package/dist/trading-operation.js.map +1 -0
- package/dist/verify-operation.d.ts +80 -0
- package/dist/verify-operation.d.ts.map +1 -0
- package/dist/verify-operation.js +243 -0
- package/dist/verify-operation.js.map +1 -0
- package/dist/wallet-operation.d.ts +53 -0
- package/dist/wallet-operation.d.ts.map +1 -0
- package/dist/wallet-operation.js +55 -0
- package/dist/wallet-operation.js.map +1 -0
- package/dist/wasm-provider.d.ts +16 -0
- package/dist/wasm-provider.d.ts.map +1 -0
- package/dist/wasm-provider.js +17 -0
- package/dist/wasm-provider.js.map +1 -0
- package/dist/wrapper-operation.d.ts +197 -0
- package/dist/wrapper-operation.d.ts.map +1 -0
- package/dist/wrapper-operation.js +311 -0
- package/dist/wrapper-operation.js.map +1 -0
- package/index.d.ts +1 -0
- package/package.json +84 -0
- package/src/abi.ts +493 -0
- package/src/action-source-resolver.ts +660 -0
- package/src/artifacts.ts +87 -0
- package/src/builder.ts +37 -0
- package/src/deploy-operation.ts +458 -0
- package/src/encoding.ts +58 -0
- package/src/engine.ts +13226 -0
- package/src/errors.ts +35 -0
- package/src/fee-ticket-operation.ts +518 -0
- package/src/index.ts +27 -0
- package/src/ladder-limit-orders.ts +184 -0
- package/src/mint-availability-operation.ts +146 -0
- package/src/models.ts +103 -0
- package/src/operations.ts +46 -0
- package/src/paid-mint-amount.ts +402 -0
- package/src/protocol.ts +28 -0
- package/src/runtime.ts +29 -0
- package/src/sale-common.ts +1238 -0
- package/src/source-provider.ts +12 -0
- package/src/source-validation.ts +47 -0
- package/src/token-amount.ts +302 -0
- package/src/token-operation.ts +384 -0
- package/src/trade-fee.ts +264 -0
- package/src/trading-operation.ts +842 -0
- package/src/verify-operation.ts +400 -0
- package/src/wallet-operation.ts +86 -0
- package/src/wasm-provider.ts +32 -0
- package/src/wrapper-operation.ts +531 -0
|
@@ -0,0 +1,1238 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-unused-vars */
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import {
|
|
4
|
+
buildKcc20ScriptForState as buildStandardKcc20ScriptForState,
|
|
5
|
+
dispatchTag,
|
|
6
|
+
} from "./abi.js";
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_COMPUTE_BUDGET,
|
|
9
|
+
DEFAULT_KCC20_FEE_BPS,
|
|
10
|
+
DEFAULT_KCC20_MIN_PROTOCOL_FEE_SOMPI,
|
|
11
|
+
DEFAULT_KCC20_PRICE_SCALE,
|
|
12
|
+
DEFAULT_KCC20_TOKEN_DECIMALS,
|
|
13
|
+
DEFAULT_TOKEN_OUTPUT_SOMPI,
|
|
14
|
+
KCC20_ORDERBOOK_EXPANDED_SWEEP_OUTPUT_SOMPI,
|
|
15
|
+
KCC20_ORDERBOOK_MAX_EXPANDED_SWEEP_BID_LEGS,
|
|
16
|
+
KCC20_ORDERBOOK_MAX_SWEEP_BID_LEGS,
|
|
17
|
+
KCC20_ORDERBOOK_PROTOCOL_FEE_RECIPIENT,
|
|
18
|
+
KCC20_PLATFORM_PROTOCOL_FEE_RECIPIENT,
|
|
19
|
+
SOMPI_PER_TKAS,
|
|
20
|
+
SUBNETWORK_ID_NATIVE,
|
|
21
|
+
ZERO_HASH,
|
|
22
|
+
} from "./protocol.js";
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
DEFAULT_COMPUTE_BUDGET,
|
|
26
|
+
DEFAULT_KCC20_FEE_BPS,
|
|
27
|
+
DEFAULT_KCC20_MIN_PROTOCOL_FEE_SOMPI,
|
|
28
|
+
DEFAULT_KCC20_PRICE_SCALE,
|
|
29
|
+
DEFAULT_KCC20_TOKEN_DECIMALS,
|
|
30
|
+
DEFAULT_TOKEN_OUTPUT_SOMPI,
|
|
31
|
+
KCC20_ORDERBOOK_EXPANDED_SWEEP_OUTPUT_SOMPI,
|
|
32
|
+
KCC20_ORDERBOOK_MAX_EXPANDED_SWEEP_BID_LEGS,
|
|
33
|
+
KCC20_ORDERBOOK_MAX_SWEEP_BID_LEGS,
|
|
34
|
+
KCC20_ORDERBOOK_PROTOCOL_FEE_RECIPIENT,
|
|
35
|
+
KCC20_PLATFORM_PROTOCOL_FEE_RECIPIENT,
|
|
36
|
+
SOMPI_PER_TKAS,
|
|
37
|
+
SUBNETWORK_ID_NATIVE,
|
|
38
|
+
ZERO_HASH,
|
|
39
|
+
} from "./protocol.js";
|
|
40
|
+
|
|
41
|
+
export const DEFAULT_FEE = 50_000n;
|
|
42
|
+
export const DEFAULT_KCC20_MIN_GROSS_FILL_SOMPI = 50_000_000n;
|
|
43
|
+
|
|
44
|
+
export function kcc20PsktBuilderError(message, code, details = {}) {
|
|
45
|
+
const error = new Error(message);
|
|
46
|
+
error.builderErrorCode = code;
|
|
47
|
+
error.builderErrorDetails = Object.fromEntries(
|
|
48
|
+
Object.entries(details)
|
|
49
|
+
.filter(([, value]) => value !== undefined && value !== null)
|
|
50
|
+
.map(([key, value]) => [key, String(value)]),
|
|
51
|
+
);
|
|
52
|
+
return error;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const WRAPPED_ACTION_TAGS = Object.freeze({
|
|
56
|
+
unwrapByOwnerSig: kcc1Tag("unwrapByOwnerSig(byte[],int,int,int,int)"),
|
|
57
|
+
createBidFromRoot: kcc1Tag("createBidFromRoot(byte[32],int,int,int,int)"),
|
|
58
|
+
createAskByOwnerSig: kcc1Tag("createAskByOwnerSig(byte[],int,int,int,int)"),
|
|
59
|
+
fillAskPartial: kcc1Tag("fillAskPartial(byte[32],int,int,int,int,int)"),
|
|
60
|
+
fillBidPartial: kcc1Tag("fillBidPartial(int,int,int,int,int,pubkey,int)"),
|
|
61
|
+
sellIntoBidByOwnerSig: kcc1Tag(
|
|
62
|
+
"sellIntoBidByOwnerSig(byte[],byte[32],int,int,int,int,int)",
|
|
63
|
+
),
|
|
64
|
+
crossAskSide: kcc1Tag(
|
|
65
|
+
"crossAskSide(byte[32],int,int,int,int,int,int,int,int,int,int)",
|
|
66
|
+
),
|
|
67
|
+
crossBidSide: kcc1Tag(
|
|
68
|
+
"crossBidSide(int,int,int,int,int,int,int,int,int,pubkey,int)",
|
|
69
|
+
),
|
|
70
|
+
cancelAskByOwnerSig: kcc1Tag("cancelAskByOwnerSig(byte[],int)"),
|
|
71
|
+
cancelBidByOwnerSig: kcc1Tag("cancelBidByOwnerSig(byte[],int)"),
|
|
72
|
+
mergeByOwnerSig: kcc1Tag("mergeByOwnerSig(byte[])"),
|
|
73
|
+
mergePeerByOwnerSig: kcc1Tag("mergePeerByOwnerSig(byte[],int,int)"),
|
|
74
|
+
fillBidFromSellerSweep: kcc1Tag(
|
|
75
|
+
"fillBidFromSellerSweep(int,int,int,int,int,int,pubkey,int)",
|
|
76
|
+
),
|
|
77
|
+
sellIntoBidsByOwnerSig: kcc1Tag(
|
|
78
|
+
"sellIntoBidsByOwnerSig(byte[],byte[32],int,int,byte[32],int,int,byte[32],int,int,int,int,int)",
|
|
79
|
+
),
|
|
80
|
+
sellIntoBids10ByOwnerSig: kcc1Tag(
|
|
81
|
+
"sellIntoBids10ByOwnerSig(byte[],byte[32],int,int,byte[32],int,int,byte[32],int,int,byte[32],int,int,byte[32],int,int,byte[32],int,int,byte[32],int,int,byte[32],int,int,byte[32],int,int,byte[32],int,int,int,int,int)",
|
|
82
|
+
),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
function kcc1Tag(signature) {
|
|
86
|
+
const match = /^([A-Za-z_][A-Za-z0-9_]*)\((.*)\)$/.exec(signature);
|
|
87
|
+
if (!match) throw new Error(`invalid KCC1 signature ${signature}`);
|
|
88
|
+
const inputs = match[2]
|
|
89
|
+
? match[2].split(",").map((type_name) => ({ type_name }))
|
|
90
|
+
: [];
|
|
91
|
+
return dispatchTag({ name: match[1], inputs });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function parseArgs(argv) {
|
|
95
|
+
const map = { flags: new Set() };
|
|
96
|
+
for (let i = 0; i < argv.length; i++) {
|
|
97
|
+
const a = argv[i];
|
|
98
|
+
if (!a.startsWith("--")) continue;
|
|
99
|
+
const next = argv[i + 1];
|
|
100
|
+
if (!next || next.startsWith("--")) {
|
|
101
|
+
map.flags.add(a);
|
|
102
|
+
} else {
|
|
103
|
+
map[a.slice(2)] = next;
|
|
104
|
+
i++;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return map;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function parseTokenDecimalsArg(args) {
|
|
111
|
+
if (args["token-decimals"] == null) return null;
|
|
112
|
+
const raw = String(args["token-decimals"]).trim();
|
|
113
|
+
if (!/^\d+$/.test(raw))
|
|
114
|
+
throw new Error(`invalid --token-decimals ${args["token-decimals"]}`);
|
|
115
|
+
const decimals = Number(raw);
|
|
116
|
+
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 8) {
|
|
117
|
+
throw new Error(`invalid --token-decimals ${args["token-decimals"]}`);
|
|
118
|
+
}
|
|
119
|
+
return decimals;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function resolveKcc20TokenDecimals(args, ...values) {
|
|
123
|
+
const explicitDecimals = parseTokenDecimalsArg(args);
|
|
124
|
+
if (explicitDecimals != null) return explicitDecimals;
|
|
125
|
+
return values.some((value) => String(value ?? "").includes("."))
|
|
126
|
+
? DEFAULT_KCC20_TOKEN_DECIMALS
|
|
127
|
+
: 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function parseKcc20TokenAmount(
|
|
131
|
+
value,
|
|
132
|
+
label = "token amount",
|
|
133
|
+
decimals = 0,
|
|
134
|
+
) {
|
|
135
|
+
const raw = String(value ?? "").trim();
|
|
136
|
+
if (!raw) throw new Error(`missing ${label}`);
|
|
137
|
+
if (!/^(?:0|[1-9]\d*)(?:\.\d+)?$/.test(raw)) {
|
|
138
|
+
throw new Error(`${label} must be a non-negative decimal amount`);
|
|
139
|
+
}
|
|
140
|
+
const [whole, fraction = ""] = raw.split(".");
|
|
141
|
+
if (decimals === 0 && fraction.length > 0) {
|
|
142
|
+
throw new Error(`${label} requires --token-decimals for fractional input`);
|
|
143
|
+
}
|
|
144
|
+
if (fraction.length > decimals) {
|
|
145
|
+
throw new Error(`${label} supports at most ${decimals} decimal places`);
|
|
146
|
+
}
|
|
147
|
+
const scale = 10n ** BigInt(decimals);
|
|
148
|
+
return (
|
|
149
|
+
BigInt(whole) * scale +
|
|
150
|
+
BigInt((fraction + "0".repeat(decimals)).slice(0, decimals) || "0")
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function parseKcc20TokenAmountArg(args, key, fallback, label = key) {
|
|
155
|
+
const raw = args[key] ?? fallback;
|
|
156
|
+
const decimals = resolveKcc20TokenDecimals(args, raw);
|
|
157
|
+
return parseKcc20TokenAmount(raw, label, decimals);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function resolveKcc20PriceScale(
|
|
161
|
+
args,
|
|
162
|
+
fallback = DEFAULT_KCC20_PRICE_SCALE,
|
|
163
|
+
) {
|
|
164
|
+
if (args["price-scale"] != null) {
|
|
165
|
+
const raw = String(args["price-scale"]).trim();
|
|
166
|
+
if (!/^[1-9]\d*$/.test(raw))
|
|
167
|
+
throw new Error(`invalid --price-scale ${args["price-scale"]}`);
|
|
168
|
+
return BigInt(raw);
|
|
169
|
+
}
|
|
170
|
+
const decimals = parseTokenDecimalsArg(args);
|
|
171
|
+
if (decimals != null) return 10n ** BigInt(decimals);
|
|
172
|
+
return BigInt(fallback);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function requireHex32(value, label) {
|
|
176
|
+
const clean = String(value || "")
|
|
177
|
+
.trim()
|
|
178
|
+
.replace(/^0x/i, "")
|
|
179
|
+
.toLowerCase();
|
|
180
|
+
if (!/^[0-9a-f]{64}$/.test(clean)) {
|
|
181
|
+
throw new Error(`${label} must be 32-byte hex, got: ${value}`);
|
|
182
|
+
}
|
|
183
|
+
return clean;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function identifierTypeName(t) {
|
|
187
|
+
if (t === 0) return "p2pk-schnorr/v1";
|
|
188
|
+
if (t === 1) return "p2pkh-schnorr/v1";
|
|
189
|
+
if (t === 2) return "p2pkh-ecdsa/v1";
|
|
190
|
+
if (t === 3) return "p2sh/v1";
|
|
191
|
+
if (t === 4) return "covenant-id/v1";
|
|
192
|
+
return "unknown";
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function parseMintPolicy(value) {
|
|
196
|
+
const raw = String(value).trim().toLowerCase();
|
|
197
|
+
if (
|
|
198
|
+
raw === "0" ||
|
|
199
|
+
raw === "holder" ||
|
|
200
|
+
raw === "fixed" ||
|
|
201
|
+
raw === "fixed-supply" ||
|
|
202
|
+
raw === "fixedsupply"
|
|
203
|
+
)
|
|
204
|
+
return 0;
|
|
205
|
+
if (
|
|
206
|
+
raw === "1" ||
|
|
207
|
+
raw === "controlled" ||
|
|
208
|
+
raw === "controlled-mint" ||
|
|
209
|
+
raw === "controlledmint"
|
|
210
|
+
)
|
|
211
|
+
return 1;
|
|
212
|
+
if (
|
|
213
|
+
raw === "2" ||
|
|
214
|
+
raw === "public" ||
|
|
215
|
+
raw === "public-mint" ||
|
|
216
|
+
raw === "publicmint"
|
|
217
|
+
)
|
|
218
|
+
return 2;
|
|
219
|
+
throw new Error(`invalid KCC20 mint policy: ${value}`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function mintPolicyName(mode) {
|
|
223
|
+
if (mode === 0) return "fixed";
|
|
224
|
+
if (mode === 1) return "controlled";
|
|
225
|
+
if (mode === 2) return "public";
|
|
226
|
+
return "unknown";
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function hexToBytes(hex) {
|
|
230
|
+
const clean = String(hex).trim().replace(/^0x/i, "");
|
|
231
|
+
if (!/^(?:[0-9a-f]{2})*$/i.test(clean)) {
|
|
232
|
+
throw new Error(`invalid even-length hex value: ${hex}`);
|
|
233
|
+
}
|
|
234
|
+
const out = new Uint8Array(clean.length / 2);
|
|
235
|
+
for (let i = 0; i < out.length; i++) {
|
|
236
|
+
out[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
237
|
+
}
|
|
238
|
+
return out;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function bytesToHex(bytes) {
|
|
242
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export function asciiToBytes32(value, label) {
|
|
246
|
+
const clean = String(value || "")
|
|
247
|
+
.trim()
|
|
248
|
+
.replace(/\s+/g, " ");
|
|
249
|
+
if (!/^[\x20-\x7E]*$/.test(clean)) {
|
|
250
|
+
throw new Error(`${label} must be printable ASCII`);
|
|
251
|
+
}
|
|
252
|
+
const encoded = new TextEncoder().encode(clean);
|
|
253
|
+
if (encoded.length > 32) {
|
|
254
|
+
throw new Error(`${label} must be 32 bytes or fewer`);
|
|
255
|
+
}
|
|
256
|
+
const out = new Uint8Array(32);
|
|
257
|
+
out.set(encoded);
|
|
258
|
+
return out;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export function bytes32ToAscii(bytes) {
|
|
262
|
+
const arr = Uint8Array.from(bytes || []);
|
|
263
|
+
const end = arr.indexOf(0);
|
|
264
|
+
return new TextDecoder().decode(end >= 0 ? arr.slice(0, end) : arr).trimEnd();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function writeI64LE(value) {
|
|
268
|
+
let n = BigInt(value);
|
|
269
|
+
if (n > 9_223_372_036_854_775_807n) {
|
|
270
|
+
throw new Error(`amount exceeds signed i64 range: ${value}`);
|
|
271
|
+
}
|
|
272
|
+
if (n < 0n) {
|
|
273
|
+
n = (1n << 64n) + n;
|
|
274
|
+
}
|
|
275
|
+
const out = new Uint8Array(8);
|
|
276
|
+
for (let i = 0; i < out.length; i++) {
|
|
277
|
+
out[i] = Number((n >> BigInt(8 * i)) & 0xffn);
|
|
278
|
+
}
|
|
279
|
+
return out;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function readI64LE(bytes) {
|
|
283
|
+
if (bytes.length !== 8) {
|
|
284
|
+
throw new Error(`readI64LE expected 8 bytes, got ${bytes.length}`);
|
|
285
|
+
}
|
|
286
|
+
let n = 0n;
|
|
287
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
288
|
+
n |= BigInt(bytes[i]) << BigInt(8 * i);
|
|
289
|
+
}
|
|
290
|
+
if (n & (1n << 63n)) {
|
|
291
|
+
n -= 1n << 64n;
|
|
292
|
+
}
|
|
293
|
+
return n;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export function normalizeSignature(bytes) {
|
|
297
|
+
if (bytes.length === 66 && bytes[0] === 65) {
|
|
298
|
+
return bytes.slice(1);
|
|
299
|
+
}
|
|
300
|
+
if (bytes.length !== 65) {
|
|
301
|
+
throw new Error(
|
|
302
|
+
`expected 65-byte Schnorr signature+sighash, got ${bytes.length}`,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
return bytes;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function patchRange(target, start, end, replacement) {
|
|
309
|
+
if (replacement.length !== end - start) {
|
|
310
|
+
throw new Error(
|
|
311
|
+
`patch length mismatch for ${start}..${end}: ${replacement.length}`,
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
target.set(replacement, start);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export function buildNativeKcc20ScriptForState(baseScript, state) {
|
|
318
|
+
return buildStandardKcc20ScriptForState(
|
|
319
|
+
{ bytecode: Array.from(baseScript), state_layout: { start: 1, len: 112 } },
|
|
320
|
+
{
|
|
321
|
+
amount: BigInt(state.amount),
|
|
322
|
+
owner: state.ownerIdentifier || state.owner,
|
|
323
|
+
ownerScheme: Number(state.identifierType ?? state.ownerScheme ?? 0),
|
|
324
|
+
borrowScheme: Number(state.borrowScheme ?? 0),
|
|
325
|
+
borrowGuard: state.borrowGuard || hexToBytes(ZERO_HASH),
|
|
326
|
+
extensionCommitment: state.extensionCommitment,
|
|
327
|
+
},
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export function buildKcc20V3ScriptForState(baseScript, state) {
|
|
332
|
+
const script = Uint8Array.from(baseScript);
|
|
333
|
+
patchRange(script, 2, 34, state.ownerIdentifier);
|
|
334
|
+
expectPushLen(script, 34, 8, "amount");
|
|
335
|
+
patchRange(script, 35, 43, writeI64LE(state.amount));
|
|
336
|
+
expectPushLen(script, 43, 8, "mode");
|
|
337
|
+
patchRange(script, 44, 52, writeI64LE(BigInt(state.mode)));
|
|
338
|
+
expectPushLen(script, 52, 8, "unitPriceSompi");
|
|
339
|
+
patchRange(script, 53, 61, writeI64LE(state.unitPriceSompi));
|
|
340
|
+
return script;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export function buildApiPaymentChannelScriptForState(baseScript, state) {
|
|
344
|
+
const script = Uint8Array.from(baseScript);
|
|
345
|
+
patchRange(script, 2, 34, hexToBytes(state.payerPubkey));
|
|
346
|
+
patchRange(script, 35, 67, hexToBytes(state.providerPubkey));
|
|
347
|
+
patchRange(script, 68, 100, hexToBytes(state.providerPayoutPubkey));
|
|
348
|
+
patchRange(script, 101, 133, hexToBytes(state.voucherDomainHash));
|
|
349
|
+
patchRange(script, 134, 142, writeI64LE(state.refundAfterMs));
|
|
350
|
+
patchRange(script, 143, 151, writeI64LE(state.reserveSompi));
|
|
351
|
+
patchRange(script, 152, 160, writeI64LE(state.maxSpendSompi));
|
|
352
|
+
patchRange(script, 161, 169, writeI64LE(state.closeAfterMs || 0n));
|
|
353
|
+
return script;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export function buildKcc20OrderbookScriptForState(baseScript, state) {
|
|
357
|
+
if (!state.canonicalTokenId)
|
|
358
|
+
throw new Error("KCC20Orderbook state missing canonicalTokenId");
|
|
359
|
+
const priceScale = requireSupportedKcc20DisplayScale(
|
|
360
|
+
state.priceScale ?? DEFAULT_KCC20_PRICE_SCALE,
|
|
361
|
+
"KCC20Orderbook priceScale",
|
|
362
|
+
);
|
|
363
|
+
const script = Uint8Array.from(baseScript);
|
|
364
|
+
expectPushLen(script, 1, 32, "canonicalTokenId");
|
|
365
|
+
patchRange(script, 2, 34, state.canonicalTokenId);
|
|
366
|
+
expectPushLen(script, 34, 32, "ownerIdentifier");
|
|
367
|
+
patchRange(script, 35, 67, state.ownerIdentifier);
|
|
368
|
+
expectPushLen(script, 67, 1, "ownerScheme");
|
|
369
|
+
patchRange(
|
|
370
|
+
script,
|
|
371
|
+
68,
|
|
372
|
+
69,
|
|
373
|
+
Uint8Array.of(Number(state.ownerScheme ?? state.identifierType ?? 0)),
|
|
374
|
+
);
|
|
375
|
+
expectPushLen(script, 69, 8, "amount");
|
|
376
|
+
patchRange(script, 70, 78, writeI64LE(state.amount));
|
|
377
|
+
expectPushLen(script, 78, 8, "mode");
|
|
378
|
+
patchRange(script, 79, 87, writeI64LE(BigInt(state.mode)));
|
|
379
|
+
expectPushLen(script, 87, 8, "unitPriceSompi");
|
|
380
|
+
patchRange(script, 88, 96, writeI64LE(state.unitPriceSompi));
|
|
381
|
+
expectPushLen(script, 96, 32, "feeTicketId");
|
|
382
|
+
patchRange(script, 97, 129, state.feeTicketId || hexToBytes(ZERO_HASH));
|
|
383
|
+
expectPushLen(script, 129, 8, "priceScale");
|
|
384
|
+
patchRange(script, 130, 138, writeI64LE(priceScale));
|
|
385
|
+
return script;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
export function buildKcc20FeeTicketScriptForState(baseScript, state) {
|
|
389
|
+
const script = Uint8Array.from(baseScript);
|
|
390
|
+
patchRange(script, 2, 34, state.ownerIdentifier);
|
|
391
|
+
expectPushLen(script, 34, 1, "ownerScheme");
|
|
392
|
+
patchRange(
|
|
393
|
+
script,
|
|
394
|
+
35,
|
|
395
|
+
36,
|
|
396
|
+
Uint8Array.of(Number(state.ownerScheme ?? state.identifierType ?? 0)),
|
|
397
|
+
);
|
|
398
|
+
expectPushLen(script, 36, 8, "mode");
|
|
399
|
+
patchRange(script, 37, 45, writeI64LE(BigInt(state.mode)));
|
|
400
|
+
expectPushLen(script, 45, 32, "utilityTokenId");
|
|
401
|
+
patchRange(script, 46, 78, state.utilityTokenId);
|
|
402
|
+
expectPushLen(script, 78, 8, "denomination");
|
|
403
|
+
patchRange(script, 79, 87, writeI64LE(BigInt(state.denomination)));
|
|
404
|
+
return script;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export function buildKcc20VestingScriptForState(baseScript, state) {
|
|
408
|
+
const script = Uint8Array.from(baseScript);
|
|
409
|
+
expectPushLen(script, 1, 32, "canonicalTokenId");
|
|
410
|
+
patchRange(script, 2, 34, state.canonicalTokenId);
|
|
411
|
+
expectPushLen(script, 34, 32, "beneficiary");
|
|
412
|
+
patchRange(script, 35, 67, state.beneficiary);
|
|
413
|
+
expectPushLen(script, 67, 1, "beneficiaryScheme");
|
|
414
|
+
patchRange(
|
|
415
|
+
script,
|
|
416
|
+
68,
|
|
417
|
+
69,
|
|
418
|
+
Uint8Array.of(
|
|
419
|
+
Number(state.beneficiaryScheme ?? state.beneficiaryType ?? 0),
|
|
420
|
+
),
|
|
421
|
+
);
|
|
422
|
+
expectPushLen(script, 69, 8, "unlockTimeMs");
|
|
423
|
+
patchRange(script, 70, 78, writeI64LE(BigInt(state.unlockTimeMs)));
|
|
424
|
+
return script;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export function buildKaspaFomoRoundScript(baseScript, state, recipients = {}) {
|
|
428
|
+
const script = buildKaspaFomoRoundScriptForState(baseScript, state);
|
|
429
|
+
if (recipients.roundSigner) {
|
|
430
|
+
const signer = hexToBytes(
|
|
431
|
+
requireHex32(recipients.roundSigner, "round signer"),
|
|
432
|
+
);
|
|
433
|
+
patchRange(script, 118, 150, signer);
|
|
434
|
+
patchRange(script, 357, 389, signer);
|
|
435
|
+
}
|
|
436
|
+
if (recipients.marketingRecipient) {
|
|
437
|
+
patchRange(
|
|
438
|
+
script,
|
|
439
|
+
537,
|
|
440
|
+
569,
|
|
441
|
+
hexToBytes(
|
|
442
|
+
requireHex32(recipients.marketingRecipient, "marketing recipient"),
|
|
443
|
+
),
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
if (recipients.platformRecipient) {
|
|
447
|
+
patchRange(
|
|
448
|
+
script,
|
|
449
|
+
599,
|
|
450
|
+
631,
|
|
451
|
+
hexToBytes(
|
|
452
|
+
requireHex32(recipients.platformRecipient, "platform recipient"),
|
|
453
|
+
),
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
return script;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export function buildKaspaFomoRoundScriptForState(baseScript, state) {
|
|
460
|
+
const script = Uint8Array.from(baseScript);
|
|
461
|
+
patchRange(
|
|
462
|
+
script,
|
|
463
|
+
2,
|
|
464
|
+
34,
|
|
465
|
+
hexToBytes(requireHex32(state.lastBuyer, "last buyer")),
|
|
466
|
+
);
|
|
467
|
+
expectPushLen(script, 34, 8, "endTimeMs");
|
|
468
|
+
patchRange(script, 35, 43, writeI64LE(BigInt(state.endTimeMs)));
|
|
469
|
+
expectPushLen(script, 43, 8, "ticketCount");
|
|
470
|
+
patchRange(script, 44, 52, writeI64LE(BigInt(state.ticketCount)));
|
|
471
|
+
return script;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export function readKaspaFomoRoundState(script) {
|
|
475
|
+
const bytes = Uint8Array.from(script);
|
|
476
|
+
expectPushLen(bytes, 1, 32, "lastBuyer");
|
|
477
|
+
expectPushLen(bytes, 34, 8, "endTimeMs");
|
|
478
|
+
expectPushLen(bytes, 43, 8, "ticketCount");
|
|
479
|
+
return {
|
|
480
|
+
lastBuyer: bytesToHex(bytes.slice(2, 34)),
|
|
481
|
+
endTimeMs: readI64LE(bytes.slice(35, 43)),
|
|
482
|
+
ticketCount: readI64LE(bytes.slice(44, 52)),
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
export function buildKcc20WrapperScriptForState(baseScript, state) {
|
|
487
|
+
const script = Uint8Array.from(baseScript);
|
|
488
|
+
patchRange(script, 2, 34, state.canonicalTokenId);
|
|
489
|
+
if (script[34] !== 1) {
|
|
490
|
+
throw new Error(
|
|
491
|
+
`unsupported KCC20Wrapper enabled push length ${script[34]}; expected 1`,
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
script[35] = state.enabled ? 1 : 0;
|
|
495
|
+
expectPushLen(script, 36, 8, "priceScale");
|
|
496
|
+
patchRange(
|
|
497
|
+
script,
|
|
498
|
+
37,
|
|
499
|
+
45,
|
|
500
|
+
writeI64LE(
|
|
501
|
+
requireSupportedKcc20DisplayScale(
|
|
502
|
+
state.priceScale ?? DEFAULT_KCC20_PRICE_SCALE,
|
|
503
|
+
"KCC20Wrapper priceScale",
|
|
504
|
+
),
|
|
505
|
+
),
|
|
506
|
+
);
|
|
507
|
+
return script;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function kcc20DecimalsFromDisplayScale(value) {
|
|
511
|
+
const scale = BigInt(value);
|
|
512
|
+
for (let decimals = 0; decimals <= 8; decimals += 1) {
|
|
513
|
+
if (10n ** BigInt(decimals) === scale) return decimals;
|
|
514
|
+
}
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function kcc20DisplayScaleForDecimals(decimals) {
|
|
519
|
+
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 8) {
|
|
520
|
+
throw new Error(`unsupported KCC20 decimals: ${decimals}`);
|
|
521
|
+
}
|
|
522
|
+
return 10n ** BigInt(decimals);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function requireSupportedKcc20DisplayScale(value, label) {
|
|
526
|
+
const decimals = kcc20DecimalsFromDisplayScale(value);
|
|
527
|
+
if (decimals === null) {
|
|
528
|
+
throw new Error(
|
|
529
|
+
`${label} must be an exact power-of-ten display scale for decimals 0-8`,
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
return kcc20DisplayScaleForDecimals(decimals);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
export function orderbookModeName(mode) {
|
|
536
|
+
if (Number(mode) === 0) return "holder";
|
|
537
|
+
if (Number(mode) === 1) return "root";
|
|
538
|
+
if (Number(mode) === 2) return "ask";
|
|
539
|
+
if (Number(mode) === 3) return "bid";
|
|
540
|
+
return "unknown";
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
export function stateToReceiptFields(state) {
|
|
544
|
+
const amount = BigInt(state.amount).toString();
|
|
545
|
+
const owner = state.ownerIdentifier || state.owner;
|
|
546
|
+
const ownerScheme = Number(state.ownerScheme ?? state.identifierType ?? 0);
|
|
547
|
+
return {
|
|
548
|
+
owner: bytesToHex(owner),
|
|
549
|
+
ownerScheme,
|
|
550
|
+
ownerSchemeName: identifierTypeName(ownerScheme),
|
|
551
|
+
borrowScheme: Number(state.borrowScheme ?? 0),
|
|
552
|
+
borrowGuard: bytesToHex(state.borrowGuard || hexToBytes(ZERO_HASH)),
|
|
553
|
+
extensionCommitment: bytesToHex(state.extensionCommitment),
|
|
554
|
+
tokenAmount: amount,
|
|
555
|
+
stateAmount: amount,
|
|
556
|
+
balance: amount,
|
|
557
|
+
amount,
|
|
558
|
+
isMintAuthority: amount === "0",
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
export function stateToV3ReceiptFields(state) {
|
|
563
|
+
const owner = bytesToHex(state.ownerIdentifier);
|
|
564
|
+
const amount = BigInt(state.amount).toString();
|
|
565
|
+
const unitPrice = BigInt(state.unitPriceSompi).toString();
|
|
566
|
+
const priceScale = BigInt(
|
|
567
|
+
state.priceScale ?? DEFAULT_KCC20_PRICE_SCALE,
|
|
568
|
+
).toString();
|
|
569
|
+
const mode = Number(state.mode);
|
|
570
|
+
const ownerScheme = Number(state.ownerScheme ?? state.identifierType ?? 0);
|
|
571
|
+
const feeRecipient = KCC20_ORDERBOOK_PROTOCOL_FEE_RECIPIENT;
|
|
572
|
+
const fields = {
|
|
573
|
+
ownerIdentifier: owner,
|
|
574
|
+
stateOwner: owner,
|
|
575
|
+
ownerScheme,
|
|
576
|
+
ownerSchemeName: identifierTypeName(ownerScheme),
|
|
577
|
+
tokenAmount: amount,
|
|
578
|
+
stateAmount: amount,
|
|
579
|
+
amount,
|
|
580
|
+
mode,
|
|
581
|
+
stateMode: mode,
|
|
582
|
+
modeName: orderbookModeName(mode),
|
|
583
|
+
unitPriceSompi: unitPrice,
|
|
584
|
+
marketUnitPriceSompi: unitPrice,
|
|
585
|
+
priceScale,
|
|
586
|
+
tokenDisplayScale: priceScale,
|
|
587
|
+
minGrossFillSompi: DEFAULT_KCC20_MIN_GROSS_FILL_SOMPI.toString(),
|
|
588
|
+
minProtocolFeeSompi: DEFAULT_KCC20_MIN_PROTOCOL_FEE_SOMPI.toString(),
|
|
589
|
+
feeRecipient,
|
|
590
|
+
protocolFeeRecipient: feeRecipient,
|
|
591
|
+
feeBps: Number(DEFAULT_KCC20_FEE_BPS),
|
|
592
|
+
protocolFeeBps: Number(DEFAULT_KCC20_FEE_BPS),
|
|
593
|
+
feeTicketId: state.feeTicketId ? bytesToHex(state.feeTicketId) : ZERO_HASH,
|
|
594
|
+
};
|
|
595
|
+
if (state.canonicalTokenId) {
|
|
596
|
+
fields.canonicalTokenId = bytesToHex(state.canonicalTokenId);
|
|
597
|
+
fields.tokenId = fields.canonicalTokenId;
|
|
598
|
+
}
|
|
599
|
+
return fields;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export function receiptToKcc20OrderbookState(receipt, fallbackOwnerHex) {
|
|
603
|
+
const state = {
|
|
604
|
+
ownerIdentifier: hexToBytes(
|
|
605
|
+
requireHex32(
|
|
606
|
+
receipt.stateOwner || receipt.ownerIdentifier || fallbackOwnerHex,
|
|
607
|
+
"state owner",
|
|
608
|
+
),
|
|
609
|
+
),
|
|
610
|
+
ownerScheme: Number(
|
|
611
|
+
receipt.ownerScheme ??
|
|
612
|
+
receipt.stateOwnerType ??
|
|
613
|
+
receipt.identifierType ??
|
|
614
|
+
0,
|
|
615
|
+
),
|
|
616
|
+
amount: BigInt(
|
|
617
|
+
receipt.stateAmount || receipt.tokenAmount || receipt.amount || "0",
|
|
618
|
+
),
|
|
619
|
+
mode: Number(receipt.stateMode ?? receipt.mode ?? 0),
|
|
620
|
+
unitPriceSompi: BigInt(
|
|
621
|
+
receipt.marketUnitPriceSompi || receipt.unitPriceSompi || "0",
|
|
622
|
+
),
|
|
623
|
+
priceScale: BigInt(
|
|
624
|
+
receipt.tokenDisplayScale ||
|
|
625
|
+
receipt.priceScale ||
|
|
626
|
+
DEFAULT_KCC20_PRICE_SCALE,
|
|
627
|
+
),
|
|
628
|
+
feeRecipient: hexToBytes(KCC20_ORDERBOOK_PROTOCOL_FEE_RECIPIENT),
|
|
629
|
+
feeBps: Number(DEFAULT_KCC20_FEE_BPS),
|
|
630
|
+
feeTicketId: hexToBytes(
|
|
631
|
+
requireHex32(receipt.feeTicketId || ZERO_HASH, "fee ticket id"),
|
|
632
|
+
),
|
|
633
|
+
};
|
|
634
|
+
if (receipt.canonicalTokenId || receipt.tokenId) {
|
|
635
|
+
state.canonicalTokenId = hexToBytes(
|
|
636
|
+
requireHex32(
|
|
637
|
+
receipt.canonicalTokenId || receipt.tokenId,
|
|
638
|
+
"canonical token id",
|
|
639
|
+
),
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
return state;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
export function buildKcc20V3IssueSigScript(
|
|
646
|
+
kw,
|
|
647
|
+
{ signature, toOwner, tokenAmount, tokenOutputIndex, rootOutputIndex },
|
|
648
|
+
) {
|
|
649
|
+
const builder = new kw.ScriptBuilder();
|
|
650
|
+
builder.addData(signature);
|
|
651
|
+
builder.addData(toOwner);
|
|
652
|
+
builder.addI64(BigInt(tokenAmount));
|
|
653
|
+
builder.addI64(BigInt(tokenOutputIndex));
|
|
654
|
+
builder.addI64(BigInt(rootOutputIndex));
|
|
655
|
+
builder.addI64(0n);
|
|
656
|
+
return builder.drain();
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
export function buildKcc20V3CreateBidSigScript(
|
|
660
|
+
kw,
|
|
661
|
+
{ buyer, bidAmount, unitPriceSompi, bidOutputIndex, rootOutputIndex },
|
|
662
|
+
) {
|
|
663
|
+
const builder = new kw.ScriptBuilder();
|
|
664
|
+
builder.addData(buyer);
|
|
665
|
+
builder.addI64(BigInt(bidAmount));
|
|
666
|
+
builder.addI64(BigInt(unitPriceSompi));
|
|
667
|
+
builder.addI64(BigInt(bidOutputIndex));
|
|
668
|
+
builder.addI64(BigInt(rootOutputIndex));
|
|
669
|
+
builder.addData(WRAPPED_ACTION_TAGS.createBidFromRoot);
|
|
670
|
+
return builder.drain();
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
export function buildKcc20V3CreateAskSigScript(
|
|
674
|
+
kw,
|
|
675
|
+
{ signature, askAmount, unitPriceSompi, askOutputIndex, changeOutputIndex },
|
|
676
|
+
) {
|
|
677
|
+
const builder = new kw.ScriptBuilder();
|
|
678
|
+
builder.addData(signature);
|
|
679
|
+
builder.addI64(BigInt(askAmount));
|
|
680
|
+
builder.addI64(BigInt(unitPriceSompi));
|
|
681
|
+
builder.addI64(BigInt(askOutputIndex));
|
|
682
|
+
builder.addI64(BigInt(changeOutputIndex));
|
|
683
|
+
builder.addData(WRAPPED_ACTION_TAGS.createAskByOwnerSig);
|
|
684
|
+
return builder.drain();
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
export function buildKcc20V3FillAskSigScript(
|
|
688
|
+
kw,
|
|
689
|
+
{
|
|
690
|
+
buyerOwner,
|
|
691
|
+
fillAmount,
|
|
692
|
+
buyerTokenOutputIndex,
|
|
693
|
+
askOutputIndex,
|
|
694
|
+
sellerOutputIndex,
|
|
695
|
+
},
|
|
696
|
+
) {
|
|
697
|
+
const builder = new kw.ScriptBuilder();
|
|
698
|
+
builder.addData(buyerOwner);
|
|
699
|
+
builder.addI64(BigInt(fillAmount));
|
|
700
|
+
builder.addI64(BigInt(buyerTokenOutputIndex));
|
|
701
|
+
builder.addI64(BigInt(askOutputIndex));
|
|
702
|
+
builder.addI64(BigInt(sellerOutputIndex));
|
|
703
|
+
builder.addData(WRAPPED_ACTION_TAGS.fillAskPartial);
|
|
704
|
+
return builder.drain();
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
export function buildKcc20OrderbookFillAskSigScript(
|
|
708
|
+
kw,
|
|
709
|
+
{
|
|
710
|
+
buyerOwner,
|
|
711
|
+
fillAmount,
|
|
712
|
+
buyerTokenOutputIndex,
|
|
713
|
+
askOutputIndex,
|
|
714
|
+
sellerOutputIndex,
|
|
715
|
+
ticketInputIndex = -1,
|
|
716
|
+
},
|
|
717
|
+
) {
|
|
718
|
+
const builder = new kw.ScriptBuilder();
|
|
719
|
+
builder.addData(buyerOwner);
|
|
720
|
+
builder.addI64(BigInt(fillAmount));
|
|
721
|
+
builder.addI64(BigInt(buyerTokenOutputIndex));
|
|
722
|
+
builder.addI64(BigInt(askOutputIndex));
|
|
723
|
+
builder.addI64(BigInt(sellerOutputIndex));
|
|
724
|
+
builder.addI64(BigInt(ticketInputIndex));
|
|
725
|
+
builder.addData(WRAPPED_ACTION_TAGS.fillAskPartial);
|
|
726
|
+
return builder.drain();
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
export function buildKcc20V3FillBidSigScript(
|
|
730
|
+
kw,
|
|
731
|
+
{
|
|
732
|
+
sellerTokenInputIndex,
|
|
733
|
+
fillAmount,
|
|
734
|
+
buyerTokenOutputIndex,
|
|
735
|
+
bidOutputIndex,
|
|
736
|
+
sellerOutputIndex,
|
|
737
|
+
seller,
|
|
738
|
+
},
|
|
739
|
+
) {
|
|
740
|
+
const builder = new kw.ScriptBuilder();
|
|
741
|
+
builder.addI64(BigInt(sellerTokenInputIndex));
|
|
742
|
+
builder.addI64(BigInt(fillAmount));
|
|
743
|
+
builder.addI64(BigInt(buyerTokenOutputIndex));
|
|
744
|
+
builder.addI64(BigInt(bidOutputIndex));
|
|
745
|
+
builder.addI64(BigInt(sellerOutputIndex));
|
|
746
|
+
builder.addData(seller);
|
|
747
|
+
builder.addData(WRAPPED_ACTION_TAGS.fillBidPartial);
|
|
748
|
+
return builder.drain();
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
export function buildKcc20OrderbookFillBidSigScript(
|
|
752
|
+
kw,
|
|
753
|
+
{
|
|
754
|
+
sellerTokenInputIndex,
|
|
755
|
+
fillAmount,
|
|
756
|
+
buyerTokenOutputIndex,
|
|
757
|
+
bidOutputIndex,
|
|
758
|
+
sellerOutputIndex,
|
|
759
|
+
seller,
|
|
760
|
+
ticketInputIndex = -1,
|
|
761
|
+
},
|
|
762
|
+
) {
|
|
763
|
+
const builder = new kw.ScriptBuilder();
|
|
764
|
+
builder.addI64(BigInt(sellerTokenInputIndex));
|
|
765
|
+
builder.addI64(BigInt(fillAmount));
|
|
766
|
+
builder.addI64(BigInt(buyerTokenOutputIndex));
|
|
767
|
+
builder.addI64(BigInt(bidOutputIndex));
|
|
768
|
+
builder.addI64(BigInt(sellerOutputIndex));
|
|
769
|
+
builder.addData(seller);
|
|
770
|
+
builder.addI64(BigInt(ticketInputIndex));
|
|
771
|
+
builder.addData(WRAPPED_ACTION_TAGS.fillBidPartial);
|
|
772
|
+
return builder.drain();
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
export function buildKcc20V3SellIntoBidSigScript(
|
|
776
|
+
kw,
|
|
777
|
+
{
|
|
778
|
+
signature,
|
|
779
|
+
buyerOwner,
|
|
780
|
+
fillAmount,
|
|
781
|
+
buyerTokenOutputIndex,
|
|
782
|
+
sellerChangeOutputIndex,
|
|
783
|
+
sellerRefundOutputIndex = -1,
|
|
784
|
+
sellerOutputsEndIndex = -1,
|
|
785
|
+
takesRefundOutput = false,
|
|
786
|
+
},
|
|
787
|
+
) {
|
|
788
|
+
const builder = new kw.ScriptBuilder();
|
|
789
|
+
builder.addData(signature);
|
|
790
|
+
builder.addData(buyerOwner);
|
|
791
|
+
builder.addI64(BigInt(fillAmount));
|
|
792
|
+
builder.addI64(BigInt(buyerTokenOutputIndex));
|
|
793
|
+
builder.addI64(BigInt(sellerChangeOutputIndex));
|
|
794
|
+
if (takesRefundOutput) {
|
|
795
|
+
builder.addI64(BigInt(sellerRefundOutputIndex));
|
|
796
|
+
builder.addI64(BigInt(sellerOutputsEndIndex));
|
|
797
|
+
}
|
|
798
|
+
builder.addData(WRAPPED_ACTION_TAGS.sellIntoBidByOwnerSig);
|
|
799
|
+
return builder.drain();
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
export function buildKcc20OrderbookCrossAskSigScript(
|
|
803
|
+
kw,
|
|
804
|
+
{
|
|
805
|
+
buyerOwner,
|
|
806
|
+
bidInputIndex,
|
|
807
|
+
fillAmount,
|
|
808
|
+
clearingUnitPriceSompi,
|
|
809
|
+
buyerTokenOutputIndex,
|
|
810
|
+
askOutputIndex,
|
|
811
|
+
bidOutputIndex,
|
|
812
|
+
sellerOutputIndex,
|
|
813
|
+
feeOutputIndex,
|
|
814
|
+
refundOutputIndex,
|
|
815
|
+
ticketInputIndex = -1,
|
|
816
|
+
},
|
|
817
|
+
) {
|
|
818
|
+
const builder = new kw.ScriptBuilder();
|
|
819
|
+
builder.addData(buyerOwner);
|
|
820
|
+
builder.addI64(BigInt(bidInputIndex));
|
|
821
|
+
builder.addI64(BigInt(fillAmount));
|
|
822
|
+
builder.addI64(BigInt(clearingUnitPriceSompi));
|
|
823
|
+
builder.addI64(BigInt(buyerTokenOutputIndex));
|
|
824
|
+
builder.addI64(BigInt(askOutputIndex));
|
|
825
|
+
builder.addI64(BigInt(bidOutputIndex));
|
|
826
|
+
builder.addI64(BigInt(sellerOutputIndex));
|
|
827
|
+
builder.addI64(BigInt(feeOutputIndex));
|
|
828
|
+
builder.addI64(BigInt(refundOutputIndex));
|
|
829
|
+
builder.addI64(BigInt(ticketInputIndex));
|
|
830
|
+
builder.addData(WRAPPED_ACTION_TAGS.crossAskSide);
|
|
831
|
+
return builder.drain();
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
export function buildKcc20OrderbookCrossAskLegacySigScript(
|
|
835
|
+
kw,
|
|
836
|
+
{
|
|
837
|
+
buyerOwner,
|
|
838
|
+
bidInputIndex,
|
|
839
|
+
fillAmount,
|
|
840
|
+
clearingUnitPriceSompi,
|
|
841
|
+
buyerTokenOutputIndex,
|
|
842
|
+
askOutputIndex,
|
|
843
|
+
bidOutputIndex,
|
|
844
|
+
sellerOutputIndex,
|
|
845
|
+
feeOutputIndex,
|
|
846
|
+
refundOutputIndex,
|
|
847
|
+
},
|
|
848
|
+
) {
|
|
849
|
+
const builder = new kw.ScriptBuilder();
|
|
850
|
+
builder.addData(buyerOwner);
|
|
851
|
+
builder.addI64(BigInt(bidInputIndex));
|
|
852
|
+
builder.addI64(BigInt(fillAmount));
|
|
853
|
+
builder.addI64(BigInt(clearingUnitPriceSompi));
|
|
854
|
+
builder.addI64(BigInt(buyerTokenOutputIndex));
|
|
855
|
+
builder.addI64(BigInt(askOutputIndex));
|
|
856
|
+
builder.addI64(BigInt(bidOutputIndex));
|
|
857
|
+
builder.addI64(BigInt(sellerOutputIndex));
|
|
858
|
+
builder.addI64(BigInt(feeOutputIndex));
|
|
859
|
+
builder.addI64(BigInt(refundOutputIndex));
|
|
860
|
+
builder.addData(WRAPPED_ACTION_TAGS.crossAskSide);
|
|
861
|
+
return builder.drain();
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
export function buildKcc20OrderbookCrossBidSigScript(
|
|
865
|
+
kw,
|
|
866
|
+
{
|
|
867
|
+
askInputIndex,
|
|
868
|
+
fillAmount,
|
|
869
|
+
clearingUnitPriceSompi,
|
|
870
|
+
buyerTokenOutputIndex,
|
|
871
|
+
askOutputIndex,
|
|
872
|
+
bidOutputIndex,
|
|
873
|
+
sellerOutputIndex,
|
|
874
|
+
feeOutputIndex,
|
|
875
|
+
refundOutputIndex,
|
|
876
|
+
seller,
|
|
877
|
+
ticketInputIndex = -1,
|
|
878
|
+
},
|
|
879
|
+
) {
|
|
880
|
+
const builder = new kw.ScriptBuilder();
|
|
881
|
+
builder.addI64(BigInt(askInputIndex));
|
|
882
|
+
builder.addI64(BigInt(fillAmount));
|
|
883
|
+
builder.addI64(BigInt(clearingUnitPriceSompi));
|
|
884
|
+
builder.addI64(BigInt(buyerTokenOutputIndex));
|
|
885
|
+
builder.addI64(BigInt(askOutputIndex));
|
|
886
|
+
builder.addI64(BigInt(bidOutputIndex));
|
|
887
|
+
builder.addI64(BigInt(sellerOutputIndex));
|
|
888
|
+
builder.addI64(BigInt(feeOutputIndex));
|
|
889
|
+
builder.addI64(BigInt(refundOutputIndex));
|
|
890
|
+
builder.addData(seller);
|
|
891
|
+
builder.addI64(BigInt(ticketInputIndex));
|
|
892
|
+
builder.addData(WRAPPED_ACTION_TAGS.crossBidSide);
|
|
893
|
+
return builder.drain();
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
export function buildKcc20OrderbookCrossBidLegacySigScript(
|
|
897
|
+
kw,
|
|
898
|
+
{
|
|
899
|
+
askInputIndex,
|
|
900
|
+
fillAmount,
|
|
901
|
+
clearingUnitPriceSompi,
|
|
902
|
+
buyerTokenOutputIndex,
|
|
903
|
+
askOutputIndex,
|
|
904
|
+
bidOutputIndex,
|
|
905
|
+
sellerOutputIndex,
|
|
906
|
+
feeOutputIndex,
|
|
907
|
+
refundOutputIndex,
|
|
908
|
+
seller,
|
|
909
|
+
},
|
|
910
|
+
) {
|
|
911
|
+
const builder = new kw.ScriptBuilder();
|
|
912
|
+
builder.addI64(BigInt(askInputIndex));
|
|
913
|
+
builder.addI64(BigInt(fillAmount));
|
|
914
|
+
builder.addI64(BigInt(clearingUnitPriceSompi));
|
|
915
|
+
builder.addI64(BigInt(buyerTokenOutputIndex));
|
|
916
|
+
builder.addI64(BigInt(askOutputIndex));
|
|
917
|
+
builder.addI64(BigInt(bidOutputIndex));
|
|
918
|
+
builder.addI64(BigInt(sellerOutputIndex));
|
|
919
|
+
builder.addI64(BigInt(feeOutputIndex));
|
|
920
|
+
builder.addI64(BigInt(refundOutputIndex));
|
|
921
|
+
builder.addData(seller);
|
|
922
|
+
builder.addData(WRAPPED_ACTION_TAGS.crossBidSide);
|
|
923
|
+
return builder.drain();
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
export function buildKcc20OrderbookCancelAskSigScript(
|
|
927
|
+
kw,
|
|
928
|
+
{ signature, holderOutputIndex },
|
|
929
|
+
) {
|
|
930
|
+
const builder = new kw.ScriptBuilder();
|
|
931
|
+
builder.addData(signature);
|
|
932
|
+
builder.addI64(BigInt(holderOutputIndex));
|
|
933
|
+
builder.addData(WRAPPED_ACTION_TAGS.cancelAskByOwnerSig);
|
|
934
|
+
return builder.drain();
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
export function buildKcc20OrderbookCancelBidSigScript(
|
|
938
|
+
kw,
|
|
939
|
+
{ signature, refundOutputIndex },
|
|
940
|
+
) {
|
|
941
|
+
const builder = new kw.ScriptBuilder();
|
|
942
|
+
builder.addData(signature);
|
|
943
|
+
builder.addI64(BigInt(refundOutputIndex));
|
|
944
|
+
builder.addData(WRAPPED_ACTION_TAGS.cancelBidByOwnerSig);
|
|
945
|
+
return builder.drain();
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
export function buildKcc20OrderbookMergePrimarySigScript(kw, { signature }) {
|
|
949
|
+
const builder = new kw.ScriptBuilder();
|
|
950
|
+
builder.addData(signature);
|
|
951
|
+
builder.addData(WRAPPED_ACTION_TAGS.mergeByOwnerSig);
|
|
952
|
+
return builder.drain();
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
export function buildKcc20OrderbookMergePeerSigScript(
|
|
956
|
+
kw,
|
|
957
|
+
{ signature, primaryInputIndex, mergedAmount },
|
|
958
|
+
) {
|
|
959
|
+
const builder = new kw.ScriptBuilder();
|
|
960
|
+
builder.addData(signature);
|
|
961
|
+
builder.addI64(BigInt(primaryInputIndex));
|
|
962
|
+
builder.addI64(BigInt(mergedAmount));
|
|
963
|
+
builder.addData(WRAPPED_ACTION_TAGS.mergePeerByOwnerSig);
|
|
964
|
+
return builder.drain();
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
export function buildKcc20OrderbookFillBidFromSellerSweepSigScript(
|
|
968
|
+
kw,
|
|
969
|
+
{
|
|
970
|
+
sellerTokenInputIndex,
|
|
971
|
+
sellerAuthOutputOrdinal,
|
|
972
|
+
fillAmount,
|
|
973
|
+
buyerTokenOutputIndex,
|
|
974
|
+
bidOutputIndex,
|
|
975
|
+
sellerOutputIndex,
|
|
976
|
+
seller,
|
|
977
|
+
ticketInputIndex = -1,
|
|
978
|
+
},
|
|
979
|
+
) {
|
|
980
|
+
const builder = new kw.ScriptBuilder();
|
|
981
|
+
builder.addI64(BigInt(sellerTokenInputIndex));
|
|
982
|
+
builder.addI64(BigInt(sellerAuthOutputOrdinal));
|
|
983
|
+
builder.addI64(BigInt(fillAmount));
|
|
984
|
+
builder.addI64(BigInt(buyerTokenOutputIndex));
|
|
985
|
+
builder.addI64(BigInt(bidOutputIndex));
|
|
986
|
+
builder.addI64(BigInt(sellerOutputIndex));
|
|
987
|
+
builder.addData(seller);
|
|
988
|
+
builder.addI64(BigInt(ticketInputIndex));
|
|
989
|
+
builder.addData(WRAPPED_ACTION_TAGS.fillBidFromSellerSweep);
|
|
990
|
+
return builder.drain();
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
export function buildKcc20OrderbookSellIntoBidsSigScript(
|
|
994
|
+
kw,
|
|
995
|
+
{
|
|
996
|
+
signature,
|
|
997
|
+
legs,
|
|
998
|
+
changeOutputIndex,
|
|
999
|
+
sellerRefundOutputIndex = -1,
|
|
1000
|
+
sellerOutputsEndIndex = -1,
|
|
1001
|
+
takesRefundOutput = false,
|
|
1002
|
+
},
|
|
1003
|
+
) {
|
|
1004
|
+
const builder = new kw.ScriptBuilder();
|
|
1005
|
+
builder.addData(signature);
|
|
1006
|
+
for (let i = 0; i < KCC20_ORDERBOOK_MAX_SWEEP_BID_LEGS; i++) {
|
|
1007
|
+
const leg = legs[i] || {};
|
|
1008
|
+
builder.addData(leg.buyerOwner || hexToBytes(ZERO_HASH));
|
|
1009
|
+
builder.addI64(BigInt(leg.fillAmount || 0n));
|
|
1010
|
+
builder.addI64(BigInt(leg.buyerTokenOutputIndex ?? -1));
|
|
1011
|
+
}
|
|
1012
|
+
builder.addI64(BigInt(changeOutputIndex));
|
|
1013
|
+
if (takesRefundOutput) {
|
|
1014
|
+
builder.addI64(BigInt(sellerRefundOutputIndex));
|
|
1015
|
+
builder.addI64(BigInt(sellerOutputsEndIndex));
|
|
1016
|
+
}
|
|
1017
|
+
builder.addData(WRAPPED_ACTION_TAGS.sellIntoBidsByOwnerSig);
|
|
1018
|
+
return builder.drain();
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
export function buildKcc20OrderbookSellIntoBids10SigScript(
|
|
1022
|
+
kw,
|
|
1023
|
+
{
|
|
1024
|
+
signature,
|
|
1025
|
+
legs,
|
|
1026
|
+
changeOutputIndex,
|
|
1027
|
+
sellerRefundOutputIndex = -1,
|
|
1028
|
+
sellerOutputsEndIndex = -1,
|
|
1029
|
+
takesRefundOutput = false,
|
|
1030
|
+
},
|
|
1031
|
+
) {
|
|
1032
|
+
const builder = new kw.ScriptBuilder();
|
|
1033
|
+
builder.addData(signature);
|
|
1034
|
+
for (let i = 0; i < KCC20_ORDERBOOK_MAX_EXPANDED_SWEEP_BID_LEGS; i++) {
|
|
1035
|
+
const leg = legs[i] || {};
|
|
1036
|
+
builder.addData(leg.buyerOwner || hexToBytes(ZERO_HASH));
|
|
1037
|
+
builder.addI64(BigInt(leg.fillAmount || 0n));
|
|
1038
|
+
builder.addI64(BigInt(leg.buyerTokenOutputIndex ?? -1));
|
|
1039
|
+
}
|
|
1040
|
+
builder.addI64(BigInt(changeOutputIndex));
|
|
1041
|
+
if (takesRefundOutput) {
|
|
1042
|
+
builder.addI64(BigInt(sellerRefundOutputIndex));
|
|
1043
|
+
builder.addI64(BigInt(sellerOutputsEndIndex));
|
|
1044
|
+
}
|
|
1045
|
+
builder.addData(WRAPPED_ACTION_TAGS.sellIntoBids10ByOwnerSig);
|
|
1046
|
+
return builder.drain();
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
export function argByteArray(hex) {
|
|
1050
|
+
const values = hexToBytes(hex);
|
|
1051
|
+
return {
|
|
1052
|
+
kind: "array",
|
|
1053
|
+
data: {
|
|
1054
|
+
type_ref: {
|
|
1055
|
+
base: "byte",
|
|
1056
|
+
array_dims: [{ kind: "fixed", value: values.length }],
|
|
1057
|
+
},
|
|
1058
|
+
values: Array.from(values, (b) => ({ kind: "byte", data: b })),
|
|
1059
|
+
},
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
export function argByte(value) {
|
|
1064
|
+
return { kind: "byte", data: Number(value) };
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
export function argInt(value) {
|
|
1068
|
+
const n = BigInt(value);
|
|
1069
|
+
if (n < 0n || n > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
1070
|
+
throw new Error(
|
|
1071
|
+
`SilverScript int constructor arg is outside JS safe integer range: ${value}`,
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
return { kind: "int", data: Number(n) };
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
export function argBool(value) {
|
|
1078
|
+
return { kind: "bool", data: Boolean(value) };
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
export function p2pkScriptPubKey(kw, pubkeyHex) {
|
|
1082
|
+
return new kw.ScriptPublicKey(0, `20${requireHex32(pubkeyHex, "pubkey")}ac`);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
export function p2shScriptHashHex(kw, script) {
|
|
1086
|
+
const spk = kw.payToScriptHashScript(script);
|
|
1087
|
+
const hex = String(spk.script);
|
|
1088
|
+
if (!/^aa20[0-9a-f]{64}87$/i.test(hex)) {
|
|
1089
|
+
throw new Error(`unexpected P2SH script public key: ${hex}`);
|
|
1090
|
+
}
|
|
1091
|
+
return hex.slice(4, 68).toLowerCase();
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
export function calculateFeeSplit(grossSompi, feeBps = DEFAULT_KCC20_FEE_BPS) {
|
|
1095
|
+
const gross = BigInt(grossSompi);
|
|
1096
|
+
const fee = calculateFeeSompi(gross, feeBps);
|
|
1097
|
+
return { fee, net: gross - fee };
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
export function exactGrossSompi(
|
|
1101
|
+
rawAmount,
|
|
1102
|
+
unitPriceSompi,
|
|
1103
|
+
priceScale = DEFAULT_KCC20_PRICE_SCALE,
|
|
1104
|
+
) {
|
|
1105
|
+
const raw = BigInt(rawAmount);
|
|
1106
|
+
const price = BigInt(unitPriceSompi);
|
|
1107
|
+
const scale = BigInt(priceScale ?? DEFAULT_KCC20_PRICE_SCALE);
|
|
1108
|
+
if (raw < 0n || price < 0n || scale <= 0n)
|
|
1109
|
+
throw new Error("invalid exact gross inputs");
|
|
1110
|
+
const whole = raw / scale;
|
|
1111
|
+
const fraction = raw - whole * scale;
|
|
1112
|
+
const fractionProduct = fraction * price;
|
|
1113
|
+
if (fractionProduct % scale !== 0n) {
|
|
1114
|
+
throw new Error(
|
|
1115
|
+
`gross value is not an exact sompi amount for raw=${raw} unitPriceSompi=${price} priceScale=${scale}`,
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
return whole * price + fractionProduct / scale;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
export function calculateFeeSompi(grossSompi, feeBps = DEFAULT_KCC20_FEE_BPS) {
|
|
1122
|
+
const gross = BigInt(grossSompi);
|
|
1123
|
+
const bps = BigInt(feeBps);
|
|
1124
|
+
if (gross < 0n)
|
|
1125
|
+
throw new Error(`grossSompi must be non-negative: ${grossSompi}`);
|
|
1126
|
+
if (bps < 0n || bps > 10_000n)
|
|
1127
|
+
throw new Error(`feeBps must be 0..10000: ${feeBps}`);
|
|
1128
|
+
const percentageFee = (gross * bps) / 10_000n;
|
|
1129
|
+
return percentageFee < DEFAULT_KCC20_MIN_PROTOCOL_FEE_SOMPI
|
|
1130
|
+
? DEFAULT_KCC20_MIN_PROTOCOL_FEE_SOMPI
|
|
1131
|
+
: percentageFee;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
export function selectFundingEntry(
|
|
1135
|
+
entries,
|
|
1136
|
+
requiredSompi,
|
|
1137
|
+
skippedOutpoints = [],
|
|
1138
|
+
) {
|
|
1139
|
+
const skipped = new Set(skippedOutpoints);
|
|
1140
|
+
const sorted = [...entries].sort((a, b) => {
|
|
1141
|
+
const av = utxoAmountSompi(a);
|
|
1142
|
+
const bv = utxoAmountSompi(b);
|
|
1143
|
+
if (av === bv) return 0;
|
|
1144
|
+
return av < bv ? 1 : -1;
|
|
1145
|
+
});
|
|
1146
|
+
const entry = sorted.find((candidate) => {
|
|
1147
|
+
const outpoint = `${candidate.outpoint?.transactionId}:${candidate.outpoint?.index}`;
|
|
1148
|
+
return (
|
|
1149
|
+
!skipped.has(outpoint) && utxoAmountSompi(candidate) >= requiredSompi
|
|
1150
|
+
);
|
|
1151
|
+
});
|
|
1152
|
+
if (!entry) {
|
|
1153
|
+
throw new Error(`no single funding UTXO can cover ${requiredSompi} sompi`);
|
|
1154
|
+
}
|
|
1155
|
+
return entry;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
export function requiredToccataFeeSompi(kw, network, transaction) {
|
|
1159
|
+
if (
|
|
1160
|
+
typeof kw.calculateTransactionFee !== "function" ||
|
|
1161
|
+
typeof kw.calculateTransactionMass !== "function"
|
|
1162
|
+
) {
|
|
1163
|
+
throw new Error("Kaspa transaction fee calculators are unavailable");
|
|
1164
|
+
}
|
|
1165
|
+
const calculatedFee = BigInt(
|
|
1166
|
+
kw.calculateTransactionFee(network, transaction, 1) || 0n,
|
|
1167
|
+
);
|
|
1168
|
+
const baseMass = BigInt(kw.calculateTransactionMass(network, transaction, 1));
|
|
1169
|
+
const computeBudget = [...transaction.inputs].reduce(
|
|
1170
|
+
(sum, input) => sum + BigInt(input.computeBudget || 0),
|
|
1171
|
+
0n,
|
|
1172
|
+
);
|
|
1173
|
+
const relayFee = (baseMass + computeBudget * 100n) * 100n;
|
|
1174
|
+
return relayFee > calculatedFee ? relayFee : calculatedFee;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
export function utxoAmountSompi(entry) {
|
|
1178
|
+
const amount = entry?.amount ?? entry?.utxoEntry?.amount;
|
|
1179
|
+
if (amount === undefined || amount === null) {
|
|
1180
|
+
throw new Error("UTXO entry is missing amount");
|
|
1181
|
+
}
|
|
1182
|
+
return BigInt(amount);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
export function findOutputIndex(
|
|
1186
|
+
tx,
|
|
1187
|
+
address,
|
|
1188
|
+
networkId,
|
|
1189
|
+
addressFromScriptPublicKey,
|
|
1190
|
+
) {
|
|
1191
|
+
for (let i = 0; i < tx.outputs.length; i++) {
|
|
1192
|
+
const outputAddress = addressFromScriptPublicKey(
|
|
1193
|
+
tx.outputs[i].scriptPublicKey,
|
|
1194
|
+
networkId,
|
|
1195
|
+
)?.toString();
|
|
1196
|
+
if (outputAddress === address) return i;
|
|
1197
|
+
}
|
|
1198
|
+
return -1;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
export function setVersionOneInputMassFields(tx, computeBudget = 30) {
|
|
1202
|
+
const inputs = tx.inputs;
|
|
1203
|
+
for (const input of inputs) {
|
|
1204
|
+
input.sigOpCount = 0;
|
|
1205
|
+
input.computeBudget = computeBudget;
|
|
1206
|
+
}
|
|
1207
|
+
tx.inputs = inputs;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
export function extractLockedOutput(lockReceipt, saleCovenantId, tokenAmount) {
|
|
1211
|
+
const output = lockReceipt.outputs?.find(
|
|
1212
|
+
(candidate) =>
|
|
1213
|
+
candidate.ownerIdentifier === saleCovenantId &&
|
|
1214
|
+
Number(candidate.identifierType) === 4 &&
|
|
1215
|
+
BigInt(candidate.tokenAmount) === BigInt(tokenAmount),
|
|
1216
|
+
);
|
|
1217
|
+
if (!output) {
|
|
1218
|
+
throw new Error(
|
|
1219
|
+
`lock receipt does not contain ${tokenAmount} tokens owned by sale covenant ${saleCovenantId}`,
|
|
1220
|
+
);
|
|
1221
|
+
}
|
|
1222
|
+
if (!lockReceipt.txid) {
|
|
1223
|
+
throw new Error("lock receipt is missing submitted txid");
|
|
1224
|
+
}
|
|
1225
|
+
return {
|
|
1226
|
+
txid: lockReceipt.txid,
|
|
1227
|
+
vout: Number(output.vout),
|
|
1228
|
+
tokenAmount: BigInt(output.tokenAmount),
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
function expectPushLen(script, offset, expected, label) {
|
|
1233
|
+
if (script[offset] !== expected) {
|
|
1234
|
+
throw new Error(
|
|
1235
|
+
`unsupported KCC20 ${label} push length ${script[offset]}; expected ${expected}`,
|
|
1236
|
+
);
|
|
1237
|
+
}
|
|
1238
|
+
}
|