@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,184 @@
|
|
|
1
|
+
import {
|
|
2
|
+
calculateKcc20OrderTotalSompi,
|
|
3
|
+
parseKcc20DisplayAmountToBaseUnits,
|
|
4
|
+
} from "./token-amount.js";
|
|
5
|
+
import {
|
|
6
|
+
KCC20_MIN_PROTOCOL_FEE_SOMPI,
|
|
7
|
+
calculateKcc20ProtocolFeeSompi,
|
|
8
|
+
} from "./trade-fee.js";
|
|
9
|
+
|
|
10
|
+
export const KCC20_LADDER_MAX_ORDERS = 20;
|
|
11
|
+
|
|
12
|
+
export type Kcc20LadderDirection = "increment" | "decrement";
|
|
13
|
+
|
|
14
|
+
export interface Kcc20LadderLimitPlan {
|
|
15
|
+
unitPriceSompi: string[];
|
|
16
|
+
notionalsSompi: bigint[];
|
|
17
|
+
minNotionalSompi: bigint;
|
|
18
|
+
totalNotionalSompi: bigint;
|
|
19
|
+
totalProtocolFeeSompi: bigint;
|
|
20
|
+
totalBuySettlementSompi: bigint;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Builds compounded unit prices for a same-amount resting limit-order ladder.
|
|
25
|
+
*/
|
|
26
|
+
export function kcc20LadderUnitPricesSompi(input: {
|
|
27
|
+
baseUnitPriceSompi: bigint;
|
|
28
|
+
count: number;
|
|
29
|
+
direction: Kcc20LadderDirection;
|
|
30
|
+
percent: number;
|
|
31
|
+
}): bigint[] {
|
|
32
|
+
const count = Math.min(
|
|
33
|
+
KCC20_LADDER_MAX_ORDERS,
|
|
34
|
+
Math.max(1, Math.floor(input.count)),
|
|
35
|
+
);
|
|
36
|
+
if (input.baseUnitPriceSompi <= 0n) return [];
|
|
37
|
+
|
|
38
|
+
const percent = Number.isFinite(input.percent)
|
|
39
|
+
? Math.max(0, input.percent)
|
|
40
|
+
: 0;
|
|
41
|
+
const stepPpm = BigInt(Math.round(percent * 10_000));
|
|
42
|
+
const million = 1_000_000n;
|
|
43
|
+
const sign = input.direction === "increment" ? 1n : -1n;
|
|
44
|
+
const prices: bigint[] = [];
|
|
45
|
+
let current = input.baseUnitPriceSompi;
|
|
46
|
+
|
|
47
|
+
for (let index = 0; index < count; index += 1) {
|
|
48
|
+
if (current <= 0n) break;
|
|
49
|
+
prices.push(current);
|
|
50
|
+
if (index === count - 1 || stepPpm === 0n) continue;
|
|
51
|
+
|
|
52
|
+
const factor = million + sign * stepPpm;
|
|
53
|
+
if (factor <= 0n) break;
|
|
54
|
+
const next = (current * factor + million / 2n) / million;
|
|
55
|
+
current =
|
|
56
|
+
next === current
|
|
57
|
+
? input.direction === "increment"
|
|
58
|
+
? current + 1n
|
|
59
|
+
: current - 1n
|
|
60
|
+
: next;
|
|
61
|
+
}
|
|
62
|
+
return prices;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function parseKcc20LadderPercent(value: string): number | undefined {
|
|
66
|
+
const trimmed = value.trim();
|
|
67
|
+
if (!trimmed) return undefined;
|
|
68
|
+
const parsed = Number(trimmed);
|
|
69
|
+
return Number.isFinite(parsed) && parsed >= 0 && parsed <= 100
|
|
70
|
+
? parsed
|
|
71
|
+
: undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function planKcc20LadderLimitOrders(input: {
|
|
75
|
+
tokenAmount: string;
|
|
76
|
+
baseUnitPriceSompi: string;
|
|
77
|
+
decimals: number;
|
|
78
|
+
count: number;
|
|
79
|
+
direction: Kcc20LadderDirection;
|
|
80
|
+
percent: number;
|
|
81
|
+
protocolFeeBps: number;
|
|
82
|
+
}): Kcc20LadderLimitPlan | undefined {
|
|
83
|
+
let base: bigint;
|
|
84
|
+
try {
|
|
85
|
+
base = BigInt(input.baseUnitPriceSompi.trim());
|
|
86
|
+
} catch {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
if (base <= 0n) return undefined;
|
|
90
|
+
|
|
91
|
+
const prices = kcc20LadderUnitPricesSompi({
|
|
92
|
+
baseUnitPriceSompi: base,
|
|
93
|
+
count: input.count,
|
|
94
|
+
direction: input.direction,
|
|
95
|
+
percent: input.percent,
|
|
96
|
+
});
|
|
97
|
+
const requested = Math.min(
|
|
98
|
+
KCC20_LADDER_MAX_ORDERS,
|
|
99
|
+
Math.max(1, Math.floor(input.count)),
|
|
100
|
+
);
|
|
101
|
+
if (prices.length !== requested) return undefined;
|
|
102
|
+
|
|
103
|
+
const notionalsSompi: bigint[] = [];
|
|
104
|
+
let totalBuySettlementSompi = 0n;
|
|
105
|
+
for (const price of prices) {
|
|
106
|
+
const total = calculateKcc20OrderTotalSompi(
|
|
107
|
+
input.tokenAmount,
|
|
108
|
+
price.toString(),
|
|
109
|
+
input.decimals,
|
|
110
|
+
);
|
|
111
|
+
if (!total) return undefined;
|
|
112
|
+
const notional = BigInt(total.totalSompi);
|
|
113
|
+
notionalsSompi.push(notional);
|
|
114
|
+
totalBuySettlementSompi +=
|
|
115
|
+
notional + calculateKcc20ProtocolFeeSompi(notional, input.protocolFeeBps);
|
|
116
|
+
}
|
|
117
|
+
const totalNotionalSompi = notionalsSompi.reduce(
|
|
118
|
+
(sum, value) => sum + value,
|
|
119
|
+
0n,
|
|
120
|
+
);
|
|
121
|
+
const minNotionalSompi = notionalsSompi.reduce(
|
|
122
|
+
(min, value) => (value < min ? value : min),
|
|
123
|
+
notionalsSompi[0],
|
|
124
|
+
);
|
|
125
|
+
return {
|
|
126
|
+
unitPriceSompi: prices.map((price) => price.toString()),
|
|
127
|
+
notionalsSompi,
|
|
128
|
+
minNotionalSompi,
|
|
129
|
+
totalNotionalSompi,
|
|
130
|
+
totalProtocolFeeSompi: totalBuySettlementSompi - totalNotionalSompi,
|
|
131
|
+
totalBuySettlementSompi,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function kcc20LadderMeetsMinOrderValue(
|
|
136
|
+
plan: Kcc20LadderLimitPlan,
|
|
137
|
+
minSompi = KCC20_MIN_PROTOCOL_FEE_SOMPI,
|
|
138
|
+
): boolean {
|
|
139
|
+
return plan.minNotionalSompi >= minSompi;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function maxAffordableKcc20LadderCount(input: {
|
|
143
|
+
side: "buy" | "sell";
|
|
144
|
+
tokenAmount: string;
|
|
145
|
+
baseUnitPriceSompi: string;
|
|
146
|
+
decimals: number;
|
|
147
|
+
direction: Kcc20LadderDirection;
|
|
148
|
+
percent: number;
|
|
149
|
+
protocolFeeBps: number;
|
|
150
|
+
availableTokenBaseUnits?: bigint;
|
|
151
|
+
availableKasSompi?: bigint;
|
|
152
|
+
}): number {
|
|
153
|
+
if (input.side === "sell") {
|
|
154
|
+
if (input.availableTokenBaseUnits === undefined)
|
|
155
|
+
return KCC20_LADDER_MAX_ORDERS;
|
|
156
|
+
let amount: bigint;
|
|
157
|
+
try {
|
|
158
|
+
amount = BigInt(
|
|
159
|
+
parseKcc20DisplayAmountToBaseUnits(
|
|
160
|
+
input.tokenAmount,
|
|
161
|
+
input.decimals,
|
|
162
|
+
"token amount",
|
|
163
|
+
),
|
|
164
|
+
);
|
|
165
|
+
} catch {
|
|
166
|
+
return KCC20_LADDER_MAX_ORDERS;
|
|
167
|
+
}
|
|
168
|
+
if (amount <= 0n) return KCC20_LADDER_MAX_ORDERS;
|
|
169
|
+
const affordable = input.availableTokenBaseUnits / amount;
|
|
170
|
+
if (affordable < 1n) return 1;
|
|
171
|
+
const asNumber = Number(affordable);
|
|
172
|
+
return Number.isSafeInteger(asNumber)
|
|
173
|
+
? Math.min(KCC20_LADDER_MAX_ORDERS, asNumber)
|
|
174
|
+
: KCC20_LADDER_MAX_ORDERS;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (input.availableKasSompi === undefined) return KCC20_LADDER_MAX_ORDERS;
|
|
178
|
+
for (let count = KCC20_LADDER_MAX_ORDERS; count >= 1; count -= 1) {
|
|
179
|
+
const plan = planKcc20LadderLimitOrders({ ...input, count });
|
|
180
|
+
if (plan && plan.totalBuySettlementSompi <= input.availableKasSompi)
|
|
181
|
+
return count;
|
|
182
|
+
}
|
|
183
|
+
return 1;
|
|
184
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { buildKcc20WalletOperationFromPlan } from "./wallet-operation.js";
|
|
2
|
+
import type { Kcc20IndexedCovenantUtxo } from "./action-source-resolver.js";
|
|
3
|
+
|
|
4
|
+
const HEX_64_RE = /^[a-f0-9]{64}$/;
|
|
5
|
+
|
|
6
|
+
export interface Kcc20MintAvailabilityWalletInfo {
|
|
7
|
+
walletAddress: string;
|
|
8
|
+
kcc20Owner: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface Kcc20BuildMintAvailabilityOperationInput {
|
|
12
|
+
covenantId: string;
|
|
13
|
+
active: boolean;
|
|
14
|
+
activeMinterUtxo: Record<string, unknown>;
|
|
15
|
+
activeMinterUtxos: Record<string, unknown>[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface Kcc20MintAvailabilityOperationOptions {
|
|
19
|
+
network?: string;
|
|
20
|
+
createdAt?: string;
|
|
21
|
+
requestId?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function resolveKcc20MintAvailabilitySources(input: {
|
|
25
|
+
publicMintControlSupported: boolean;
|
|
26
|
+
activeUtxos: readonly Kcc20IndexedCovenantUtxo[];
|
|
27
|
+
owner: string;
|
|
28
|
+
active: boolean;
|
|
29
|
+
}): {
|
|
30
|
+
activeMinterUtxo: Kcc20IndexedCovenantUtxo;
|
|
31
|
+
activeMinterUtxos: Kcc20IndexedCovenantUtxo[];
|
|
32
|
+
} {
|
|
33
|
+
if (!input.publicMintControlSupported) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
"This KCC20 token does not support public mint availability updates",
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
const activeMinterUtxos = input.activeUtxos.filter(
|
|
39
|
+
(utxo) =>
|
|
40
|
+
utxo.state?.["isMintAuthority"] === true &&
|
|
41
|
+
Number(utxo.state?.["mintPolicy"]) === 2,
|
|
42
|
+
);
|
|
43
|
+
const activeMinterUtxo = activeMinterUtxos[0];
|
|
44
|
+
if (!activeMinterUtxo?.state)
|
|
45
|
+
throw new Error("Active public minter UTXO not found");
|
|
46
|
+
|
|
47
|
+
const state = activeMinterUtxo.state;
|
|
48
|
+
const owner = String(
|
|
49
|
+
state["owner"] ?? state["ownerIdentifier"] ?? "",
|
|
50
|
+
).toLowerCase();
|
|
51
|
+
const ownerScheme = Number(state["ownerScheme"] ?? state["identifierType"]);
|
|
52
|
+
if (ownerScheme !== 0 || owner !== input.owner.toLowerCase()) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
"Public mint availability updates require the active minter owner",
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
const currentActive = state["publicMintActive"] === true;
|
|
58
|
+
if (currentActive === input.active) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
input.active
|
|
61
|
+
? "Public mint is already active"
|
|
62
|
+
: "Public mint is already paused",
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return { activeMinterUtxo, activeMinterUtxos };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function buildKcc20MintAvailabilityOperation(
|
|
69
|
+
walletInfo: Kcc20MintAvailabilityWalletInfo,
|
|
70
|
+
input: Kcc20BuildMintAvailabilityOperationInput,
|
|
71
|
+
options: Kcc20MintAvailabilityOperationOptions = {},
|
|
72
|
+
) {
|
|
73
|
+
const covenantId = requireHex64(input.covenantId, "covenantId");
|
|
74
|
+
if (typeof input.active !== "boolean") {
|
|
75
|
+
throw new Error("active must be a boolean");
|
|
76
|
+
}
|
|
77
|
+
if (!input.activeMinterUtxo || typeof input.activeMinterUtxo !== "object") {
|
|
78
|
+
throw new Error("activeMinterUtxo is required");
|
|
79
|
+
}
|
|
80
|
+
if (
|
|
81
|
+
!Array.isArray(input.activeMinterUtxos) ||
|
|
82
|
+
!input.activeMinterUtxos.length
|
|
83
|
+
) {
|
|
84
|
+
throw new Error("activeMinterUtxos must contain at least one source");
|
|
85
|
+
}
|
|
86
|
+
const outpoints = input.activeMinterUtxos.map((utxo) => utxoOutpoint(utxo));
|
|
87
|
+
const selectedOutpoint = utxoOutpoint(input.activeMinterUtxo);
|
|
88
|
+
|
|
89
|
+
return buildKcc20WalletOperationFromPlan(
|
|
90
|
+
walletInfo,
|
|
91
|
+
{
|
|
92
|
+
builderKey: "kcc20.set-public-mint-active",
|
|
93
|
+
operation: "set-mint-availability",
|
|
94
|
+
contract: "KCC20",
|
|
95
|
+
action: "setPublicMintActive",
|
|
96
|
+
description: "Build a public mint availability update request.",
|
|
97
|
+
params: {
|
|
98
|
+
covenantId,
|
|
99
|
+
active: input.active,
|
|
100
|
+
activeMinterUtxo: input.activeMinterUtxo,
|
|
101
|
+
activeMinterUtxos: input.activeMinterUtxos,
|
|
102
|
+
},
|
|
103
|
+
sourceRequirements: [
|
|
104
|
+
{
|
|
105
|
+
type: "kcc20-mint-authority-utxo",
|
|
106
|
+
covenantId,
|
|
107
|
+
outpoint: selectedOutpoint,
|
|
108
|
+
outpoints,
|
|
109
|
+
purpose:
|
|
110
|
+
"preserve remaining supply while updating public mint availability",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
type: "kaspa-funding-utxo",
|
|
114
|
+
ownerAddress: walletInfo.walletAddress,
|
|
115
|
+
purpose: "fund network fee",
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
warnings: [],
|
|
119
|
+
tokenIdentity: {
|
|
120
|
+
canonicalCovenantId: covenantId,
|
|
121
|
+
deployCandidateId: covenantId,
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
options,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function utxoOutpoint(utxo: Record<string, unknown>): string {
|
|
129
|
+
const txidHex = requireHex64(utxo["txidHex"], "minter txid");
|
|
130
|
+
const vout = Number(utxo["vout"]);
|
|
131
|
+
if (!Number.isInteger(vout) || vout < 0) {
|
|
132
|
+
throw new Error("minter vout must be a non-negative integer");
|
|
133
|
+
}
|
|
134
|
+
return `${txidHex}:${vout}`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function requireHex64(value: unknown, field: string): string {
|
|
138
|
+
if (typeof value !== "string") {
|
|
139
|
+
throw new Error(`${field} must be 64 hex characters`);
|
|
140
|
+
}
|
|
141
|
+
const normalized = value.trim().toLowerCase().replace(/^0x/, "");
|
|
142
|
+
if (!HEX_64_RE.test(normalized)) {
|
|
143
|
+
throw new Error(`${field} must be 64 hex characters`);
|
|
144
|
+
}
|
|
145
|
+
return normalized;
|
|
146
|
+
}
|
package/src/models.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { KaspaWasmRuntime } from "./runtime.js";
|
|
2
|
+
|
|
3
|
+
export const KCC20_BUILDER_INPUT_SCHEMA =
|
|
4
|
+
"kcc20-shared-pskt-builder-input/v1" as const;
|
|
5
|
+
export const KCC20_BUILDER_OUTPUT_SCHEMA =
|
|
6
|
+
"kcc20-shared-pskt-builder-output/v1" as const;
|
|
7
|
+
|
|
8
|
+
export type Hex64 = string;
|
|
9
|
+
|
|
10
|
+
export interface TransactionOutpoint {
|
|
11
|
+
txidHex: Hex64;
|
|
12
|
+
vout: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface CovenantUtxo extends TransactionOutpoint {
|
|
16
|
+
address: string;
|
|
17
|
+
amountSompi: string;
|
|
18
|
+
/** Decoded state required by the selected operation. */
|
|
19
|
+
state: Record<string, unknown>;
|
|
20
|
+
/** Optional script/artifact data supplied by the source resolver. */
|
|
21
|
+
scriptHex?: string;
|
|
22
|
+
artifactKey?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface FundingUtxo extends TransactionOutpoint {
|
|
26
|
+
address: string;
|
|
27
|
+
amountSompi: string;
|
|
28
|
+
scriptPublicKeyHex?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface BuildSources {
|
|
32
|
+
covenantUtxos?: CovenantUtxo[];
|
|
33
|
+
walletUtxos: FundingUtxo[];
|
|
34
|
+
optionalFeeTicketUtxos?: CovenantUtxo[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ArtifactDescriptor {
|
|
38
|
+
key: string;
|
|
39
|
+
version: string;
|
|
40
|
+
hash: Hex64;
|
|
41
|
+
abi?: unknown;
|
|
42
|
+
script?: unknown;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface BuildContext {
|
|
46
|
+
network: string;
|
|
47
|
+
walletAddress: string;
|
|
48
|
+
ownerIdentifier: string;
|
|
49
|
+
protocolVersion: string;
|
|
50
|
+
artifacts: Record<string, ArtifactDescriptor>;
|
|
51
|
+
/** Values normally controlled by backend configuration. */
|
|
52
|
+
protocolFeeBps?: string;
|
|
53
|
+
priorityFeeSompi?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface Kcc20PsktBuildRequest {
|
|
57
|
+
schema: typeof KCC20_BUILDER_INPUT_SCHEMA;
|
|
58
|
+
builderKey: string;
|
|
59
|
+
operation: string;
|
|
60
|
+
action: string;
|
|
61
|
+
params: Record<string, unknown>;
|
|
62
|
+
context: BuildContext;
|
|
63
|
+
sources: BuildSources;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface SignInput {
|
|
67
|
+
index: number;
|
|
68
|
+
sighashType?: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface CovenantSigningScript {
|
|
72
|
+
inputIndex: number;
|
|
73
|
+
scriptHex: string;
|
|
74
|
+
signType?: string;
|
|
75
|
+
signatureScriptHex?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface Kcc20PsktBuildResult {
|
|
79
|
+
schema: typeof KCC20_BUILDER_OUTPUT_SCHEMA;
|
|
80
|
+
psktTransactionJson: string;
|
|
81
|
+
signInputs: SignInput[];
|
|
82
|
+
scripts?: CovenantSigningScript[];
|
|
83
|
+
sourceOutpoints: string[];
|
|
84
|
+
artifactHashes: Record<string, Hex64>;
|
|
85
|
+
operationDigest: Hex64;
|
|
86
|
+
metadata?: Record<string, unknown>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface Kcc20PsktBuilderDependencies {
|
|
90
|
+
wasm: KaspaWasmRuntime;
|
|
91
|
+
artifacts?: Record<string, unknown>;
|
|
92
|
+
artifactProvider?: (key: string) => Promise<unknown>;
|
|
93
|
+
config?: Record<string, unknown>;
|
|
94
|
+
/**
|
|
95
|
+
* Host-owned source transport. When supplied, the builder does not create,
|
|
96
|
+
* connect, or disconnect an RPC client; the host may therefore back this
|
|
97
|
+
* provider with one long-lived browser or server connection.
|
|
98
|
+
*/
|
|
99
|
+
sourceProvider?: {
|
|
100
|
+
getUtxosByAddresses(args: { addresses: string[] }): Promise<unknown>;
|
|
101
|
+
};
|
|
102
|
+
rpcClientFactory?: (config: unknown) => any;
|
|
103
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export const KCC20_BUILDER_KEYS = [
|
|
2
|
+
"kcc20.deploy-token",
|
|
3
|
+
"kcc20.mint",
|
|
4
|
+
"kcc20.set-public-mint-active",
|
|
5
|
+
"kcc20.transfer",
|
|
6
|
+
"kcc20.consolidate-holders",
|
|
7
|
+
"kcc20.reveal-token",
|
|
8
|
+
"kcc20wrapper.deploy-market",
|
|
9
|
+
"kcc20wrapper.wrap",
|
|
10
|
+
"kcc20wrapper.unwrap",
|
|
11
|
+
"kcc20orderbook.create-bid",
|
|
12
|
+
"kcc20orderbook.create-ask",
|
|
13
|
+
"kcc20orderbook.fill-ask",
|
|
14
|
+
"kcc20orderbook.fill-bid",
|
|
15
|
+
"kcc20orderbook.sweep-asks",
|
|
16
|
+
"kcc20orderbook.sweep-bids",
|
|
17
|
+
"kcc20orderbook.consolidate-holders",
|
|
18
|
+
"kcc20orderbook.cancel-ask",
|
|
19
|
+
"kcc20orderbook.cancel-bid",
|
|
20
|
+
"fee-ticket.deploy-root",
|
|
21
|
+
"fee-ticket.update-denomination",
|
|
22
|
+
"fee-ticket.create-from-utility-burn",
|
|
23
|
+
"fee-ticket.burn",
|
|
24
|
+
"fee-ticket.transfer",
|
|
25
|
+
] as const;
|
|
26
|
+
|
|
27
|
+
export type Kcc20BuilderKey = (typeof KCC20_BUILDER_KEYS)[number];
|
|
28
|
+
|
|
29
|
+
export function isKcc20BuilderKey(value: string): value is Kcc20BuilderKey {
|
|
30
|
+
return (KCC20_BUILDER_KEYS as readonly string[]).includes(value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const BACKEND_ONLY_BUILDER_KEYS = [
|
|
34
|
+
"kcc20orderbook.matcher-settle-crossed",
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
export type BackendOnlyBuilderKey = (typeof BACKEND_ONLY_BUILDER_KEYS)[number];
|
|
38
|
+
|
|
39
|
+
export function isBackendOnlyBuilderKey(
|
|
40
|
+
value: unknown,
|
|
41
|
+
): value is BackendOnlyBuilderKey {
|
|
42
|
+
return (
|
|
43
|
+
typeof value === "string" &&
|
|
44
|
+
(BACKEND_ONLY_BUILDER_KEYS as readonly string[]).includes(value)
|
|
45
|
+
);
|
|
46
|
+
}
|