Skip to content

Conversation

@solidsnakedev
Copy link
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings December 23, 2025 18:55
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements transaction chaining and comprehensive native script support for multi-signature workflows. The changes enable building dependent transactions in sequence and support for native scripts including ScriptAll, ScriptAny, ScriptNOfK, and time-locked scripts.

Key changes:

  • Transaction chaining via SignBuilder.chainResult() returning consumed/available UTxOs and pre-computed txHash
  • Native script support with addSigner operation for multi-sig transactions
  • Enhanced wallet signing with auto-fetch of reference UTxOs for native script signer detection

Reviewed changes

Copilot reviewed 129 out of 129 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
WalletNew.ts Added referenceUtxos context parameter to signTx for native script signer extraction
Ogmios.ts Added native script language support and script type detection
KupmiosEffects.ts Implemented script type conversion and improved error messages
ClientImpl.ts Added auto-fetch of reference UTxOs and native script key hash extraction
AddSigner.ts New operation for adding required signers to transactions
Collect.ts Enhanced to filter native scripts that don't require redeemers
Pay.ts Renamed scriptRef to script parameter for consistency
SignBuilderImpl.ts Implemented memoized chainResult() for transaction chaining
TransactionBuilder.ts Added addSigner method and updated ChainResult interface
UTxO.ts Changed scriptRef type from ScriptRef to Script for better type safety
ScriptRef.ts Removed length validation on bytes field
Test files Comprehensive devnet tests for native scripts, addSigner, and chaining

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

*/
export class ScriptRef extends Schema.TaggedClass<ScriptRef>()("ScriptRef", {
bytes: Schema.Uint8ArrayFromHex.pipe(Schema.filter((b) => b.length > 0))
bytes: Schema.Uint8ArrayFromHex
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal of the length validation filter Schema.filter((b) => b.length > 0) from the bytes field allows empty ScriptRef instances to be created. This could lead to invalid script references being stored in transaction outputs. Consider whether empty script references should be allowed according to the Cardano specification.

Copilot uses AI. Check for mistakes.
Comment on lines 120 to 137
switch (language) {
case "native":
encodedScript = script // Native scripts don't need double encoding
break
case "plutus:v1":
case "plutus:v2":
case "plutus:v3":
encodedScript = Script.applyDoubleCborEncoding(script)
break
case "native": {
// Parse the native script from CBOR
return NativeScripts.fromCBORBytes(rawScriptBytes)
}
case "plutus:v1": {
const doubleCborHex = Script.applyDoubleCborEncoding(script)
return new PlutusV1.PlutusV1({ bytes: Bytes.fromHex(doubleCborHex) })
}
case "plutus:v2": {
const doubleCborHex = Script.applyDoubleCborEncoding(script)
return new PlutusV2.PlutusV2({ bytes: Bytes.fromHex(doubleCborHex) })
}
case "plutus:v3": {
const doubleCborHex = Script.applyDoubleCborEncoding(script)
return new PlutusV3.PlutusV3({ bytes: Bytes.fromHex(doubleCborHex) })
}
}
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The switch statement has no default case. If an unexpected language type is returned from Kupo, TypeScript will return undefined implicitly, which could cause runtime errors. Add a default case that throws an error for unknown script language types.

Copilot uses AI. Check for mistakes.
Comment on lines +162 to +171
switch (script._tag) {
case "NativeScript":
return { language: "native", cbor: CoreScript.toCBORHex(script) }
case "PlutusV1":
return { language: "plutus:v1", cbor: CoreScript.toCBORHex(script) }
case "PlutusV2":
return { language: "plutus:v2", cbor: CoreScript.toCBORHex(script) }
case "PlutusV3":
return { language: "plutus:v3", cbor: CoreScript.toCBORHex(script) }
}
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The switch statement has no default case. If an unexpected script tag is encountered, TypeScript will return undefined implicitly. Add a default case that throws an error for unknown script types to catch programming errors early.

Copilot uses AI. Check for mistakes.
address: output.address,
assets: output.assets,
datumOption: output.datumOption,
scriptRef: output.scriptRef ? Script.fromCBOR(output.scriptRef.bytes) : undefined
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Script.fromCBOR call at line 76 can throw an error if the scriptRef bytes are invalid or corrupted. This error would be thrown during the chainResult computation, potentially after the transaction has been built and signed. Consider wrapping this in error handling or validating the scriptRef earlier in the transaction building process.

Copilot uses AI. Check for mistakes.
Comment on lines 34 to 38
const alreadyExists = state.requiredSigners.some(
(existing) =>
existing.hash.length === params.keyHash.hash.length &&
existing.hash.every((b, i) => b === params.keyHash.hash[i])
)
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deduplication logic performs a byte-by-byte comparison instead of using the KeyHash's built-in equality check. The KeyHash class likely has an [Equal.symbol] method that should be used instead. Replace this manual comparison with Equal.equals(existing, params.keyHash) from the effect library for consistency and correctness.

Copilot uses AI. Check for mistakes.
import type * as Network from "../../core/Network.js"
import type * as RewardAccount from "../../core/RewardAccount.js"
import type * as CoreScript from "../../core/Script.js"
import * as Script from "../../core/Script.js"
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import Script.

Copilot uses AI. Check for mistakes.
import * as Script from "../../core/Script.js"
import * as Time from "../../core/Time/index.js"
import * as Transaction from "../../core/Transaction.js"
import * as TransactionHash from "../../core/TransactionHash.js"
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import TransactionHash.

Copilot uses AI. Check for mistakes.
import type * as CoreUTxO from "../../core/UTxO.js"
import * as CoreUTxO from "../../core/UTxO.js"
import { runEffectPromise } from "../../utils/effect-runtime.js"
import { hashTransaction } from "../../utils/Hash.js"
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import hashTransaction.

Copilot uses AI. Check for mistakes.
…ipts

- Include reference script bytes in transaction size for base fee
- Apply tiered pricing separately (15/25/100 lovelace per byte)
- Fix native script detection in reference inputs for redeemer validation
- Use Equal.equals() for KeyHash deduplication in AddSigner
@solidsnakedev solidsnakedev merged commit f4f6ac3 into main Dec 23, 2025
5 checks passed
@solidsnakedev solidsnakedev deleted the feat/add-tx-chaining branch December 23, 2025 21:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants