@hardkas/tx-builder 0.7.1-alpha → 0.7.4-alpha

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.
Files changed (2) hide show
  1. package/dist/index.js +105 -24
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -23,7 +23,9 @@ function estimateTransactionMass(input) {
23
23
  outputs += KASPA_MASS_CONSTANTS.OUTPUT_P2PK;
24
24
  } else {
25
25
  outputs += KASPA_MASS_CONSTANTS.SCRIPT_FALLBACK;
26
- warnings.push(`P2SH/Other script detected for address: ${out.address}. Mass is estimated using placeholder script-size assumptions.`);
26
+ warnings.push(
27
+ `P2SH/Other script detected for address: ${out.address}. Mass is estimated using placeholder script-size assumptions.`
28
+ );
27
29
  }
28
30
  }
29
31
  if (input.hasChange) {
@@ -69,16 +71,31 @@ function verifyTxPlanSemantics(plan, context = {}) {
69
71
  };
70
72
  const ePlan = plan;
71
73
  if (ePlan.mode === "simulated" && ePlan.networkId !== "simnet") {
72
- addIssue("ENV_CONSISTENCY_FAILURE", "error", `Environment mismatch: simulated plan must target 'simnet', but targets '${ePlan.networkId}'`);
74
+ addIssue(
75
+ "ENV_CONSISTENCY_FAILURE",
76
+ "error",
77
+ `Environment mismatch: simulated plan must target 'simnet', but targets '${ePlan.networkId}'`
78
+ );
73
79
  }
74
80
  if (!plan.inputs.every((i) => i.address.includes(":"))) {
75
- addIssue("INVALID_ADDRESS_FORMAT", "error", "One or more input addresses are missing prefix (e.g. kaspa:)");
81
+ addIssue(
82
+ "INVALID_ADDRESS_FORMAT",
83
+ "error",
84
+ "One or more input addresses are missing prefix (e.g. kaspa:)"
85
+ );
76
86
  }
77
87
  if (!plan.outputs.every((o) => o.address.includes(":"))) {
78
- addIssue("INVALID_ADDRESS_FORMAT", "error", "One or more output addresses are missing prefix (e.g. kaspa:)");
88
+ addIssue(
89
+ "INVALID_ADDRESS_FORMAT",
90
+ "error",
91
+ "One or more output addresses are missing prefix (e.g. kaspa:)"
92
+ );
79
93
  }
80
94
  const inputTotalSompi = plan.inputs.reduce((sum, i) => sum + BigInt(i.amountSompi), 0n);
81
- const outputTotalSompi = plan.outputs.reduce((sum, o) => sum + BigInt(o.amountSompi), 0n);
95
+ const outputTotalSompi = plan.outputs.reduce(
96
+ (sum, o) => sum + BigInt(o.amountSompi),
97
+ 0n
98
+ );
82
99
  const changeAmountSompi = plan.change ? BigInt(plan.change.amountSompi) : 0n;
83
100
  const planFeeSompi = BigInt(plan.estimatedFeeSompi);
84
101
  const recomputedFeeSompi = inputTotalSompi - outputTotalSompi - changeAmountSompi;
@@ -86,10 +103,18 @@ function verifyTxPlanSemantics(plan, context = {}) {
86
103
  addIssue("ZERO_INPUTS", "critical", "Transaction has zero or negative total inputs.");
87
104
  }
88
105
  if (outputTotalSompi <= 0n) {
89
- addIssue("ZERO_OUTPUTS", "error", "Transaction has zero or negative total outputs (excluding change).");
106
+ addIssue(
107
+ "ZERO_OUTPUTS",
108
+ "error",
109
+ "Transaction has zero or negative total outputs (excluding change)."
110
+ );
90
111
  }
91
112
  if (recomputedFeeSompi < 0n) {
92
- addIssue("NEGATIVE_FEE", "critical", `Negative fee detected: inputs (${inputTotalSompi}) < outputs + change (${outputTotalSompi + changeAmountSompi})`);
113
+ addIssue(
114
+ "NEGATIVE_FEE",
115
+ "critical",
116
+ `Negative fee detected: inputs (${inputTotalSompi}) < outputs + change (${outputTotalSompi + changeAmountSompi})`
117
+ );
93
118
  }
94
119
  const massResult = estimateTransactionMass({
95
120
  inputCount: plan.inputs.length,
@@ -98,27 +123,55 @@ function verifyTxPlanSemantics(plan, context = {}) {
98
123
  });
99
124
  const recomputedMass = massResult.mass;
100
125
  if (recomputedMass !== BigInt(plan.estimatedMass)) {
101
- addIssue("MASS_MISMATCH", "critical", `Mass mismatch: plan says ${plan.estimatedMass}, recomputed ${recomputedMass}`);
126
+ addIssue(
127
+ "MASS_MISMATCH",
128
+ "critical",
129
+ `Mass mismatch: plan says ${plan.estimatedMass}, recomputed ${recomputedMass}`
130
+ );
102
131
  }
103
132
  if (planFeeSompi !== recomputedFeeSompi) {
104
- addIssue("FEE_MISMATCH", "critical", `Fee mismatch: estimatedFeeSompi (${planFeeSompi}) does not match input-output delta (${recomputedFeeSompi})`);
133
+ addIssue(
134
+ "FEE_MISMATCH",
135
+ "critical",
136
+ `Fee mismatch: estimatedFeeSompi (${planFeeSompi}) does not match input-output delta (${recomputedFeeSompi})`
137
+ );
105
138
  }
106
139
  plan.outputs.forEach((o, i) => {
107
140
  if (BigInt(o.amountSompi) <= 0n) {
108
- addIssue("INVALID_OUTPUT_AMOUNT", "error", `Output ${i} has non-positive amount: ${o.amountSompi}`, `outputs[${i}]`);
141
+ addIssue(
142
+ "INVALID_OUTPUT_AMOUNT",
143
+ "error",
144
+ `Output ${i} has non-positive amount: ${o.amountSompi}`,
145
+ `outputs[${i}]`
146
+ );
109
147
  }
110
148
  if (BigInt(o.amountSompi) < 600n) {
111
- addIssue("DUST_OUTPUT", "warning", `Output ${i} might be dust: ${o.amountSompi} sompi`, `outputs[${i}]`);
149
+ addIssue(
150
+ "DUST_OUTPUT",
151
+ "warning",
152
+ `Output ${i} might be dust: ${o.amountSompi} sompi`,
153
+ `outputs[${i}]`
154
+ );
112
155
  }
113
156
  });
114
157
  if (plan.change && BigInt(plan.change.amountSompi) < 600n) {
115
- addIssue("DUST_CHANGE", "warning", `Change output might be dust: ${plan.change.amountSompi} sompi`, "change");
158
+ addIssue(
159
+ "DUST_CHANGE",
160
+ "warning",
161
+ `Change output might be dust: ${plan.change.amountSompi} sompi`,
162
+ "change"
163
+ );
116
164
  }
117
165
  const seenInputs = /* @__PURE__ */ new Set();
118
166
  plan.inputs.forEach((input, i) => {
119
167
  const id = `${input.outpoint.transactionId}:${input.outpoint.index}`;
120
168
  if (seenInputs.has(id)) {
121
- addIssue("DUPLICATE_INPUT", "critical", `Duplicate input detected: ${id}`, `inputs[${i}]`);
169
+ addIssue(
170
+ "DUPLICATE_INPUT",
171
+ "critical",
172
+ `Duplicate input detected: ${id}`,
173
+ `inputs[${i}]`
174
+ );
122
175
  }
123
176
  seenInputs.add(id);
124
177
  });
@@ -128,15 +181,30 @@ function verifyTxPlanSemantics(plan, context = {}) {
128
181
  (u) => u.outpoint.transactionId === input.outpoint.transactionId && u.outpoint.index === input.outpoint.index
129
182
  );
130
183
  if (!match) {
131
- addIssue("UNKNOWN_INPUT", "error", `Input ${i} not found in provided UTXO context`, `inputs[${i}]`);
184
+ addIssue(
185
+ "UNKNOWN_INPUT",
186
+ "error",
187
+ `Input ${i} not found in provided UTXO context`,
188
+ `inputs[${i}]`
189
+ );
132
190
  } else if (BigInt(match.amountSompi) !== BigInt(input.amountSompi)) {
133
- addIssue("INPUT_AMOUNT_MISMATCH", "critical", `Input ${i} amount mismatch: plan says ${input.amountSompi}, context says ${match.amountSompi}`, `inputs[${i}]`);
191
+ addIssue(
192
+ "INPUT_AMOUNT_MISMATCH",
193
+ "critical",
194
+ `Input ${i} amount mismatch: plan says ${input.amountSompi}, context says ${match.amountSompi}`,
195
+ `inputs[${i}]`
196
+ );
134
197
  }
135
198
  });
