Skip to content

feat: USDC trustline setup for smart wallet#195

Merged
KevinMB0220 merged 1 commit intoGalaxy-KJ:mainfrom
Bosun-Josh121:feat/usdc-trustline-setup-smart-wallet
Mar 29, 2026
Merged

feat: USDC trustline setup for smart wallet#195
KevinMB0220 merged 1 commit intoGalaxy-KJ:mainfrom
Bosun-Josh121:feat/usdc-trustline-setup-smart-wallet

Conversation

@Bosun-Josh121
Copy link
Copy Markdown
Contributor

@Bosun-Josh121 Bosun-Josh121 commented Mar 28, 2026

Pull Request

📋 Description

Adds USDC trustline support to the Smart Wallet. Introduces setupUSDCTrustline() as a standalone method and integrates it optionally into the deploy() flow via an autoTrustlineUSDC flag. The method builds an unsigned fee-less ChangeTrust transaction for USDC on the user's classic Stellar account, returning XDR for the fee sponsorship workflow.

🔗 Related Issues

Closes #177

🧪 Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing completed
  • All tests passing locally

📚 Documentation Updates (Required)

  • Updated docs/AI.md with new patterns/examples
  • Updated API reference in relevant package README
  • Added/updated code examples
  • Updated ARCHITECTURE.md (if architecture changed)
  • Added inline JSDoc/TSDoc comments
  • Updated ROADMAP.md progress (mark issue as completed)

Documentation Checklist by Component:

If you modified packages/core/stellar-sdk/:

  • Updated packages/core/stellar-sdk/README.md
  • Added examples to docs/examples/stellar-sdk/
  • Updated type definitions documentation

If you modified packages/core/invisible-wallet/:

  • Updated packages/core/invisible-wallet/README.md
  • Added security notes to docs/SECURITY.md
  • Updated wallet flow diagrams in docs/ARCHITECTURE.md

If you modified packages/core/automation/:

  • Updated packages/core/automation/README.md
  • Added automation examples to docs/examples/automation/
  • Updated trigger/action types in docs

If you modified packages/core/defi-protocols/:

  • Updated packages/core/defi-protocols/README.md
  • Added protocol integration guide
  • Updated DeFi architecture section in docs/ARCHITECTURE.md

If you modified packages/core/oracles/:

  • Updated packages/core/oracles/README.md
  • Added oracle source documentation
  • Updated price feed examples

