Skip to content

feat(sdk): expose OP_RETURN, output-order and change-to-VIN0 controls - #4286

Open
romchornyi wants to merge 1 commit into
v4.2-devfrom
feat/maya-op-return
Open

feat(sdk): expose OP_RETURN, output-order and change-to-VIN0 controls#4286
romchornyi wants to merge 1 commit into
v4.2-devfrom
feat/maya-op-return

Conversation

@romchornyi

@romchornyi romchornyi commented Aug 4, 2026

Copy link
Copy Markdown

Issue being fixed or feature implemented

The Dash iOS wallet is restoring MAYACHAIN swap routes, which requires the DASH
deposit to carry the swap memo in an OP_RETURN. CoreTransactionBuilder could
not express that, so Maya was disabled during the DashSync unlink.

MAYAChain's UTXO deposit contract (docs,
"UTXO Chains") demands a specific shape: VOUT0 = Asgard vault, VOUT1 = the
memo as a zero-value OP_RETURN, VOUT2 = change paid back to the VIN0
address
, and no output reordering. The change rule matters because MAYAChain
identifies the depositor by VIN0 and pays refunds there — routing change to a
fresh HD address fails silently, with only a later refund going astray.

Because finalize/build_signed fund and sign inside a single FFI call, none of
this can be applied after the fact. It has to be expressible on the builder.

What was done?

  • packages/rs-platform-wallet-ffi/src/core_wallet/transaction_builder.rs:
    core_wallet_tx_builder_add_op_return, ..._preserve_output_order and
    ..._change_to_first_input, following the existing setter style. An over-long
    payload is rejected before take_builder() runs, so a refused memo cannot
    leave the slot holding a mem::take default and silently drop outputs the
    caller already configured.
  • packages/rs-platform-wallet-ffi/src/core_wallet/broadcast.rs:
    core_wallet_signed_transaction_v2_bytes — read a finalized transaction's
    bytes without broadcasting, so the deposit shape can be asserted pre-broadcast.
  • packages/swift-sdk/.../CoreTransactionBuilder.swift: addOpReturn(_:),
    preserveOutputOrder(), changeToFirstInput(), and
    FinalizedCoreTransaction.serializedData().
  • .github/workflows/tests-rs-workspace.yml: fail the workflow if a local
    [patch."https://github.com/dashpay/rust-dashcore"] override is left in
    Cargo.toml — that override is invisible in review and produces a build that
    only works on one machine.

Depends on dashpay/rust-dashcore#922, which adds the underlying add_op_return,
preserve_output_order and change_to_first_input to key-wallet. Until that
merges and the rev in Cargo.toml is bumped, building this locally needs the
patch override — deliberately not committed, which is what the new CI guard
enforces.

How Has This Been Tested?

Added packages/swift-sdk/SwiftTests/SwiftDashSDKIntegrationTests/Core/MayaDepositVerificationIntegrationTests.swift,
which builds short- and long-memo deposits against a local dashmate devnet and
asserts output count and order, the OP_RETURN payload, VOUT2 == VIN0
scriptPubKey, the 80-byte memo ceiling, Maya's dust floor and a ≥ 1 duff/byte
fee — then checks fee parity for ordinary, multi-recipient, selected-input,
drain and asset-lock shapes so the precise output sizing does not move existing
fees.

Also verified: cargo check -p platform-wallet-ffi,
./build_ios.sh --target ios --target sim, and a green dashpay build of the
consuming wallet app.

Known gap: the integration test currently stalls in SPV bootstrap on a
22k-block devnet (compact filters lag past the 180 s wait) and has not yet run
its assertions end to end.

Breaking Changes

None. All three builder controls are opt-in and default behaviour is unchanged.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

  • New Features
    • Added support for including OP_RETURN data in wallet transactions.
    • Added options to preserve transaction output order and route change to the first selected input.
    • Added the ability to retrieve serialized bytes from finalized transactions without consuming them.
    • Improved validation and error reporting for invalid transaction data and oversized OP_RETURN payloads.

…trols

MAYAChain requires a UTXO deposit shaped as VOUT0=vault, VOUT1=OP_RETURN memo,
VOUT2=change paid back to the VIN0 address, with no output reordering, and it
identifies the depositor by VIN0 for refunds.
https://docs.mayaprotocol.com/mayachain-dev-docs/concepts/sending-transactions

`CoreTransactionBuilder.buildSigned` builds and signs in one FFI call, so none
of this can be applied after the fact — it has to be expressed on the builder.

