@odatano/core 0.3.16 → 0.3.18
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/@cds-models/CardanoODataService/index.d.ts +434 -427
- package/@cds-models/CardanoODataService/index.d.ts.map +1 -1
- package/@cds-models/CardanoODataService/index.js +7 -0
- package/@cds-models/CardanoODataService/index.js.map +1 -1
- package/@cds-models/CardanoODataService/index.ts +99 -92
- package/@cds-models/CardanoSignService/index.d.ts +1549 -0
- package/@cds-models/CardanoSignService/index.d.ts.map +1 -0
- package/@cds-models/CardanoSignService/index.js +291 -0
- package/@cds-models/CardanoSignService/index.js.map +1 -0
- package/@cds-models/CardanoSignService/index.ts +519 -0
- package/@cds-models/CardanoTransactionService/index.d.ts +338 -815
- package/@cds-models/CardanoTransactionService/index.d.ts.map +1 -1
- package/@cds-models/CardanoTransactionService/index.js +3 -63
- package/@cds-models/CardanoTransactionService/index.js.map +1 -1
- package/@cds-models/CardanoTransactionService/index.ts +71 -210
- package/@cds-models/index.d.ts +150 -1
- package/@cds-models/index.d.ts.map +1 -1
- package/@cds-models/index.js +51 -1
- package/@cds-models/index.js.map +1 -1
- package/@cds-models/index.ts +74 -2
- package/@cds-models/odatano/cardano/index.d.ts +553 -696
- package/@cds-models/odatano/cardano/index.d.ts.map +1 -1
- package/@cds-models/odatano/cardano/index.js +3 -52
- package/@cds-models/odatano/cardano/index.js.map +1 -1
- package/@cds-models/odatano/cardano/index.ts +93 -165
- package/README.md +78 -19
- package/db/schema.cds +6 -108
- package/db/types.cds +111 -0
- package/package.json +22 -6
- package/src/index.d.ts.map +1 -1
- package/src/index.js +8 -3
- package/src/index.js.map +1 -1
- package/src/plugin.d.ts.map +1 -1
- package/src/plugin.js +7 -2
- package/src/plugin.js.map +1 -1
- package/srv/blockchain/backends/koios-backend.d.ts.map +1 -1
- package/srv/blockchain/backends/koios-backend.js +6 -16
- package/srv/blockchain/backends/koios-backend.js.map +1 -1
- package/srv/blockchain/cardano-client.d.ts.map +1 -1
- package/srv/blockchain/cardano-client.js +13 -10
- package/srv/blockchain/cardano-client.js.map +1 -1
- package/srv/blockchain/cardano-indexer.d.ts.map +1 -1
- package/srv/blockchain/cardano-indexer.js +10 -8
- package/srv/blockchain/cardano-indexer.js.map +1 -1
- package/srv/blockchain/cardano-tx-builder.d.ts.map +1 -1
- package/srv/blockchain/cardano-tx-builder.js +16 -16
- package/srv/blockchain/cardano-tx-builder.js.map +1 -1
- package/srv/blockchain/signing/hsm-signer.d.ts.map +1 -0
- package/srv/blockchain/signing/hsm-signer.js +290 -0
- package/srv/blockchain/signing/hsm-signer.js.map +1 -0
- package/srv/blockchain/signing/signature-verifier.d.ts.map +1 -1
- package/srv/blockchain/signing/signature-verifier.js +7 -25
- package/srv/blockchain/signing/signature-verifier.js.map +1 -1
- package/srv/blockchain/transaction-building/buildooor-tx.d.ts.map +1 -1
- package/srv/blockchain/transaction-building/buildooor-tx.js +171 -437
- package/srv/blockchain/transaction-building/buildooor-tx.js.map +1 -1
- package/srv/blockchain/transaction-building/cardano-tx.d.ts.map +1 -1
- package/srv/blockchain/transaction-building/csl-tx.d.ts.map +1 -1
- package/srv/blockchain/transaction-building/csl-tx.js +230 -611
- package/srv/blockchain/transaction-building/csl-tx.js.map +1 -1
- package/srv/cardano-service.cds +17 -9
- package/srv/cardano-service.js +2 -14
- package/srv/cardano-service.js.map +1 -1
- package/srv/cardano-sign-service.cds +128 -0
- package/srv/cardano-sign-service.d.ts.map +1 -0
- package/srv/cardano-sign-service.js +401 -0
- package/srv/cardano-sign-service.js.map +1 -0
- package/srv/cardano-tx-service.cds +116 -196
- package/srv/cardano-tx-service.js +5 -308
- package/srv/cardano-tx-service.js.map +1 -1
- package/srv/server.d.ts.map +1 -1
- package/srv/server.js +60 -5
- package/srv/server.js.map +1 -1
- package/srv/utils/const.d.ts.map +1 -1
- package/srv/utils/const.js +5 -1
- package/srv/utils/const.js.map +1 -1
- package/srv/utils/error-codes.d.ts.map +1 -1
- package/srv/utils/error-codes.js +15 -0
- package/srv/utils/error-codes.js.map +1 -1
- package/srv/utils/errors.d.ts.map +1 -1
- package/srv/utils/errors.js +12 -1
- package/srv/utils/errors.js.map +1 -1
- package/srv/utils/mappers.d.ts.map +1 -1
- package/srv/utils/mappers.js +9 -29
- package/srv/utils/mappers.js.map +1 -1
- package/srv/utils/signing-helper.d.ts.map +1 -1
- package/srv/utils/signing-helper.js +43 -25
- package/srv/utils/signing-helper.js.map +1 -1
- package/srv/utils/tx-build-helper.d.ts.map +1 -1
- package/srv/utils/tx-build-helper.js +10 -4
- package/srv/utils/tx-build-helper.js.map +1 -1
- package/srv/utils/types.d.ts.map +1 -1
- package/srv/utils/types.js +2 -0
- package/srv/utils/types.js.map +1 -1
|
@@ -31,207 +31,51 @@ class BuildooorTxBuilder {
|
|
|
31
31
|
const params = protocolParams ?? await client.getProtocolParameters();
|
|
32
32
|
const txbParameters = this._mapLedgerParametersToBuildooorParams(params);
|
|
33
33
|
this.txBuilder = new buildooor_1.TxBuilder(txbParameters);
|
|
34
|
-
logger.debug(`
|
|
34
|
+
logger.debug(`Initialized with protocol parameters`);
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
|
-
* Build unsigned ADA
|
|
38
|
-
* @param req transaction build request
|
|
39
|
-
* @param ctx transaction build context
|
|
40
|
-
* @returns {Promise<TxBuildResult>} transaction build result
|
|
37
|
+
* Build unsigned transfer transaction (ADA-only or with native assets)
|
|
41
38
|
*/
|
|
42
|
-
async
|
|
39
|
+
async buildUnsignedTransfer(req, ctx) {
|
|
43
40
|
try {
|
|
44
|
-
// mapping of ODATANO UTxO Type to ledger-ts UTxO objects (with multi-asset support)
|
|
45
|
-
// This allows spending UTxOs that contain native assets - they will be returned in the change output
|
|
46
41
|
const ledgerUtxos = ctx.utxos.map(utxo => this._mapMultiAssetUtxoToLedgerUtxo(utxo));
|
|
47
|
-
// and map to Buildooor TxIn objects for inputs
|
|
48
42
|
const inputs = ledgerUtxos.map(utxo => ({ utxo }));
|
|
49
|
-
// set Addresses
|
|
50
43
|
const recipientAddress = cardano_ledger_ts_1.Address.fromString(req.recipientAddress);
|
|
51
44
|
const changeAddress = cardano_ledger_ts_1.Address.fromString(req.changeAddress ?? req.senderAddress);
|
|
52
|
-
// set Amount
|
|
53
45
|
const amount = BigInt(String(req.lovelaceAmount));
|
|
54
|
-
//
|
|
46
|
+
// Build output value (lovelace + optional native assets)
|
|
55
47
|
let outputValue = cardano_ledger_ts_1.Value.lovelaces(amount);
|
|
56
48
|
if (req.assets && req.assets.length > 0) {
|
|
57
|
-
|
|
58
|
-
if (asset.unit === 'lovelace')
|
|
59
|
-
continue;
|
|
60
|
-
const { policyId, assetName } = (0, tx_build_helper_1.parseAssetUnit)(asset.unit);
|
|
61
|
-
const assetValue = cardano_ledger_ts_1.Value.singleAsset(new cardano_ledger_ts_1.Hash28(policyId), Buffer.from(assetName, 'hex'), BigInt(asset.quantity));
|
|
62
|
-
outputValue = cardano_ledger_ts_1.Value.add(outputValue, assetValue);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
const txOutParams = {
|
|
66
|
-
address: recipientAddress,
|
|
67
|
-
value: outputValue,
|
|
68
|
-
};
|
|
69
|
-
if (req.outputDatum) {
|
|
70
|
-
txOutParams.datum = (0, tx_build_helper_1.jsonToPlutusData)(req.outputDatum);
|
|
49
|
+
outputValue = this._buildLedgerValue(amount, req.assets);
|
|
71
50
|
}
|
|
72
|
-
const outputs = [
|
|
73
|
-
|
|
74
|
-
const tx = await this.txBuilder.build({
|
|
75
|
-
inputs,
|
|
76
|
-
outputs,
|
|
77
|
-
changeAddress,
|
|
78
|
-
});
|
|
79
|
-
// full unsigned tx cbor (4-tuple, witness empty)
|
|
80
|
-
const unsignedTxBytes = tx.toCbor().toBuffer();
|
|
81
|
-
const unsignedTxCbor = (0, uint8array_utils_1.toHex)(unsignedTxBytes);
|
|
82
|
-
const txBodyHash = tx.hash.toString();
|
|
51
|
+
const outputs = [this._buildTxOut(recipientAddress, outputValue, req.outputDatum)];
|
|
52
|
+
const tx = await this.txBuilder.build({ inputs, outputs, changeAddress });
|
|
83
53
|
logger.debug(`Built unsigned transaction successfully.`);
|
|
84
|
-
return
|
|
85
|
-
unsignedTxCbor: unsignedTxCbor,
|
|
86
|
-
txBodyHash: txBodyHash,
|
|
87
|
-
senderAddress: req.senderAddress,
|
|
88
|
-
network: this.cardanoClient.network,
|
|
89
|
-
sizeBytes: unsignedTxBytes.length,
|
|
90
|
-
builderEngine: this.name,
|
|
91
|
-
feeLovelace: tx.body.fee.toString(),
|
|
92
|
-
inputs: ctx.utxos.map(u => ({
|
|
93
|
-
txHash: u.txHash,
|
|
94
|
-
index: u.outputIndex,
|
|
95
|
-
lovelace: (0, tx_build_helper_1.getLovelace)(u).toString()
|
|
96
|
-
})),
|
|
97
|
-
outputs: tx.body.outputs.map((o) => ({
|
|
98
|
-
address: o.address?.toString?.() ?? "",
|
|
99
|
-
lovelace: o.value?.lovelaces?.toString?.() ?? "0"
|
|
100
|
-
})),
|
|
101
|
-
warnings: []
|
|
102
|
-
};
|
|
54
|
+
return this._buildResult(req, ctx, this._extractTxDetails(tx));
|
|
103
55
|
}
|
|
104
56
|
catch (err) {
|
|
105
|
-
(0, tx_build_helper_1.mapBuilderError)(err
|
|
57
|
+
(0, tx_build_helper_1.mapBuilderError)(err);
|
|
106
58
|
}
|
|
107
59
|
}
|
|
108
60
|
async buildUnsignedTransactionWithMetadata(req, ctx) {
|
|
109
61
|
try {
|
|
110
|
-
// mapping of ODATANO UTxO Type to ledger-ts UTxO objects (with multi-asset support)
|
|
111
|
-
// This allows spending UTxOs that contain native assets - they will be returned in the change output
|
|
112
62
|
const ledgerUtxos = ctx.utxos.map(utxo => this._mapMultiAssetUtxoToLedgerUtxo(utxo));
|
|
113
|
-
// Buildooor TxIn objects for inputs
|
|
114
63
|
const inputs = ledgerUtxos.map(utxo => ({ utxo }));
|
|
115
|
-
// Addresses
|
|
116
64
|
const recipientAddress = cardano_ledger_ts_1.Address.fromString(req.recipientAddress);
|
|
117
65
|
const changeAddress = cardano_ledger_ts_1.Address.fromString(req.changeAddress ?? req.senderAddress);
|
|
118
|
-
// Amount
|
|
119
66
|
const amount = BigInt(String(req.lovelaceAmount));
|
|
120
67
|
const metadata = this._mapOdatanoMetadataToLedgerMetadata(req.metadataJson);
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
new cardano_ledger_ts_1.TxOut({
|
|
124
|
-
address: recipientAddress,
|
|
125
|
-
value: cardano_ledger_ts_1.Value.lovelaces(amount)
|
|
126
|
-
})
|
|
127
|
-
];
|
|
128
|
-
// build the transaction
|
|
129
|
-
const tx = await this.txBuilder.build({
|
|
130
|
-
inputs,
|
|
131
|
-
outputs,
|
|
132
|
-
changeAddress,
|
|
133
|
-
metadata
|
|
134
|
-
});
|
|
135
|
-
// full unsigned tx cbor (4-tuple, witness empty)
|
|
136
|
-
const unsignedTxBytes = tx.toCbor().toBuffer();
|
|
137
|
-
const unsignedTxCbor = (0, uint8array_utils_1.toHex)(unsignedTxBytes);
|
|
138
|
-
const txBodyHash = tx.hash.toString();
|
|
68
|
+
const outputs = [new cardano_ledger_ts_1.TxOut({ address: recipientAddress, value: cardano_ledger_ts_1.Value.lovelaces(amount) })];
|
|
69
|
+
const tx = await this.txBuilder.build({ inputs, outputs, changeAddress, metadata });
|
|
139
70
|
logger.debug(`Built unsigned transaction successfully.`);
|
|
140
|
-
return
|
|
141
|
-
unsignedTxCbor: unsignedTxCbor,
|
|
142
|
-
txBodyHash: txBodyHash,
|
|
143
|
-
senderAddress: req.senderAddress,
|
|
144
|
-
network: this.cardanoClient.network,
|
|
145
|
-
builderEngine: this.name,
|
|
146
|
-
sizeBytes: unsignedTxBytes.length,
|
|
147
|
-
feeLovelace: tx.body.fee.toString(),
|
|
148
|
-
inputs: ctx.utxos.map(u => ({
|
|
149
|
-
txHash: u.txHash,
|
|
150
|
-
index: u.outputIndex,
|
|
151
|
-
lovelace: (0, tx_build_helper_1.getLovelace)(u).toString()
|
|
152
|
-
})),
|
|
153
|
-
outputs: tx.body.outputs.map((o) => ({
|
|
154
|
-
address: o.address?.toString?.() ?? "",
|
|
155
|
-
lovelace: o.value?.lovelaces?.toString?.() ?? "0"
|
|
156
|
-
})),
|
|
157
|
-
warnings: []
|
|
158
|
-
};
|
|
71
|
+
return this._buildResult(req, ctx, this._extractTxDetails(tx));
|
|
159
72
|
}
|
|
160
73
|
catch (err) {
|
|
161
|
-
(0, tx_build_helper_1.mapBuilderError)(err
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
async buildUnsignedMultiAssetTransaction(req, ctx) {
|
|
165
|
-
if (!req.assets || req.assets.length === 0) {
|
|
166
|
-
throw new Error('[BuildooorTxBuilder] buildUnsignedMultiAssetTransaction requires assets to be specified');
|
|
167
|
-
}
|
|
168
|
-
try {
|
|
169
|
-
// Map all available UTxOs to ledger UTxOs for Buildooor (let builder handle selection)
|
|
170
|
-
const ledgerUtxos = ctx.utxos.map(utxo => this._mapMultiAssetUtxoToLedgerUtxo(utxo));
|
|
171
|
-
// Buildooor TxIn objects for inputs
|
|
172
|
-
const inputs = ledgerUtxos.map(utxo => ({ utxo }));
|
|
173
|
-
// Addresses
|
|
174
|
-
const recipientAddress = cardano_ledger_ts_1.Address.fromString(req.recipientAddress);
|
|
175
|
-
const changeAddress = cardano_ledger_ts_1.Address.fromString(req.changeAddress ?? req.senderAddress);
|
|
176
|
-
// Build output value with ADA + assets
|
|
177
|
-
let outputValue = cardano_ledger_ts_1.Value.lovelaces(BigInt(req.lovelaceAmount));
|
|
178
|
-
for (const asset of req.assets) {
|
|
179
|
-
// Parse policyId and assetName from unit (format: policyId.assetName or policyId+assetName)
|
|
180
|
-
const { policyId, assetName } = (0, tx_build_helper_1.parseAssetUnit)(asset.unit);
|
|
181
|
-
const policyHash = new cardano_ledger_ts_1.Hash28(policyId);
|
|
182
|
-
const assetValue = cardano_ledger_ts_1.Value.singleAsset(policyHash, Buffer.from(assetName, 'hex'), BigInt(asset.quantity));
|
|
183
|
-
outputValue = cardano_ledger_ts_1.Value.add(outputValue, assetValue);
|
|
184
|
-
}
|
|
185
|
-
// Build output (with optional inline datum for script addresses)
|
|
186
|
-
const txOutParams = {
|
|
187
|
-
address: recipientAddress,
|
|
188
|
-
value: outputValue,
|
|
189
|
-
};
|
|
190
|
-
if (req.outputDatum) {
|
|
191
|
-
txOutParams.datum = (0, tx_build_helper_1.jsonToPlutusData)(req.outputDatum);
|
|
192
|
-
}
|
|
193
|
-
const outputs = [new cardano_ledger_ts_1.TxOut(txOutParams)];
|
|
194
|
-
// Build the transaction
|
|
195
|
-
const tx = await this.txBuilder.build({
|
|
196
|
-
inputs,
|
|
197
|
-
outputs,
|
|
198
|
-
changeAddress,
|
|
199
|
-
});
|
|
200
|
-
// Full unsigned tx cbor (4-tuple, witness empty)
|
|
201
|
-
const unsignedTxBytes = tx.toCbor().toBuffer();
|
|
202
|
-
const unsignedTxCbor = (0, uint8array_utils_1.toHex)(unsignedTxBytes);
|
|
203
|
-
const txBodyHash = tx.hash.toString();
|
|
204
|
-
logger.debug(`Built unsigned multi-asset transaction successfully.`);
|
|
205
|
-
return {
|
|
206
|
-
unsignedTxCbor: unsignedTxCbor,
|
|
207
|
-
txBodyHash: txBodyHash,
|
|
208
|
-
senderAddress: req.senderAddress,
|
|
209
|
-
network: this.cardanoClient.network,
|
|
210
|
-
sizeBytes: unsignedTxBytes.length,
|
|
211
|
-
builderEngine: this.name,
|
|
212
|
-
feeLovelace: tx.body.fee.toString(),
|
|
213
|
-
inputs: ctx.utxos.map(u => ({
|
|
214
|
-
txHash: u.txHash,
|
|
215
|
-
index: u.outputIndex,
|
|
216
|
-
lovelace: (0, tx_build_helper_1.getLovelace)(u).toString()
|
|
217
|
-
})),
|
|
218
|
-
outputs: tx.body.outputs.map((o) => ({
|
|
219
|
-
address: o.address?.toString?.() ?? "",
|
|
220
|
-
lovelace: o.value?.lovelaces?.toString?.() ?? "0"
|
|
221
|
-
})),
|
|
222
|
-
warnings: []
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
catch (err) {
|
|
226
|
-
// Extract asset unit from error message if possible
|
|
227
|
-
const assetMatch = err?.message?.match(/not enough\s+([a-f0-9.]+)/i);
|
|
228
|
-
const assetUnit = assetMatch?.[1];
|
|
229
|
-
(0, tx_build_helper_1.mapBuilderError)(err, assetUnit);
|
|
74
|
+
(0, tx_build_helper_1.mapBuilderError)(err);
|
|
230
75
|
}
|
|
231
76
|
}
|
|
232
77
|
async buildUnsignedMintTransaction(req, ctx) {
|
|
233
78
|
try {
|
|
234
|
-
// Addresses
|
|
235
79
|
const recipientAddress = cardano_ledger_ts_1.Address.fromString(req.recipientAddress);
|
|
236
80
|
const changeAddress = cardano_ledger_ts_1.Address.fromString(req.changeAddress ?? req.senderAddress);
|
|
237
81
|
// Parse the minting policy script once
|
|
@@ -242,9 +86,8 @@ class BuildooorTxBuilder {
|
|
|
242
86
|
const mints = [];
|
|
243
87
|
for (const mintAction of req.mintActions) {
|
|
244
88
|
const { assetName } = (0, tx_build_helper_1.parseAssetUnit)(mintAction.assetUnit);
|
|
245
|
-
const assetValue = cardano_ledger_ts_1.Value.singleAsset(script.hash, Buffer.from(assetName, 'hex'), BigInt(mintAction.quantity));
|
|
246
89
|
mints.push({
|
|
247
|
-
value:
|
|
90
|
+
value: cardano_ledger_ts_1.Value.singleAsset(script.hash, Buffer.from(assetName, 'hex'), BigInt(mintAction.quantity)),
|
|
248
91
|
script: {
|
|
249
92
|
inline: script,
|
|
250
93
|
redeemer: req.mintRedeemer
|
|
@@ -262,126 +105,36 @@ class BuildooorTxBuilder {
|
|
|
262
105
|
const quantity = BigInt(mintAction.quantity);
|
|
263
106
|
if (quantity > 0n) {
|
|
264
107
|
const { assetName } = (0, tx_build_helper_1.parseAssetUnit)(mintAction.assetUnit);
|
|
265
|
-
|
|
266
|
-
mintValue = cardano_ledger_ts_1.Value.add(mintValue, assetValue);
|
|
108
|
+
mintValue = cardano_ledger_ts_1.Value.add(mintValue, cardano_ledger_ts_1.Value.singleAsset(script.hash, Buffer.from(assetName, 'hex'), quantity));
|
|
267
109
|
}
|
|
268
110
|
}
|
|
269
|
-
// Build output
|
|
270
|
-
let outputValue = cardano_ledger_ts_1.Value.lovelaces(BigInt(req.lovelaceAmount
|
|
111
|
+
// Build output — recipient gets the minted assets + min ADA
|
|
112
|
+
let outputValue = cardano_ledger_ts_1.Value.lovelaces(BigInt(req.lovelaceAmount));
|
|
271
113
|
outputValue = cardano_ledger_ts_1.Value.add(outputValue, mintValue);
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
value: outputValue,
|
|
276
|
-
};
|
|
277
|
-
if (req.inlineDatum) {
|
|
278
|
-
txOutParams.datum = (0, tx_build_helper_1.jsonToPlutusData)(req.inlineDatum);
|
|
279
|
-
}
|
|
280
|
-
const outputs = [new cardano_ledger_ts_1.TxOut(txOutParams)];
|
|
281
|
-
// Find an ADA-only UTxO for collateral (Plutus scripts require ADA-only collateral)
|
|
282
|
-
const adaOnlyUtxo = ctx.utxos.find(u => u.amount.every(a => a.unit.toLowerCase() === 'lovelace'));
|
|
283
|
-
if (!adaOnlyUtxo) {
|
|
284
|
-
throw new Error('[BuildooorTxBuilder] No ADA-only UTxO available for collateral. Plutus scripts require ADA-only collateral.');
|
|
285
|
-
}
|
|
286
|
-
// Use only 1 collateral to minimize tx size
|
|
287
|
-
const collateralUtxos = [this._mapOdatanoUtxoToLedgerUtxo(adaOnlyUtxo)];
|
|
288
|
-
// Exclude collateral UTxO from regular inputs so it is not consumed on successful tx.
|
|
289
|
-
// This preserves the dedicated collateral UTxO for future Plutus transactions.
|
|
290
|
-
const fundingUtxos = ctx.utxos.filter(u => !(u.txHash === adaOnlyUtxo.txHash && u.outputIndex === adaOnlyUtxo.outputIndex));
|
|
114
|
+
const outputs = [this._buildTxOut(recipientAddress, outputValue, req.inlineDatum)];
|
|
115
|
+
// Collateral + funding separation
|
|
116
|
+
const { collateralUtxos, fundingUtxos } = this._setupCollateral(ctx.utxos);
|
|
291
117
|
const fundingLedgerUtxos = fundingUtxos.map(utxo => this._mapMultiAssetUtxoToLedgerUtxo(utxo));
|
|
292
118
|
const inputs = fundingLedgerUtxos.map(utxo => ({ utxo }));
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
if (ctx.evaluateTransaction) {
|
|
296
|
-
// Build first pass with high execution units for evaluation
|
|
297
|
-
logger.debug(`Building evaluation pass with high execution units`);
|
|
298
|
-
const evalMints = buildMints(const_1.HIGH_EXECUTION_UNITS);
|
|
119
|
+
// Evaluate execution units
|
|
120
|
+
const finalExUnits = await this._evaluateExUnits(async () => {
|
|
299
121
|
const evalTx = await this.txBuilder.build({
|
|
300
|
-
inputs,
|
|
301
|
-
|
|
302
|
-
changeAddress,
|
|
303
|
-
mints: evalMints,
|
|
304
|
-
collaterals: collateralUtxos,
|
|
305
|
-
requiredSigners: req.requiredSigners
|
|
122
|
+
inputs, outputs, changeAddress, mints: buildMints(const_1.HIGH_EXECUTION_UNITS),
|
|
123
|
+
collaterals: collateralUtxos, requiredSigners: req.requiredSigners
|
|
306
124
|
});
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const evalResults = await ctx.evaluateTransaction(evalTxCbor);
|
|
311
|
-
logger.debug(`Evaluation results: ${JSON.stringify(evalResults)}`);
|
|
312
|
-
if (evalResults && evalResults.length > 0) {
|
|
313
|
-
// Use the evaluated budget (take first result for single script)
|
|
314
|
-
const budget = evalResults[0].budget;
|
|
315
|
-
// Add safety margin to evaluated units
|
|
316
|
-
finalExUnits = {
|
|
317
|
-
mem: Math.ceil(budget.memory * const_1.EXECUTION_UNIT_BUFFER),
|
|
318
|
-
cpu: Math.ceil(budget.cpu * const_1.EXECUTION_UNIT_BUFFER)
|
|
319
|
-
};
|
|
320
|
-
logger.info(`Using evaluated execution units: mem=${finalExUnits.mem}, cpu=${finalExUnits.cpu}`);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
catch (evalError) {
|
|
324
|
-
logger.warn(`Evaluation failed, using default units: ${evalError.message}`);
|
|
325
|
-
// Fall back to defaults on evaluation failure
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
else {
|
|
329
|
-
logger.debug(`No evaluator available, using default execution units`);
|
|
330
|
-
}
|
|
331
|
-
// Build with final execution units
|
|
125
|
+
return (0, uint8array_utils_1.toHex)(evalTx.toCbor().toBuffer());
|
|
126
|
+
}, ctx.evaluateTransaction);
|
|
127
|
+
// Build with final execution units + witness buffer
|
|
332
128
|
const mints = buildMints(finalExUnits);
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
outputs,
|
|
337
|
-
changeAddress,
|
|
338
|
-
mints: mints,
|
|
339
|
-
collaterals: collateralUtxos,
|
|
340
|
-
requiredSigners: req.requiredSigners
|
|
341
|
-
});
|
|
342
|
-
// Add minimal buffer for witness set CBOR overhead (signing adds ~44 bytes)
|
|
343
|
-
const calculatedFee = BigInt(txFirstPass.body.fee.toString());
|
|
344
|
-
const witnessBuffer = BigInt(const_1.WITNESS_BUFFER_BYTES);
|
|
345
|
-
const adjustedMinFee = calculatedFee + witnessBuffer;
|
|
346
|
-
logger.debug(`First pass fee: ${calculatedFee}, rebuilding with witness buffer: ${adjustedMinFee}`);
|
|
347
|
-
// Final build with adjusted minimum fee to account for witness overhead
|
|
348
|
-
const tx = await this.txBuilder.build({
|
|
349
|
-
inputs,
|
|
350
|
-
outputs,
|
|
351
|
-
changeAddress,
|
|
352
|
-
mints: mints,
|
|
353
|
-
collaterals: collateralUtxos,
|
|
354
|
-
requiredSigners: req.requiredSigners,
|
|
355
|
-
fee: adjustedMinFee
|
|
129
|
+
const tx = await this._buildWithWitnessBuffer({
|
|
130
|
+
inputs, outputs, changeAddress, mints,
|
|
131
|
+
collaterals: collateralUtxos, requiredSigners: req.requiredSigners
|
|
356
132
|
});
|
|
357
|
-
// Full unsigned tx cbor (4-tuple, witness empty)
|
|
358
|
-
const unsignedTxBytes = tx.toCbor().toBuffer();
|
|
359
|
-
const unsignedTxCbor = (0, uint8array_utils_1.toHex)(unsignedTxBytes);
|
|
360
|
-
const txBodyHash = tx.hash.toString();
|
|
361
133
|
logger.debug(`Built unsigned minting transaction successfully with fee: ${tx.body.fee.toString()}`);
|
|
362
|
-
return {
|
|
363
|
-
unsignedTxCbor: unsignedTxCbor,
|
|
364
|
-
txBodyHash: txBodyHash,
|
|
365
|
-
senderAddress: req.senderAddress,
|
|
366
|
-
network: this.cardanoClient.network,
|
|
367
|
-
builderEngine: this.name,
|
|
368
|
-
sizeBytes: unsignedTxBytes.length,
|
|
369
|
-
feeLovelace: tx.body.fee.toString(),
|
|
370
|
-
inputs: ctx.utxos.map(u => ({
|
|
371
|
-
txHash: u.txHash,
|
|
372
|
-
index: u.outputIndex,
|
|
373
|
-
lovelace: (0, tx_build_helper_1.getLovelace)(u).toString()
|
|
374
|
-
})),
|
|
375
|
-
outputs: tx.body.outputs.map((o) => ({
|
|
376
|
-
address: o.address?.toString?.() ?? "",
|
|
377
|
-
lovelace: o.value?.lovelaces?.toString?.() ?? "0"
|
|
378
|
-
})),
|
|
379
|
-
scriptHash: script.hash.toString(),
|
|
380
|
-
warnings: []
|
|
381
|
-
};
|
|
134
|
+
return this._buildResult(req, ctx, this._extractTxDetails(tx), { scriptHash: script.hash.toString() });
|
|
382
135
|
}
|
|
383
136
|
catch (err) {
|
|
384
|
-
(0, tx_build_helper_1.mapBuilderError)(err
|
|
137
|
+
(0, tx_build_helper_1.mapBuilderError)(err);
|
|
385
138
|
}
|
|
386
139
|
}
|
|
387
140
|
async buildUnsignedPlutusSpendTransaction(req, ctx) {
|
|
@@ -397,160 +150,173 @@ class BuildooorTxBuilder {
|
|
|
397
150
|
? (0, tx_build_helper_1.jsonToPlutusData)(plutusScriptExecution.datum)
|
|
398
151
|
: "inline";
|
|
399
152
|
// Find the specific script UTxO in the provided context UTxOs
|
|
400
|
-
// The coordinator is responsible for including the script UTxO in ctx.utxos
|
|
401
153
|
const scriptUtxoRef = plutusScriptExecution.scriptUtxo;
|
|
402
154
|
const scriptOdatanoUtxo = ctx.utxos.find(u => u.txHash === scriptUtxoRef.txHash && u.outputIndex === scriptUtxoRef.outputIndex);
|
|
403
155
|
if (!scriptOdatanoUtxo) {
|
|
404
|
-
throw new Error(`
|
|
156
|
+
throw new Error(`Script UTxO ${scriptUtxoRef.txHash}#${scriptUtxoRef.outputIndex} not found in provided UTxOs`);
|
|
405
157
|
}
|
|
406
|
-
// Map the script UTxO to ledger format
|
|
407
158
|
const scriptLedgerUtxo = this._mapMultiAssetUtxoToLedgerUtxo(scriptOdatanoUtxo);
|
|
408
159
|
// Map sender UTxOs (excluding the script UTxO) as regular inputs
|
|
409
160
|
const senderUtxos = ctx.utxos.filter(u => !(u.txHash === scriptUtxoRef.txHash && u.outputIndex === scriptUtxoRef.outputIndex));
|
|
410
|
-
// Addresses
|
|
411
161
|
const recipientAddress = cardano_ledger_ts_1.Address.fromString(req.recipientAddress);
|
|
412
162
|
const changeAddress = cardano_ledger_ts_1.Address.fromString(req.changeAddress ?? req.senderAddress);
|
|
413
163
|
// Build output — include multi-assets from script UTxO in continuing output
|
|
164
|
+
const scriptNonAdaAssets = scriptOdatanoUtxo.amount.filter(a => a.unit.toLowerCase() !== 'lovelace' && BigInt(a.quantity) > 0n);
|
|
414
165
|
let outputValue = cardano_ledger_ts_1.Value.lovelaces(BigInt(req.lovelaceAmount || 2_000_000));
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
const { policyId, assetName } = (0, tx_build_helper_1.parseAssetUnit)(amount.unit);
|
|
418
|
-
const policyHash = new cardano_ledger_ts_1.Hash28(policyId);
|
|
419
|
-
const assetValue = cardano_ledger_ts_1.Value.singleAsset(policyHash, Buffer.from(assetName, 'hex'), BigInt(amount.quantity));
|
|
420
|
-
outputValue = cardano_ledger_ts_1.Value.add(outputValue, assetValue);
|
|
421
|
-
}
|
|
166
|
+
if (scriptNonAdaAssets.length > 0) {
|
|
167
|
+
outputValue = this._buildLedgerValue(BigInt(req.lovelaceAmount || 2_000_000), scriptOdatanoUtxo.amount);
|
|
422
168
|
}
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
};
|
|
427
|
-
if (req.inlineDatum) {
|
|
428
|
-
txOutParams.datum = (0, tx_build_helper_1.jsonToPlutusData)(req.inlineDatum);
|
|
429
|
-
}
|
|
430
|
-
const outputs = [new cardano_ledger_ts_1.TxOut(txOutParams)];
|
|
431
|
-
// Find an ADA-only UTxO for collateral (from sender UTxOs only)
|
|
432
|
-
const adaOnlyUtxo = senderUtxos.find(u => u.amount.every(a => a.unit.toLowerCase() === 'lovelace'));
|
|
433
|
-
if (!adaOnlyUtxo) {
|
|
434
|
-
throw new Error('[BuildooorTxBuilder] No ADA-only UTxO available for collateral. Plutus scripts require ADA-only collateral.');
|
|
435
|
-
}
|
|
436
|
-
const collateralUtxos = [this._mapOdatanoUtxoToLedgerUtxo(adaOnlyUtxo)];
|
|
437
|
-
// Exclude collateral UTxO from regular inputs so it is not consumed on successful tx.
|
|
438
|
-
// This preserves the dedicated collateral UTxO for future Plutus transactions.
|
|
439
|
-
const fundingUtxos = senderUtxos.filter(u => !(u.txHash === adaOnlyUtxo.txHash && u.outputIndex === adaOnlyUtxo.outputIndex));
|
|
169
|
+
const outputs = [this._buildTxOut(recipientAddress, outputValue, req.inlineDatum)];
|
|
170
|
+
// Collateral + funding separation (from sender UTxOs only)
|
|
171
|
+
const { collateralUtxos, fundingUtxos } = this._setupCollateral(senderUtxos);
|
|
440
172
|
const fundingLedgerUtxos = fundingUtxos.map(utxo => this._mapMultiAssetUtxoToLedgerUtxo(utxo));
|
|
441
173
|
// Helper to build inputs with specified execution units
|
|
442
174
|
const buildInputs = (exUnits) => {
|
|
443
|
-
// Script input with witness
|
|
444
175
|
const scriptInput = {
|
|
445
176
|
utxo: scriptLedgerUtxo,
|
|
446
|
-
inputScript: {
|
|
447
|
-
script,
|
|
448
|
-
datum,
|
|
449
|
-
redeemer: redeemerData,
|
|
450
|
-
executionUnits: exUnits
|
|
451
|
-
}
|
|
177
|
+
inputScript: { script, datum, redeemer: redeemerData, executionUnits: exUnits }
|
|
452
178
|
};
|
|
453
|
-
// Regular sender inputs for fees (excluding collateral)
|
|
454
179
|
const regularInputs = fundingLedgerUtxos.map(utxo => ({ utxo }));
|
|
455
180
|
return [scriptInput, ...regularInputs];
|
|
456
181
|
};
|
|
457
|
-
//
|
|
458
|
-
|
|
459
|
-
if (ctx.evaluateTransaction) {
|
|
460
|
-
// Build first pass with high execution units for evaluation
|
|
461
|
-
logger.debug(`Building evaluation pass with high execution units`);
|
|
462
|
-
const evalInputs = buildInputs(const_1.HIGH_EXECUTION_UNITS);
|
|
182
|
+
// Evaluate execution units
|
|
183
|
+
const finalExUnits = await this._evaluateExUnits(async () => {
|
|
463
184
|
const evalTx = await this.txBuilder.build({
|
|
464
|
-
inputs:
|
|
465
|
-
|
|
466
|
-
changeAddress,
|
|
467
|
-
collaterals: collateralUtxos,
|
|
468
|
-
requiredSigners: req.requiredSigners
|
|
185
|
+
inputs: buildInputs(const_1.HIGH_EXECUTION_UNITS), outputs, changeAddress,
|
|
186
|
+
collaterals: collateralUtxos, requiredSigners: req.requiredSigners
|
|
469
187
|
});
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
logger.debug(`Evaluation results: ${JSON.stringify(evalResults)}`);
|
|
474
|
-
if (evalResults && evalResults.length > 0) {
|
|
475
|
-
const budget = evalResults[0].budget;
|
|
476
|
-
finalExUnits = {
|
|
477
|
-
mem: Math.ceil(budget.memory * const_1.EXECUTION_UNIT_BUFFER),
|
|
478
|
-
cpu: Math.ceil(budget.cpu * const_1.EXECUTION_UNIT_BUFFER)
|
|
479
|
-
};
|
|
480
|
-
logger.info(`Using evaluated execution units: mem=${finalExUnits.mem}, cpu=${finalExUnits.cpu}`);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
catch (evalError) {
|
|
484
|
-
logger.warn(`Evaluation failed, using default units: ${evalError.message}`);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
else {
|
|
488
|
-
logger.debug(`No evaluator available, using default execution units`);
|
|
489
|
-
}
|
|
490
|
-
// Build with final execution units
|
|
188
|
+
return (0, uint8array_utils_1.toHex)(evalTx.toCbor().toBuffer());
|
|
189
|
+
}, ctx.evaluateTransaction);
|
|
190
|
+
// Build with final execution units + witness buffer
|
|
491
191
|
const inputs = buildInputs(finalExUnits);
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
outputs,
|
|
496
|
-
changeAddress,
|
|
497
|
-
collaterals: collateralUtxos,
|
|
498
|
-
requiredSigners: req.requiredSigners
|
|
192
|
+
const tx = await this._buildWithWitnessBuffer({
|
|
193
|
+
inputs, outputs, changeAddress,
|
|
194
|
+
collaterals: collateralUtxos, requiredSigners: req.requiredSigners
|
|
499
195
|
});
|
|
500
|
-
// Add minimal buffer for witness set CBOR overhead
|
|
501
|
-
const calculatedFee = BigInt(txFirstPass.body.fee.toString());
|
|
502
|
-
const witnessBuffer = BigInt(const_1.WITNESS_BUFFER_BYTES);
|
|
503
|
-
const adjustedMinFee = calculatedFee + witnessBuffer;
|
|
504
|
-
logger.debug(`First pass fee: ${calculatedFee}, rebuilding with witness buffer: ${adjustedMinFee}`);
|
|
505
|
-
// Final build with adjusted minimum fee
|
|
506
|
-
const tx = await this.txBuilder.build({
|
|
507
|
-
inputs,
|
|
508
|
-
outputs,
|
|
509
|
-
changeAddress,
|
|
510
|
-
collaterals: collateralUtxos,
|
|
511
|
-
requiredSigners: req.requiredSigners,
|
|
512
|
-
fee: adjustedMinFee
|
|
513
|
-
});
|
|
514
|
-
const unsignedTxBytes = tx.toCbor().toBuffer();
|
|
515
|
-
const unsignedTxCbor = (0, uint8array_utils_1.toHex)(unsignedTxBytes);
|
|
516
|
-
const txBodyHash = tx.hash.toString();
|
|
517
196
|
logger.debug(`Built unsigned Plutus spending transaction successfully with fee: ${tx.body.fee.toString()}`);
|
|
518
|
-
return {
|
|
519
|
-
unsignedTxCbor,
|
|
520
|
-
txBodyHash,
|
|
521
|
-
senderAddress: req.senderAddress,
|
|
522
|
-
network: this.cardanoClient.network,
|
|
523
|
-
builderEngine: this.name,
|
|
524
|
-
sizeBytes: unsignedTxBytes.length,
|
|
525
|
-
feeLovelace: tx.body.fee.toString(),
|
|
526
|
-
inputs: ctx.utxos.map(u => ({
|
|
527
|
-
txHash: u.txHash,
|
|
528
|
-
index: u.outputIndex,
|
|
529
|
-
lovelace: (0, tx_build_helper_1.getLovelace)(u).toString()
|
|
530
|
-
})),
|
|
531
|
-
outputs: tx.body.outputs.map((o) => ({
|
|
532
|
-
address: o.address?.toString?.() ?? "",
|
|
533
|
-
lovelace: o.value?.lovelaces?.toString?.() ?? "0"
|
|
534
|
-
})),
|
|
535
|
-
scriptHash: script.hash.toString(),
|
|
536
|
-
warnings: []
|
|
537
|
-
};
|
|
197
|
+
return this._buildResult(req, ctx, this._extractTxDetails(tx), { scriptHash: script.hash.toString() });
|
|
538
198
|
}
|
|
539
199
|
catch (err) {
|
|
540
|
-
(0, tx_build_helper_1.mapBuilderError)(err
|
|
200
|
+
(0, tx_build_helper_1.mapBuilderError)(err);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//---------------------------------------------------------------------------
|
|
204
|
+
// Shared Helper Methods
|
|
205
|
+
//---------------------------------------------------------------------------
|
|
206
|
+
/** Extract CBOR, hash, fee, size, and outputs from a built Buildooor Tx */
|
|
207
|
+
_extractTxDetails(tx) {
|
|
208
|
+
const unsignedTxBytes = tx.toCbor().toBuffer();
|
|
209
|
+
return {
|
|
210
|
+
unsignedTxCbor: (0, uint8array_utils_1.toHex)(unsignedTxBytes),
|
|
211
|
+
txBodyHash: tx.hash.toString(),
|
|
212
|
+
sizeBytes: unsignedTxBytes.length,
|
|
213
|
+
feeLovelace: tx.body.fee.toString(),
|
|
214
|
+
outputDetails: tx.body.outputs.map((o) => ({
|
|
215
|
+
address: o.address?.toString?.() ?? "",
|
|
216
|
+
lovelace: o.value?.lovelaces?.toString?.() ?? "0"
|
|
217
|
+
})),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/** Build the standard TxBuildResult object */
|
|
221
|
+
_buildResult(req, ctx, txDetails, extra) {
|
|
222
|
+
return {
|
|
223
|
+
unsignedTxCbor: txDetails.unsignedTxCbor,
|
|
224
|
+
txBodyHash: txDetails.txBodyHash,
|
|
225
|
+
senderAddress: req.senderAddress,
|
|
226
|
+
network: this.cardanoClient.network,
|
|
227
|
+
builderEngine: this.name,
|
|
228
|
+
sizeBytes: txDetails.sizeBytes,
|
|
229
|
+
feeLovelace: txDetails.feeLovelace,
|
|
230
|
+
inputs: ctx.utxos.map(u => ({
|
|
231
|
+
txHash: u.txHash,
|
|
232
|
+
index: u.outputIndex,
|
|
233
|
+
lovelace: (0, tx_build_helper_1.getLovelace)(u).toString()
|
|
234
|
+
})),
|
|
235
|
+
outputs: txDetails.outputDetails,
|
|
236
|
+
...extra,
|
|
237
|
+
warnings: [],
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Evaluate execution units via callback. Caller provides an async function
|
|
242
|
+
* that builds the evaluation tx and returns its CBOR hex.
|
|
243
|
+
*/
|
|
244
|
+
async _evaluateExUnits(buildEvalTx, evaluator) {
|
|
245
|
+
if (!evaluator) {
|
|
246
|
+
logger.debug('No evaluator available, using default execution units');
|
|
247
|
+
return const_1.DEFAULT_EXECUTION_UNITS;
|
|
248
|
+
}
|
|
249
|
+
logger.debug('Building evaluation pass with high execution units');
|
|
250
|
+
const evalTxCbor = await buildEvalTx();
|
|
251
|
+
try {
|
|
252
|
+
const evalResults = await evaluator(evalTxCbor);
|
|
253
|
+
logger.debug(`Evaluation results: ${JSON.stringify(evalResults)}`);
|
|
254
|
+
if (evalResults && evalResults.length > 0) {
|
|
255
|
+
const budget = evalResults[0].budget;
|
|
256
|
+
const result = {
|
|
257
|
+
mem: Math.ceil(budget.memory * const_1.EXECUTION_UNIT_BUFFER),
|
|
258
|
+
cpu: Math.ceil(budget.cpu * const_1.EXECUTION_UNIT_BUFFER)
|
|
259
|
+
};
|
|
260
|
+
logger.info(`Using evaluated execution units: mem=${result.mem}, cpu=${result.cpu}`);
|
|
261
|
+
return result;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
catch (evalError) {
|
|
265
|
+
logger.warn(`Evaluation failed, using default units: ${evalError.message}`);
|
|
266
|
+
}
|
|
267
|
+
return const_1.DEFAULT_EXECUTION_UNITS;
|
|
268
|
+
}
|
|
269
|
+
/** Two-pass build: first build to calculate fee, then rebuild with witness buffer */
|
|
270
|
+
async _buildWithWitnessBuffer(buildParams) {
|
|
271
|
+
const txFirstPass = await this.txBuilder.build(buildParams);
|
|
272
|
+
const calculatedFee = BigInt(txFirstPass.body.fee.toString());
|
|
273
|
+
const adjustedMinFee = calculatedFee + BigInt(const_1.WITNESS_BUFFER_BYTES);
|
|
274
|
+
logger.debug(`First pass fee: ${calculatedFee}, rebuilding with witness buffer: ${adjustedMinFee}`);
|
|
275
|
+
return this.txBuilder.build({ ...buildParams, fee: adjustedMinFee });
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Find an ADA-only UTxO for collateral, map it, and return remaining funding UTxOs.
|
|
279
|
+
* Throws if no ADA-only UTxO is available.
|
|
280
|
+
*/
|
|
281
|
+
_setupCollateral(utxos) {
|
|
282
|
+
const adaOnlyUtxo = utxos.find(u => u.amount.every(a => a.unit.toLowerCase() === 'lovelace'));
|
|
283
|
+
if (!adaOnlyUtxo) {
|
|
284
|
+
throw new Error('No ADA-only UTxO available for collateral. Plutus scripts require ADA-only collateral.');
|
|
541
285
|
}
|
|
286
|
+
const collateralUtxos = [this._mapOdatanoUtxoToLedgerUtxo(adaOnlyUtxo)];
|
|
287
|
+
const fundingUtxos = utxos.filter(u => !(u.txHash === adaOnlyUtxo.txHash && u.outputIndex === adaOnlyUtxo.outputIndex));
|
|
288
|
+
return { collateralUtxos, fundingUtxos };
|
|
289
|
+
}
|
|
290
|
+
/** Build a Ledger Value from lovelace + optional multi-asset array */
|
|
291
|
+
_buildLedgerValue(lovelace, assets) {
|
|
292
|
+
let value = cardano_ledger_ts_1.Value.lovelaces(lovelace);
|
|
293
|
+
if (assets) {
|
|
294
|
+
for (const asset of assets) {
|
|
295
|
+
if (asset.unit.toLowerCase() === 'lovelace')
|
|
296
|
+
continue;
|
|
297
|
+
if (BigInt(asset.quantity) <= 0n)
|
|
298
|
+
continue;
|
|
299
|
+
const { policyId, assetName } = (0, tx_build_helper_1.parseAssetUnit)(asset.unit);
|
|
300
|
+
value = cardano_ledger_ts_1.Value.add(value, cardano_ledger_ts_1.Value.singleAsset(new cardano_ledger_ts_1.Hash28(policyId), Buffer.from(assetName, 'hex'), BigInt(asset.quantity)));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return value;
|
|
304
|
+
}
|
|
305
|
+
/** Build a TxOut with optional inline datum */
|
|
306
|
+
_buildTxOut(address, value, datum) {
|
|
307
|
+
const params = { address, value };
|
|
308
|
+
if (datum) {
|
|
309
|
+
params.datum = (0, tx_build_helper_1.jsonToPlutusData)(datum);
|
|
310
|
+
}
|
|
311
|
+
return new cardano_ledger_ts_1.TxOut(params);
|
|
542
312
|
}
|
|
543
313
|
//---------------------------------------------------------------------------
|
|
544
|
-
//
|
|
314
|
+
// UTxO Mapping & Configuration Helpers
|
|
545
315
|
//---------------------------------------------------------------------------
|
|
546
316
|
/**
|
|
547
317
|
* Map ODATANO LedgerProtocolParameter to Buildooor's ProtocolParameters shape
|
|
548
|
-
* @param protocolParameters ledger protocol parameters
|
|
549
|
-
* @returns mapped protocol parameters
|
|
550
318
|
*/
|
|
551
319
|
_mapLedgerParametersToBuildooorParams(protocolParameters) {
|
|
552
|
-
// Map LedgerProtocolParameter to Buildooor's ProtocolParameters shape
|
|
553
|
-
// Using defaultProtocolParameters as base and overriding with actual values
|
|
554
320
|
return {
|
|
555
321
|
...cardano_ledger_ts_1.defaultProtocolParameters,
|
|
556
322
|
txFeePerByte: Number(protocolParameters.minFeeA),
|
|
@@ -564,22 +330,14 @@ class BuildooorTxBuilder {
|
|
|
564
330
|
}
|
|
565
331
|
/**
|
|
566
332
|
* Map ODATANO UTxO to Ledger UTxO (ADA-only)
|
|
567
|
-
* @param utxos ODATANO UTxO
|
|
568
|
-
* @returns mapped Ledger UTxO
|
|
569
333
|
*/
|
|
570
334
|
_mapOdatanoUtxoToLedgerUtxo(utxos) {
|
|
571
335
|
(0, tx_build_helper_1.assertAdaOnly)(utxos);
|
|
572
|
-
const outRef = new cardano_ledger_ts_1.TxOutRef({
|
|
573
|
-
id: utxos.txHash,
|
|
574
|
-
index: utxos.outputIndex
|
|
575
|
-
});
|
|
576
|
-
const addr = cardano_ledger_ts_1.Address.fromString(utxos.address);
|
|
577
|
-
const value = cardano_ledger_ts_1.Value.lovelaces((0, tx_build_helper_1.getLovelace)(utxos));
|
|
578
336
|
return new cardano_ledger_ts_1.UTxO({
|
|
579
|
-
utxoRef:
|
|
337
|
+
utxoRef: new cardano_ledger_ts_1.TxOutRef({ id: utxos.txHash, index: utxos.outputIndex }),
|
|
580
338
|
resolved: new cardano_ledger_ts_1.TxOut({
|
|
581
|
-
address:
|
|
582
|
-
value,
|
|
339
|
+
address: cardano_ledger_ts_1.Address.fromString(utxos.address),
|
|
340
|
+
value: cardano_ledger_ts_1.Value.lovelaces((0, tx_build_helper_1.getLovelace)(utxos)),
|
|
583
341
|
datum: undefined,
|
|
584
342
|
refScript: undefined
|
|
585
343
|
})
|
|
@@ -587,32 +345,14 @@ class BuildooorTxBuilder {
|
|
|
587
345
|
}
|
|
588
346
|
/**
|
|
589
347
|
* Map ODATANO UTxO to Ledger UTxO (with multi-asset support)
|
|
590
|
-
* @param utxo ODATANO UTxO
|
|
591
|
-
* @returns mapped Ledger UTxO
|
|
592
348
|
*/
|
|
593
349
|
_mapMultiAssetUtxoToLedgerUtxo(utxo) {
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
index: utxo.outputIndex
|
|
597
|
-
});
|
|
598
|
-
const addr = cardano_ledger_ts_1.Address.fromString(utxo.address);
|
|
599
|
-
// Build Value from all amounts
|
|
600
|
-
let value = cardano_ledger_ts_1.Value.lovelaces((0, tx_build_helper_1.getLovelace)(utxo));
|
|
601
|
-
for (const amount of utxo.amount) {
|
|
602
|
-
if (amount.unit.toLowerCase() !== 'lovelace') {
|
|
603
|
-
const { policyId, assetName } = (0, tx_build_helper_1.parseAssetUnit)(amount.unit);
|
|
604
|
-
const policyHash = new cardano_ledger_ts_1.Hash28(policyId);
|
|
605
|
-
const assetValue = cardano_ledger_ts_1.Value.singleAsset(policyHash, Buffer.from(assetName, 'hex'), BigInt(amount.quantity));
|
|
606
|
-
value = cardano_ledger_ts_1.Value.add(value, assetValue);
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
const datumValue = utxo.inlineDatum
|
|
610
|
-
? (0, plutus_data_1.dataFromCbor)(utxo.inlineDatum)
|
|
611
|
-
: undefined;
|
|
350
|
+
const value = this._buildLedgerValue((0, tx_build_helper_1.getLovelace)(utxo), utxo.amount);
|
|
351
|
+
const datumValue = utxo.inlineDatum ? (0, plutus_data_1.dataFromCbor)(utxo.inlineDatum) : undefined;
|
|
612
352
|
return new cardano_ledger_ts_1.UTxO({
|
|
613
|
-
utxoRef:
|
|
353
|
+
utxoRef: new cardano_ledger_ts_1.TxOutRef({ id: utxo.txHash, index: utxo.outputIndex }),
|
|
614
354
|
resolved: new cardano_ledger_ts_1.TxOut({
|
|
615
|
-
address:
|
|
355
|
+
address: cardano_ledger_ts_1.Address.fromString(utxo.address),
|
|
616
356
|
value,
|
|
617
357
|
datum: datumValue,
|
|
618
358
|
refScript: undefined
|
|
@@ -621,8 +361,6 @@ class BuildooorTxBuilder {
|
|
|
621
361
|
}
|
|
622
362
|
/**
|
|
623
363
|
* Map ODATANO metadata JSON to Ledger TxMetadata
|
|
624
|
-
* @param metadataJson metadata in JSON format
|
|
625
|
-
* @returns mapped TxMetadata
|
|
626
364
|
*/
|
|
627
365
|
_mapOdatanoMetadataToLedgerMetadata(metadataJson) {
|
|
628
366
|
if (!metadataJson) {
|
|
@@ -630,9 +368,7 @@ class BuildooorTxBuilder {
|
|
|
630
368
|
}
|
|
631
369
|
const metadata = {};
|
|
632
370
|
for (const [label, value] of Object.entries(metadataJson)) {
|
|
633
|
-
// convert label to number
|
|
634
371
|
const numericLabel = parseInt(label, 10);
|
|
635
|
-
// convert JSON value to TxMetadatum
|
|
636
372
|
const txMetadatum = this._jsonToTxMetadatum(value);
|
|
637
373
|
logger.debug(`Created TxMetadatum for label ${numericLabel}: ${txMetadatum.constructor.name}`);
|
|
638
374
|
metadata[numericLabel] = txMetadatum;
|
|
@@ -644,8 +380,6 @@ class BuildooorTxBuilder {
|
|
|
644
380
|
}
|
|
645
381
|
/**
|
|
646
382
|
* Recursively convert JSON value to TxMetadatum
|
|
647
|
-
* @param value JSON value
|
|
648
|
-
* @returns corresponding TxMetadatum
|
|
649
383
|
*/
|
|
650
384
|
_jsonToTxMetadatum(value) {
|
|
651
385
|
if (typeof value === 'number' || typeof value === 'bigint') {
|
|
@@ -667,7 +401,7 @@ class BuildooorTxBuilder {
|
|
|
667
401
|
}
|
|
668
402
|
return new TxMetadatum_1.TxMetadatumMap(map);
|
|
669
403
|
}
|
|
670
|
-
throw new Error(`
|
|
404
|
+
throw new Error(`Unsupported metadata value type: ${typeof value}`);
|
|
671
405
|
}
|
|
672
406
|
}
|
|
673
407
|
exports.BuildooorTxBuilder = BuildooorTxBuilder;
|