If you modified packages/contracts/:

  • Added Rust documentation comments (///)
  • Updated contract README with deployment instructions
  • Added contract interaction examples

If you modified tools/cli/:

  • Updated CLI command documentation
  • Added command examples to README
  • Updated help text in command definitions

🤖 AI-Friendly Documentation

New Files Created

No new files created — all changes are additions to existing files:
- packages/core/wallet/src/types/smart-wallet.types.ts - Added USDC_ISSUERS, USDCNetwork, DeployWithTrustlineOptions, DeployResult
- packages/core/wallet/src/smart-wallet.service.ts - Added setupUSDCTrustline() method and deploy() overloads
- packages/core/wallet/src/tests/smart-wallet.service.test.ts - Added 11 tests covering new method and deploy option

Key Functions/Classes Added

// packages/core/wallet/src/types/smart-wallet.types.ts

export const USDC_ISSUERS = {
  testnet: 'GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
  mainnet: 'GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
} as const;

export type USDCNetwork = keyof typeof USDC_ISSUERS;

export interface DeployWithTrustlineOptions {
  autoTrustlineUSDC: true;
  usdcNetwork: USDCNetwork;
  accountId: string; // Classic Stellar G-address
}

export interface DeployResult {
  contractAddress: string;
  trustlineXdr: string; // Unsigned fee-less XDR (base64)
}

// packages/core/wallet/src/smart-wallet.service.ts

async setupUSDCTrustline(
  accountId: string,
  network: USDCNetwork
): Promise<string> // returns unsigned fee-less XDR (base64)

// Backward-compatible overloads
async deploy(publicKey65Bytes: Uint8Array, factory?: string, network?: Networks | string): Promise<string>;
async deploy(publicKey65Bytes: Uint8Array, factory: string | undefined, network: Networks | string | undefined, options: DeployWithTrustlineOptions): Promise<DeployResult>;

Patterns Used

  • Fee-less XDR pattern: setupUSDCTrustline() follows the same pattern as all other service methods — returns unsigned base64 XDR for a fee sponsor to complete. The classic account must still sign before submission.
  • TypeScript overloads for backward compatibility: deploy() uses two overload signatures so existing callers receive Promise<string> unchanged; callers passing DeployWithTrustlineOptions receive Promise<DeployResult>.
  • server.getAccount() for classic transactions: Unlike Soroban simulation flows that use getLatestLedger(), classic Stellar transactions require the real account sequence number via getAccount().
  • Network-scoped issuer resolution: USDC_ISSUERS is a const object keyed by 'testnet' | 'mainnet'; extend this object to support new networks rather than adding conditional logic.

N/A — no UI changes.

⚠️ Breaking Changes

  • No breaking changes
  • Breaking changes documented in CHANGELOG.md

🔄 Deployment Notes

No special deployment steps. USDC issuers are hardcoded constants — no environment variables required.

✅ Final Checklist

  • Code follows project style guidelines
  • Self-review completed
  • No console.log or debug code left
  • Error handling implemented
  • Performance considered
  • Security reviewed
  • Documentation updated (required)
  • ROADMAP.md updated with progress

By submitting this PR, I confirm that:

  • ✅ I have updated all relevant documentation
  • ✅ AI.md includes new patterns from my changes
  • ✅ Examples are provided for new features
  • ✅ The documentation is accurate and helpful for AI assistants and developers

Summary by CodeRabbit

  • New Features
    • Added USDC trustline setup capability during wallet deployment
    • Support for both testnet and mainnet networks
    • Deployment method now optionally returns trustline transaction data alongside contract address for streamlined USDC integration

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 28, 2026

📝 Walkthrough

Walkthrough

This PR implements USDC trustline setup for Smart Wallets by adding a setupUSDCTrustline() method to SmartWalletService and extending the deploy() method with optional trustline configuration through TypeScript overloads. The implementation resolves USDC issuers for testnet and mainnet, builds unsigned ChangeTrust transactions, and returns base64 XDR. Supporting types, mocks, and test coverage are included.

Changes

Cohort / File(s) Summary
Type Definitions & Constants
packages/core/wallet/src/types/smart-wallet.types.ts
Added USDC_ISSUERS constant with testnet/mainnet issuer addresses, USDCNetwork union type, DeployWithTrustlineOptions interface for deploy configuration, and DeployResult interface for trustline+contract return value.
Service Implementation
packages/core/wallet/src/smart-wallet.service.ts
Added setupUSDCTrustline(accountId, network) method that retrieves account sequence from Horizon, builds unsigned ChangeTrust operation for USDC, and returns transaction XDR as base64. Extended deploy() with method overloads to optionally accept DeployWithTrustlineOptions and conditionally return either a contract address string or DeployResult object containing address and trustline XDR.
Test Coverage & Mocks
packages/core/wallet/src/tests/smart-wallet.service.test.ts
Extended Jest mocks for TransactionBuilder.build(), added Asset and Operation.changeTrust() mocks, and updated Server fixture with getAccount(). Added comprehensive test cases for setupUSDCTrustline() (testnet/mainnet validation, XDR return, error handling) and deploy() with trustline options (DeployResult structure, method invocation, backward compatibility).

Sequence Diagram

sequenceDiagram
    participant Client
    participant SmartWalletService
    participant HorizonServer as Horizon Server
    participant StellarSDK as Stellar SDK

    Client->>SmartWalletService: setupUSDCTrustline(accountId, network)
    SmartWalletService->>HorizonServer: getAccount(accountId)
    HorizonServer-->>SmartWalletService: account with sequence number
    SmartWalletService->>SmartWalletService: resolve USDC issuer for network
    SmartWalletService->>StellarSDK: Asset('USDC', issuer)
    StellarSDK-->>SmartWalletService: USDC asset object
    SmartWalletService->>StellarSDK: Operation.changeTrust({asset})
    StellarSDK-->>SmartWalletService: changeTrust operation
    SmartWalletService->>StellarSDK: TransactionBuilder.build()
    StellarSDK-->>SmartWalletService: transaction envelope
    SmartWalletService->>SmartWalletService: envelope.toXDR() base64
    SmartWalletService-->>Client: return trustlineXdr string
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related issues

  • [FEATURE] USDC Trustline setup for Smart Wallets #177 - Directly addresses the USDC trustline setup feature requirements, including the setupUSDCTrustline() method, testnet/mainnet issuer support, and optional autoTrustlineUSDC flag in deploy options, all implemented by this PR.

Possibly related PRs

Suggested reviewers

  • KevinMB0220

Poem

🐰 A trustline blooms, with USDC in sight,
ChangeTrust operations, perfectly right!
From testnet to mainnet, we hop with care,
XDR strings floating through Stellar's air! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: USDC trustline setup for smart wallet' clearly and concisely describes the main feature addition.
Description check ✅ Passed PR description covers the main objective, testing status, and includes detailed AI-friendly documentation with patterns and function signatures, though several documentation checklist items remain unchecked.
Linked Issues check ✅ Passed The PR implements all core requirements: setupUSDCTrustline() method, testnet/mainnet USDC issuer support, deploy() integration with autoTrustlineUSDC option, server.getAccount() for sequence, and comprehensive unit tests covering the trustline behavior.
Out of Scope Changes check ✅ Passed All code changes are scoped to the USDC trustline feature: type definitions, setupUSDCTrustline() implementation, deploy() overloads, and corresponding test coverage with no unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/core/wallet/src/smart-wallet.service.ts (1)

1152-1157: Docstring mentions "fee-less" but the transaction includes BASE_FEE.

The documentation states the returned XDR is "unsigned fee-less," but line 1189 sets fee: BASE_FEE. While this may work correctly in practice (sponsors can adjust fees), consider clarifying the docstring to avoid confusion, or explicitly set fee: '0' if truly fee-less behavior is intended.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/wallet/src/smart-wallet.service.ts` around lines 1152 - 1157,
The docstring claims the returned XDR is "unsigned fee-less" but the transaction
is created with fee: BASE_FEE; either update the docstring to remove or clarify
"fee-less" semantics (e.g., "unsigned; default base fee set but sponsor may
replace") or change the transaction creation to use fee: '0' (or 0) if you truly
want a zero-fee unsigned ChangeTrust XDR; locate the code that sets fee:
BASE_FEE and the surrounding comment block and apply the chosen fix consistently
so the docstring and the transaction fee value match.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/wallet/src/smart-wallet.service.ts`:
- Around line 1183-1194: The transaction uses this.network (service-wide
passphrase) while the USDC issuer is selected from USDC_ISSUERS[network],
causing a mismatch if the method's network param differs from the service
config; update the code in setupUSDCTrustline (or the function creating the
transaction) to derive a network passphrase from the method parameter (e.g.,
const networkPassphrase = network === 'testnet' ? Networks.TESTNET :
Networks.PUBLIC) and pass that into new TransactionBuilder(..., {
networkPassphrase }) so the TransactionBuilder uses the same network as the
USDC_ISSUERS lookup; also add an import for Networks from the Stellar SDK if not
already present.

---

Nitpick comments:
In `@packages/core/wallet/src/smart-wallet.service.ts`:
- Around line 1152-1157: The docstring claims the returned XDR is "unsigned
fee-less" but the transaction is created with fee: BASE_FEE; either update the
docstring to remove or clarify "fee-less" semantics (e.g., "unsigned; default
base fee set but sponsor may replace") or change the transaction creation to use
fee: '0' (or 0) if you truly want a zero-fee unsigned ChangeTrust XDR; locate
the code that sets fee: BASE_FEE and the surrounding comment block and apply the
chosen fix consistently so the docstring and the transaction fee value match.
🪄 Autofix (Beta)

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 22a10759-ef15-4304-bcb8-d26f414fd581

📥 Commits

Reviewing files that changed from the base of the PR and between 32dda93 and d49141d.

📒 Files selected for processing (3)
  • packages/core/wallet/src/smart-wallet.service.ts
  • packages/core/wallet/src/tests/smart-wallet.service.test.ts
  • packages/core/wallet/src/types/smart-wallet.types.ts

Comment on lines +1183 to +1194
const issuer = USDC_ISSUERS[network];
const usdcAsset = new Asset('USDC', issuer);

const account = await this.server.getAccount(accountId);

const tx = new TransactionBuilder(account, {
fee: BASE_FEE,
networkPassphrase: this.network,
})
.addOperation(Operation.changeTrust({ asset: usdcAsset }))
.setTimeout(300)
.build();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Network passphrase may not match the USDC issuer network.

The method resolves the USDC issuer based on the network parameter ('testnet' or 'mainnet'), but the transaction is built using this.network (the service's configured network passphrase). If the service was initialized with Networks.TESTNET but setupUSDCTrustline is called with 'mainnet', the resulting transaction will have the testnet passphrase but reference the mainnet USDC issuer—making it invalid on both networks.

Consider deriving the network passphrase from the network parameter to ensure consistency:

🔧 Proposed fix
+import { Networks } from '@stellar/stellar-sdk';
+
+// Inside setupUSDCTrustline:
 const issuer = USDC_ISSUERS[network];
 const usdcAsset = new Asset('USDC', issuer);
+const networkPassphrase = network === 'mainnet' ? Networks.PUBLIC : Networks.TESTNET;
 
 const account = await this.server.getAccount(accountId);
 
 const tx = new TransactionBuilder(account, {
   fee: BASE_FEE,
-  networkPassphrase: this.network,
+  networkPassphrase,
 })
📝 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
const issuer = USDC_ISSUERS[network];
const usdcAsset = new Asset('USDC', issuer);
const account = await this.server.getAccount(accountId);
const tx = new TransactionBuilder(account, {
fee: BASE_FEE,
networkPassphrase: this.network,
})
.addOperation(Operation.changeTrust({ asset: usdcAsset }))
.setTimeout(300)
.build();
const issuer = USDC_ISSUERS[network];
const usdcAsset = new Asset('USDC', issuer);
const networkPassphrase = network === 'mainnet' ? Networks.PUBLIC : Networks.TESTNET;
const account = await this.server.getAccount(accountId);
const tx = new TransactionBuilder(account, {
fee: BASE_FEE,
networkPassphrase,
})
.addOperation(Operation.changeTrust({ asset: usdcAsset }))
.setTimeout(300)
.build();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/wallet/src/smart-wallet.service.ts` around lines 1183 - 1194,
The transaction uses this.network (service-wide passphrase) while the USDC
issuer is selected from USDC_ISSUERS[network], causing a mismatch if the
method's network param differs from the service config; update the code in
setupUSDCTrustline (or the function creating the transaction) to derive a
network passphrase from the method parameter (e.g., const networkPassphrase =
network === 'testnet' ? Networks.TESTNET : Networks.PUBLIC) and pass that into
new TransactionBuilder(..., { networkPassphrase }) so the TransactionBuilder
uses the same network as the USDC_ISSUERS lookup; also add an import for
Networks from the Stellar SDK if not already present.

@KevinMB0220 KevinMB0220 merged commit cc968c0 into Galaxy-KJ:main Mar 29, 2026
7 checks passed
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.

[FEATURE] USDC Trustline setup for Smart Wallets

2 participants