FFI (rs-platform-wallet-ffi):
- core_wallet_tx_builder_add_op_return / _preserve_output_order /
  _change_to_first_input, mirroring the existing setter style
- an over-long payload is rejected before take_builder() runs, so a refused memo
  cannot leave the slot holding a mem::take default and silently drop outputs
  the caller already configured
- core_wallet_signed_transaction_v2_bytes: read the finalized transaction bytes
  without broadcasting, so the deposit shape can be asserted pre-broadcast

Swift SDK:
- addOpReturn / preserveOutputOrder / changeToFirstInput
- FinalizedCoreTransaction.serializedData()

Tests: MayaDepositVerificationIntegrationTests builds short- and long-memo
deposits and asserts output count/order, the OP_RETURN payload, VOUT2 == VIN0
scriptPubKey, the memo ceiling, the dust floor and a >= 1 duff/byte fee, then
checks fee parity for ordinary, multi-recipient, selected-input, drain and
asset-lock shapes so the precise output sizing does not move existing fees.

CI: fail the workspace workflow if the local rust-dashcore [patch] override is
still present in Cargo.toml.

Depends on key-wallet gaining add_op_return / preserve_output_order /
change_to_first_input (dashpay/rust-dashcore, branch feat/tx-builder-op-return).
Until that lands and the rev in Cargo.toml is bumped, building this needs a
local [patch] override, which is deliberately NOT committed.
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds finalized V2 transaction serialization, OP_RETURN and output-routing controls across the Rust FFI and Swift SDK, and integration tests for Maya deposits and fee parity. The macOS workflow rejects local rust-dashcore patch overrides.

Changes

Core wallet transaction flow

Layer / File(s) Summary
Finalized transaction serialization
packages/rs-platform-wallet-ffi/src/core_wallet/broadcast.rs, packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWallet/CoreTransactionBuilder.swift
The FFI returns owned consensus bytes for finalized V2 transactions. Swift exposes them as copied Data.
Transaction builder controls
packages/rs-platform-wallet-ffi/src/core_wallet/transaction_builder.rs, packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWallet/CoreTransactionBuilder.swift
The builder supports OP_RETURN outputs, output-order preservation, and change routing to the first selected input.
Maya deposit and fee verification
packages/swift-sdk/SwiftTests/SwiftDashSDKIntegrationTests/Core/MayaDepositVerificationIntegrationTests.swift
Integration tests validate deposit structure, memo encoding, UTXO selection, transaction decoding, and fee parity across multiple transaction shapes.

Workspace validation

Layer / File(s) Summary
macOS patch override guard
.github/workflows/tests-rs-workspace.yml
The macOS workflow fails when Cargo.toml contains a local rust-dashcore patch override.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MayaDepositVerificationIntegrationTests
  participant CoreTransactionBuilder
  participant CoreWalletFFI
  participant SPVWallet
  MayaDepositVerificationIntegrationTests->>SPVWallet: fund wallet and select UTXOs
  MayaDepositVerificationIntegrationTests->>CoreTransactionBuilder: build deposit transaction
  CoreTransactionBuilder->>CoreWalletFFI: add OP_RETURN and configure outputs
  CoreWalletFFI-->>CoreTransactionBuilder: finalize transaction
  CoreTransactionBuilder-->>MayaDepositVerificationIntegrationTests: return transaction
  MayaDepositVerificationIntegrationTests->>SPVWallet: decode transaction and calculate fee
  SPVWallet-->>MayaDepositVerificationIntegrationTests: transaction data and fee

Loading

Possibly related PRs

  • dashpay/platform#4185: Shares FFI transaction-builder and broadcast code for signed-payment finalization and broadcasting.

Suggested reviewers: llbartekll, shumkov, quantumexplorer

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main SDK and FFI controls added for OP_RETURN outputs, output order, and VIN0 change routing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/maya-op-return

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@thepastaclaw

thepastaclaw commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

🔍 Review in progress — actively reviewing now (commit 6f70092)
Stage: Codex precheck starting
ETA: complete ~17:54 UTC (median 23m across 30 recent reviews)
Running 9m · Last checked: 2026-08-04 17:40 UTC

@codecov

codecov Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.54%. Comparing base (f53e5ee) to head (6f70092).
⚠️ Report is 1 commits behind head on v4.2-dev.

