Skip to content

feat: add Arbitrum USDT wallet with USDT fees - #157

Open
ben-kaufman wants to merge 9 commits into
masterfrom
feat/usdt-arbitrum
Open

ben-kaufman wants to merge 9 commits into
masterfrom
feat/usdt-arbitrum

Conversation

@ben-kaufman

@ben-kaufman ben-kaufman commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Adds USDT0 support on Arbitrum One to Bitkit Core, allowing users to receive and send USDT and pay transaction fees in USDT without holding ETH.

  • Derives an EIP-7702 account from the wallet's existing mnemonic and optional passphrase.
  • Provides balance, receive-address/payment-request, fee-quote, signing and activity APIs through UniFFI for the native apps.
  • Quotes a maximum USDT fee and validates the approved payment before signing. Signed operations are saved before submission so an interrupted or uncertain response does not lose the payment.
  • Recovers pending payments after restart and reconstructs incoming and outgoing activity from chain history after seed restoration. Activity includes payment status and fees where they can be attributed.

This PR covers direct Arbitrum payments. Native UI and the backend that protects provider credentials are maintained separately. Outbound bridging is added in #158; inbound deposits from other networks are added in #159.

QA Notes

  • Run cargo test --locked --lib modules::usdt, cargo fmt --check and cargo clippy --locked --lib --tests.
  • Coverage includes address/signature vectors, payment-request parsing, fee limits, uncertain submission, nonce recovery and restored history. An opt-in Arbitrum fork test exercises deployed contracts and USDT fee collection with zero account ETH.
  • Native-app mainnet testing has exercised send/receive, USDT-paid fees, and restart/seed recovery. Deployment and physical-device release validation remain separate requirements.
  • Chain history and payment outcomes depend on the configured RPC provider. A receipt at the current Arbitrum tip establishes L2 execution, not Ethereum finality.
  • Release packaging targets unpublished v0.6.0. Before remote package consumption, build the selected merged source, record the final SwiftPM checksum in a release-preparation commit, and tag/publish that exact iOS archive and matching Android package. Use matching local artifacts for branch testing; later stack layers must use a new version if an earlier layer has already been released.

@ben-kaufman ben-kaufman changed the title feat: add USDT0 wallet support on Arbitrum feat: add Arbitrum USDT wallet with USDT fees Sep 24, 2026
@ben-kaufman
ben-kaufman marked this pull request as ready for review September 25, 2026 12:45
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-25T13:16:03.158749Z 1f805f1 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1f805f1091

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +370 to +374
if let Ok(call) = Erc20::transferCall::abi_decode(&data) {
if payment.is_some() {
return None;
}
payment = Some((call.recipient, token_amount(call.amount).ok()?));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject zero-value and self-transfer restored payments

When restoring a supported operation created by another wallet, decode_payment accepts any decoded transfer, including a zero amount or a recipient equal to the wallet address. The raw-log path explicitly discards those transfers, and locally quoted payments prohibit them, but this calldata enrichment path reintroduces them as confirmed outgoing activity, so restoring the same seed can display a spurious payment (and collapse its other raw debits into that entry). Apply the same zero/self-transfer checks before returning the decoded payment.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in ccdd478 and propagated to #158 and #159. Restore now excludes zero-value and self-directed ERC-20 transfers from decoded payments, preserving the raw fee debits and refunds.

I extended the existing raw-movement restoration test with both cases. It failed before the fix and now passes. All three USDT suites pass locally (48/54/60 tests), along with formatting, clippy and the iOS artifact checks. No signing, storage-schema or public API changes.

@ovi-reviewer ovi-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Advice: ✅ Approve


Review: diff 33 files.

Findings:
1 inline (non-blocking)

Audit:
Audited - no findings.

Coverage:
QA: the tests under "QA Notes" need a person; no approval follows from this review


Reviewed by gpt-6-sol-xhigh via gh-pr-review-loop skill
Commands: @ovi-reviewer review · test · retest · audit (author or owner) · wrong <why> (owner)

self.address.to_checksum(None)
}

pub fn receive_uri(&self) -> String {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The new receive_uri() creates the payment request, but the tests parse a separately formatted string instead of testing this method. A broken QR value could go unnoticed. Could we check that parsing receive_uri() returns this wallet’s address and chain?

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.

1 participant