136
199
  }
137
200
  if (context.expectedChangeAddress && plan.change) {
138
201
  if (plan.change.address !== context.expectedChangeAddress) {
139
- addIssue("CHANGE_ADDRESS_MISMATCH", "error", `Change address mismatch: expected ${context.expectedChangeAddress}, got ${plan.change.address}`, "change.address");
202
+ addIssue(
203
+ "CHANGE_ADDRESS_MISMATCH",
204
+ "error",
205
+ `Change address mismatch: expected ${context.expectedChangeAddress}, got ${plan.change.address}`,
206
+ "change.address"
207
+ );
140
208
  }
141
209
  }
142
210
  return {
@@ -157,16 +225,32 @@ function verifySignedTxSemantics(signed, plan) {
157
225
  if (plan) {
158
226
  const ePlan = plan;
159
227
  if (signed.sourcePlanId !== ePlan.planId && signed.sourcePlanId !== ePlan.contentHash) {
160
- addIssue("PLAN_ID_MISMATCH", "critical", `Security violation: sourcePlanId mismatch. Signed sourcePlanId is ${signed.sourcePlanId}, but plan is ${ePlan.planId}`);
228
+ addIssue(
229
+ "PLAN_ID_MISMATCH",
230
+ "critical",
231
+ `Security violation: sourcePlanId mismatch. Signed sourcePlanId is ${signed.sourcePlanId}, but plan is ${ePlan.planId}`
232
+ );
161
233
  }
162
234
  if (ePlan.amountSompi && BigInt(signed.amountSompi) !== BigInt(ePlan.amountSompi)) {
163
- addIssue("IMMUTABLE_FIELD_MUTATION", "critical", `Security violation: amountSompi changed from ${ePlan.amountSompi} to ${signed.amountSompi} after signing`);
235
+ addIssue(
236
+ "IMMUTABLE_FIELD_MUTATION",
237
+ "critical",
238
+ `Security violation: amountSompi changed from ${ePlan.amountSompi} to ${signed.amountSompi} after signing`
239
+ );
164
240
  }
165
241
  if (signed.networkId !== ePlan.networkId) {
166
- addIssue("NETWORK_MISMATCH", "critical", `Security violation: networkId changed from ${ePlan.networkId} to ${signed.networkId} after signing`);
242
+ addIssue(
243
+ "NETWORK_MISMATCH",
244
+ "critical",
245
+ `Security violation: networkId changed from ${ePlan.networkId} to ${signed.networkId} after signing`
246
+ );
167
247
  }
168
248
  } else {
169
- addIssue("PLAN_UNAVAILABLE_FOR_LINEAGE_CHECK", "warning", "Source plan is not available in the workspace; skipping lineage check");
249
+ addIssue(
250
+ "PLAN_UNAVAILABLE_FOR_LINEAGE_CHECK",
251
+ "warning",
252
+ "Source plan is not available in the workspace; skipping lineage check"
253
+ );
170
254
  }
171
255
  if (!signed.signedTransaction?.payload) {
172
256
  addIssue("MISSING_PAYLOAD", "error", "Signed transaction is missing its raw payload");
@@ -205,10 +289,7 @@ function buildPaymentPlan(request) {
205
289
  if (a.address > b.address) return 1;
206
290
  return 0;
207
291
  });
208
- const target = sortedOutputs.reduce(
209
- (sum, output) => sum + output.amountSompi,
210
- 0n
211
- );
292
+ const target = sortedOutputs.reduce((sum, output) => sum + output.amountSompi, 0n);
212
293
  if (target <= 0n) {
213
294
  throw new Error("Transaction amount must be positive.");
214
295
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardkas/tx-builder",
3
- "version": "0.7.1-alpha",
3
+ "version": "0.7.4-alpha",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -8,7 +8,7 @@
8
8
  ".": "./dist/index.js"
9
9
  },
10
10
  "dependencies": {
11
- "@hardkas/core": "0.7.1-alpha"
11
+ "@hardkas/core": "0.7.4-alpha"
12
12
  },
13
13
  "devDependencies": {
14
14
  "tsup": "^8.3.5",