Additional details and impacted files
@@             Coverage Diff              @@
##           v4.2-dev    #4286      +/-   ##
============================================
+ Coverage     87.52%   87.54%   +0.01%     
============================================
  Files          2678     2679       +1     
  Lines        341047   341467     +420     
============================================
+ Hits         298518   298933     +415     
- Misses        42529    42534       +5     
Components Coverage Δ
dpp 88.55% <ø> (+0.06%) ⬆️
drive 86.26% <ø> (ø)
drive-abci 89.56% <ø> (-0.01%) ⬇️
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.88% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 49.60% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/rs-platform-wallet-ffi/src/core_wallet/transaction_builder.rs (1)

311-321: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Restore the builder when add_op_return fails.

take_builder() replaces the stored TransactionBuilder with the mem::take default. If b.add_op_return(bytes) returns Err, b is dropped and the slot keeps that default, so later builder operations or finalization are no longer based on previously configured inputs, outputs, and options. TransactionBuilder does not derive Clone, so the error path needs to avoid requiring b.clone() unless this dependency is changed to support it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/rs-platform-wallet-ffi/src/core_wallet/transaction_builder.rs`
around lines 311 - 321, Update the add_op_return error path in the
transaction-building method to restore the original TransactionBuilder into the
shared builder slot before returning the error. Preserve b without cloning,
store it through the existing store_builder mechanism on failure, and keep the
current error result unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/swift-sdk/SwiftTests/SwiftDashSDKIntegrationTests/Core/MayaDepositVerificationIntegrationTests.swift`:
- Around line 147-158: Guard all transaction collection accesses in the
verification flow before indexing: replace direct access to decoded.outputs[1],
decoded.outputs[0], and decoded.inputs[0] with safe first-element handling via
XCTUnwrap or equivalent count assertions. Ensure malformed transaction shapes
produce readable XCTest failures before evaluating opReturnPayload or
findMatchedUTXO, while preserving the existing outputTwoMatchesInputZeroScript
logic.
- Around line 55-57: Prevent testPrompt04StaticProofAndLegacyFeeParity from
hanging local Swift SDK CI by skipping it or splitting it so the long SPV
bootstrap and waitForSpendable flow is not run by the enabled run_tests.sh suite
until bootstrap stalls are resolved; do not add a local stopSpv call because
IntegrationTestCase.tearDown and suite cleanup already handle SPV teardown.

---

Nitpick comments:
In `@packages/rs-platform-wallet-ffi/src/core_wallet/transaction_builder.rs`:
- Around line 311-321: Update the add_op_return error path in the
transaction-building method to restore the original TransactionBuilder into the
shared builder slot before returning the error. Preserve b without cloning,
store it through the existing store_builder mechanism on failure, and keep the
current error result unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b079eaf5-5ec2-4fda-b22a-a9b48a57753f

📥 Commits

Reviewing files that changed from the base of the PR and between 97904ed and 6f70092.

📒 Files selected for processing (5)
  • .github/workflows/tests-rs-workspace.yml
  • packages/rs-platform-wallet-ffi/src/core_wallet/broadcast.rs
  • packages/rs-platform-wallet-ffi/src/core_wallet/transaction_builder.rs
  • packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWallet/CoreTransactionBuilder.swift
  • packages/swift-sdk/SwiftTests/SwiftDashSDKIntegrationTests/Core/MayaDepositVerificationIntegrationTests.swift

