# Executing a transaction

To demonstrate MagicSpend++, we'll walk through a simple, real-world EVM transaction: transferring 1.0 USDC on Polygon. This compact example shows the full flow end-to-end—constructing ERC‑20 transfer calldata from the USDC ABI, requesting a canonical userOp hash from the backend, signing that hash with a Privy-backed wallet, producing EIP‑7702 authorization(s), and finally submitting everything to a submit endpoint. By following this sequence, you'll see how MagicSpend++ enables chain abstracted execution with minimal friction while keeping the signer experience familiar.

### Step 1 — Build ERC‑20 Transfer Transaction Calldata

{% tabs %}
{% tab title="Viem" %}

<pre class="language-javascript"><code class="lang-javascript"><strong>import { erc20Abi, encodeFunctionData, parseUnits } from 'viem';
</strong>
const chainId = 137;
const usdc = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174';
const recipient = '0x1111111111111111111111111111111111111111';

// 1. Convert 1.0 USDC to base units (6 decimals)
const amount = parseUnits('1.0', 6);

// 2. Encode transfer(to, amount) calldata
const encodedData = encodeFunctionData({
  abi: erc20Abi,
  functionName: 'transfer',
  args: [recipient, amount],
});
</code></pre>

{% endtab %}

{% tab title="Ethers" %}

```javascript
import { Interface, parseUnits } from 'ethers';

const chainId = 137;
const usdc = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174';
const recipient = '0x1111111111111111111111111111111111111111';

const erc20 = new Interface([
  'function transfer(address to, uint256 amount) returns (bool)'
]);

const amount = parseUnits('1.0', 6); // 1 USDC -> 1_000_000
const encodedData = erc20.encodeFunctionData('transfer', [recipient, amount]);
```

{% endtab %}
{% endtabs %}

#### Step 2 — Build the chain abstracted transaction (with quote type + token addresses)

```javascript
import axios from 'axios';

const chainId = 137; // Polygon

// Token the user settles in
const settlementToken = 'USDC'; 

// Token the user spends
const spendingTokenAddress = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174';

// For a transfer, spending and settlement tokens are both USDC.
// Use 'AMOUNT_OUT' to send an exact recipient amount; 'AMOUNT_IN' to spend an exact input amount.
const quoteType = 'AMOUNT_OUT'; // or 'AMOUNT_IN'
const amount = '1000000'; // Formatted amount (USDC uses 6 decimals)

const { data: transactionData } = await axios.post('https://api.enclave.money/magicspend/build-transaction', {
  chainId,
  transactions: [{
    to: usdc
    
    // encodedData comes from Step 1 (ERC-20 transfer calldata built via viem/ethers)
    data: encodedData
  }],
  quoteType, // 'AMOUNT_OUT' | 'AMOUNT_IN'
  amount, // '1.0' => 1 USDC
  spendingTokenAddress,   // token user spends
  settlementToken // token user settle in (ex. 'USDC' or 'SOL')
}, {
  headers: {
    'Content-Type': 'application/json',
    'Authorization': process.env.ENCLAVE_API_KEY,
  }
});

const { 
  userOpHash, 
  authorizations, 
  settlementPlan, 
  expiryTimestamp, 
  transactionId 
} = transactionData;
```

**Supported Settlement Tokens**

| Token | Identifier | Supported Networks                                                                                                 |
| ----- | ---------- | ------------------------------------------------------------------------------------------------------------------ |
| USDC  | USDC       | Ethereum Mainnet, Arbitrum, Base, Optimism, Polygon, Avalanche, Unichain, Binance Smart Chain, World Chain, Solana |
| SOL   | SOL        | Solana                                                                                                             |
| ETH   | ETH        | Ethereum Mainnet, Arbitrum, Base, Optimism, Polygon, Unichain, World Chain                                         |

### Step 3 — Initialize Privy and sign the user operation and authorizations

```javascript
import { PrivyClient } from '@privy-io/node';

// Initialize Privy client (equivalent to TurnkeyServerSDK)
const privyClient = new PrivyClient(
  process.env.NEXT_PUBLIC_PRIVY_APP_ID!,
  process.env.NEXT_PUBLIC_PRIVY_APP_SECRET!
);

// User's wallet ID from Privy (equivalent to Turnkey's organizationId + address)
const walletId = 'USER_WALLET_ID'; // Get this from the user's Privy embedded wallet

// Sign the userOpHash (equivalent to walletClient.signMessage)
const { signature: userOpSignature, encoding } = await privyClient
  .wallets()
  .ethereum()
  .signMessage(walletId, {
    params: {
      message: userOpHash
    }
  });
```

### Step 4 — Sign EIP‑7702 authorization(s)

```javascript
// Sign each authorization
const authorizationList = await Promise.all(
  authorizations.map((authorization: { contractAddress: string, chainId: number, nonce: bigint }) =>
    privyClient
      .wallets()
      .ethereum()
      .sign7702Authorization(walletId, {
        params: {
          contract: authorization.contractAddress,
          chainId: authorization.chainId,
          nonce: Number(authorization.nonce)
        }
      })
  )
);
```

### Step 5 - Submitting the transaction

```javascript
// Submitting transaction response
const { data: submitResponse } = await axios.post('https://api.enclave.money/magicspend/submit', {
  transactionId,
  userOpSignature,
  authorizationList,
}, {
  headers: {
    'Content-Type': 'application/json',
    'Authorization': process.env.ENCLAVE_API_KEY,
  }
});

const { txHash, transactionId, status } = submitResponse
```

### Step 6 - Checking the status of the transaction

```javascript
const { 
    status, 
    failureReason, 
    executedAt, 
    settledAt, 
    targetTransaction, 
    settlementTransactions  
} = await axios.get('https://api.enclave.money/magicspend/tx-status', 
    { params: { transactionId } },
    {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': process.env.ENCLAVE_API_KEY,
    }
});
// Example: { status: 'PENDING' | 'SUBMITTED' | 'TARGET_EXECUTED' | 'SETTLING | 'SETTLEMENT_EXECUTED' | 'EXPIRED' | 'FAILED' }
console.log('Transaction Status:', status);
```

**Status Codes**

| Status Code          | Description                                                                                                 |
| -------------------- | ----------------------------------------------------------------------------------------------------------- |
| PENDING              | Transaction is built but signatures for the transaction have not been submitted yet                         |
| SUBMITTED            | Transaction has been submitted and the user's desired action will be executed on the target chain           |
| TARGET\_EXECUTED     | Target chain transaction has been succeefully executed. Settlement of the transaction is now pending.       |
| SETTLING             | Settlement transactions on each of the settlement chains have been submitted and pending execution          |
| SETTLEMENT\_EXECUTED | Settlement transactions on all settlement chains have been executed                                         |
| EXPIRED              | Transaction was built but was not submitted on time for valid execution                                     |
| FAILED               | Transaction execution failed. This may be due to a reverted transaction on the target or settlement chains. |