Comment on lines +55 to +57
func testPrompt04StaticProofAndLegacyFeeParity() async throws {
try env.walletManager.startSpv(config: env.spvConfig)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether integration tests run in CI and how SPV is torn down.
fd -t f -e yml -e yaml . .github/workflows | xargs -r rg -nP -C4 'SwiftDashSDKIntegrationTests|swift test'
fd -t f 'IntegrationTestCase.swift' | xargs -r rg -nP -C6 '(func tearDown|stopSpv|startSpv)'

Repository: dashpay/platform

Length of output: 505


🏁 Script executed:

#!/bin/bash
set -e

echo "== workflow files =="
git ls-files .github/workflows | sed -n '1,120p'

echo
echo "== Swift test / SwiftDashSDKIntegrationTests references =="
rg -n -C3 'SwiftDashSDKIntegrationTests|swift-sdk|swift test|integration' .github packages/swift-sdk --glob '*.yml' --glob '*.yaml' --glob '*.swift' || true

echo
echo "== relevant swift test file slice =="
file="packages/swift-sdk/SwiftTests/SwiftDashSDKIntegrationTests/Core/MayaDepositVerificationIntegrationTests.swift"
if [ -f "$file" ]; then
  wc -l "$file"
  sed -n '1,180p' "$file"
fi

echo
echo "== integration test case references =="
rg -n -C8 'class IntegrationTestCase|open class IntegrationTestCase|func tearDown|func setUp|stopSpv|startSpv|wallet.*90|spendable|startSpv' packages/swift-sdk --glob '*.swift' || true

Repository: dashpay/platform

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -e

echo "== locate IntegrationTestCase and relevant test file =="
fd -t f 'IntegrationTestCase.swift|MayaDepositVerificationIntegrationTests.swift' packages/swift-sdk | sort

echo
echo "== IntegrationTestCase.swift =="
file="$(fd -t f 'IntegrationTestCase.swift' packages/swift-sdk | head -n1)"
if [ -n "$file" ]; then
  wc -l "$file"
  sed -n '1,180p' "$file"
fi

echo
echo "== targeted startSpv/stopSpv in IntegrationTestCase and MayaDeposit file =="
for f in $(fd -t f 'IntegrationTestCase.swift|MayaDepositVerificationIntegrationTests.swift' packages/swift-sdk); do
  echo "-- $f --"
  rg -n -C4 'class IntegrationTestCase|open class IntegrationTestCase|func setUp|func tearDown|async.*setUp|async.*tearDown|startSpv|stopSpv|restartWalletManager|resetState|skipIfDisabled' "$f" || true
done

echo
echo "== CI workflow names containing Swift or package names =="
python3 - <<'PY'
import os, re
root=".github/workflows"
matches=[]
for fn in sorted(os.listdir(root)):
    path=os.path.join(root,fn)
    if not os.path.isfile(path) or fn not in ('workflow' in fn or fn.endswith('.yml') or fn.endswith('.yaml')):
        pass
    try:
        data=open(path,encoding='utf-8').read()
    except Exception:
        continue
    if re.search(r'SwiftDashSDKIntegrationTests|swift-sdk|swift test', data):
        matches.append((fn, len([l for l in data.splitlines() if re.search(r'SwiftDashSDKIntegrationTests|swift-sdk|swift test', l)])))
print('\n'.join(f"{n} {c}" for n,c in matches))
# Print focused lines for matches, bounded.
for fn, _ in matches:
    print(f"\n--- {fn} ---")
    out=os.popen(f"rg -n -C3 'SwiftDashSDKIntegrationTests|swift-sdk|swift test' .github/workflows/{fn}").read()
    print(out or "(no focused lines)")
PY

Repository: dashpay/platform

Length of output: 4991


🏁 Script executed:

#!/bin/bash
set -e

echo "== targeted workflow contents for SwiftDashSDKIntegrationTests =="
rg -n -C4 'SwiftDashSDKIntegrationTests|swift test|Swif(.*?)test|integration tests|RUN_INTEGRATION_TESTS' .github/workflows || echo "no matches found"

echo
echo "== workflow files list =="
git ls-files .github/workflows | sort

Repository: dashpay/platform

Length of output: 3239


🏁 Script executed:

#!/bin/bash
set -e

echo "== swift-sdk-build.yml relevant lines =="
wc -l .github/workflows/swift-sdk-build.yml
sed -n '1,240p' .github/workflows/swift-sdk-build.yml

echo
echo "== swift-sdk package files mentioning tests/enablers =="
rg -n -C3 'RUN_INTEGRATION_TESTS|SwiftDashSDKIntegrationTests|swift-sdk-build|swift test|test' packages/swift-sdk .github -g '!**/*.swift' || true

Repository: dashpay/platform

Length of output: 50375


Keep this test from hanging in local Swift SDK CI runs.

This test is enabled by packages/swift-sdk/run_tests.sh, and CI runs that script for swift-sdk-build. It waits on multiple 90-second waitForSpendable windows, so a bootstrap stall before assertions can hang the local Swift SDK test job. Skip or split it until the SPV bootstrap path does not stall.

startSpv does not require a local stopSpv because IntegrationTestCase.tearDown calls env.resetState(), and the Swift bundle observer calls cleanupSpvCache() at suite end.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/swift-sdk/SwiftTests/SwiftDashSDKIntegrationTests/Core/MayaDepositVerificationIntegrationTests.swift`
around lines 55 - 57, Prevent testPrompt04StaticProofAndLegacyFeeParity from
hanging local Swift SDK CI by skipping it or splitting it so the long SPV
bootstrap and waitForSpendable flow is not run by the enabled run_tests.sh suite
until bootstrap stalls are resolved; do not add a local stopSpv call because
IntegrationTestCase.tearDown and suite cleanup already handle SPV teardown.

Comment on lines +147 to +158
let decoded = try TransactionDecoder.decode(txData, network: .regtest)
let memoOutput = decoded.outputs[1]
let decodedMemoData = try XCTUnwrap(opReturnPayload(from: memoOutput.scriptPubkey))
let decodedMemo = try XCTUnwrap(String(data: decodedMemoData, encoding: .utf8))

let inputZeroMatch = try findMatchedUTXO(for: decoded.inputs[0], in: utxosBeforeBuild)
let outputTwoMatchesInputZeroScript: Bool
if decoded.outputs.count == 3 {
outputTwoMatchesInputZeroScript = decoded.outputs[2].scriptPubkey == inputZeroMatch.scriptPubkey
} else {
outputTwoMatchesInputZeroScript = false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard the output and input counts before indexing.

decoded.outputs[1], decoded.outputs[0], and decoded.inputs[0] are indexed without a count check. If the builder returns fewer outputs or inputs than expected, the subscript traps and the whole test process crashes. The shape assertions in assertDepositObservation at Lines 181-182 run only after this indexing, so they cannot catch the case.

Use XCTUnwrap on first, or assert the counts here before indexing, so a wrong shape produces a readable test failure.

🛡️ Proposed fix
         let decoded = try TransactionDecoder.decode(txData, network: .regtest)
+        try XCTSkipIf(false)
+        guard decoded.outputs.count >= 2, !decoded.inputs.isEmpty else {
+            throw NSError(domain: "MayaVerification", code: 6, userInfo: [
+                NSLocalizedDescriptionKey:
+                    "Unexpected deposit shape: \(decoded.inputs.count) inputs, \(decoded.outputs.count) outputs"
+            ])
+        }
         let memoOutput = decoded.outputs[1]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let decoded = try TransactionDecoder.decode(txData, network: .regtest)
let memoOutput = decoded.outputs[1]
let decodedMemoData = try XCTUnwrap(opReturnPayload(from: memoOutput.scriptPubkey))
let decodedMemo = try XCTUnwrap(String(data: decodedMemoData, encoding: .utf8))
let inputZeroMatch = try findMatchedUTXO(for: decoded.inputs[0], in: utxosBeforeBuild)
let outputTwoMatchesInputZeroScript: Bool
if decoded.outputs.count == 3 {
outputTwoMatchesInputZeroScript = decoded.outputs[2].scriptPubkey == inputZeroMatch.scriptPubkey
} else {
outputTwoMatchesInputZeroScript = false
}
let decoded = try TransactionDecoder.decode(txData, network: .regtest)
try XCTSkipIf(false)
guard decoded.outputs.count >= 2, !decoded.inputs.isEmpty else {
throw NSError(domain: "MayaVerification", code: 6, userInfo: [
NSLocalizedDescriptionKey:
"Unexpected deposit shape: \(decoded.inputs.count) inputs, \(decoded.outputs.count) outputs"
])
}
let memoOutput = decoded.outputs[1]
let decodedMemoData = try XCTUnwrap(opReturnPayload(from: memoOutput.scriptPubkey))
let decodedMemo = try XCTUnwrap(String(data: decodedMemoData, encoding: .utf8))
let inputZeroMatch = try findMatchedUTXO(for: decoded.inputs[0], in: utxosBeforeBuild)
let outputTwoMatchesInputZeroScript: Bool
if decoded.outputs.count == 3 {
outputTwoMatchesInputZeroScript = decoded.outputs[2].scriptPubkey == inputZeroMatch.scriptPubkey
} else {
outputTwoMatchesInputZeroScript = false
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/swift-sdk/SwiftTests/SwiftDashSDKIntegrationTests/Core/MayaDepositVerificationIntegrationTests.swift`
around lines 147 - 158, Guard all transaction collection accesses in the
verification flow before indexing: replace direct access to decoded.outputs[1],
decoded.outputs[0], and decoded.inputs[0] with safe first-element handling via
XCTUnwrap or equivalent count assertions. Ensure malformed transaction shapes
produce readable XCTest failures before evaluating opReturnPayload or
findMatchedUTXO, while preserving the existing outputTwoMatchesInputZeroScript
logic.

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.

3 participants