# Holding Ethereum Assets from Solana

A concrete, end-to-end example of what the [Sign Bidirectional Flow](/architecture/sign-bidirectional) lets you build: a **Solana program** that custodies and moves **USDC living on Ethereum** — with no bridge, no wrapped assets, and no custodian. This exact example ships today as the MPC-custodied ERC-20 vault.

## The scenario

A user wants to deposit 100 USDC (an ERC-20 on Ethereum) into your Solana application. Your Solana program:

* owns Ethereum addresses through MPC-derived keys — no private key exists anywhere,
* lets the user deposit by sending USDC to an Ethereum address the program controls,
* credits the user's balance on Solana only after cryptographic proof that the Ethereum transfer succeeded.

## Walkthrough

### 1. Derive the deposit address

Your Solana program deterministically controls a whole family of Ethereum addresses (see [Address Derivation](/architecture/sign-bidirectional#address-derivation)): each user gets a personal deposit address, and the vault has its own treasury address. Your client derives them off-chain with signet.js — no keys are created or stored anywhere.

### 2. The user funds it

The user sends 100 USDC to their deposit address on Ethereum with any ordinary wallet — MetaMask, an exchange withdrawal, anything. Nothing Signet-specific happens yet: it is a normal ERC-20 balance sitting on an MPC-controlled Ethereum address.

### 3. Request the transfer signature on Solana

The user calls the program's deposit entry point. The program builds the exact Ethereum transaction it wants executed — moving the 100 USDC from the user's deposit address into the vault's treasury address, with real fee parameters — records a single-use pending entry for the request, and asks the MPC network for a signature via `sign_bidirectional`.

### 4. The MPC signs, the client broadcasts to Ethereum

The MPC network signs the transaction and delivers the signature back on Solana. The client picks it up, assembles the signed transaction, and broadcasts it to Ethereum — the MPC never broadcasts.

### 5. A verified outcome comes back to Solana

The MPC observes Ethereum until the transfer confirms, then publishes a signed execution report back on Solana. The program's claim entry point verifies the MPC's signature on that report, confirms the transfer actually succeeded, retires the pending entry, and credits the user 100 USDC of vault balance on Solana.

Withdrawals are the mirror image: debit the Solana balance up front, execute a transfer out of the vault's treasury on Ethereum, and refund automatically if the verified report says the transfer failed.

## See it running

The walkthrough above tracks the Solana implementation; the same vault ships on every supported source chain:

| Source chain | Implementation                                                                                                                                                                      |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Solana**   | [`solana-contract-examples`](https://github.com/sig-net/solana-contract-examples) — the vault program this walkthrough follows                                                      |
| **Canton**   | [`signet-vault-v1`](https://github.com/sig-net/canton/blob/main/daml-packages/signet-vault-v1/README.md) — live on DevNet and Testnet, with an end-to-end test against the real MPC |
| **EVM**      | [`Erc20Vault.sol`](https://github.com/sig-net/signet-evm-contract/blob/main/examples/Erc20Vault.sol) — EVM → EVM example with a two-chain e2e test                                  |

## Beyond deposits: swaps, yield, anything

Nothing in the flow is transfer-specific — step 3 signs whatever Ethereum transaction your program builds, and step 5 hands back its verified execution result:

* **Swaps**: the program submits a trade on a Uniswap-style DEX; the verified outcome reports the exact amount received, which the program credits on Solana — a swap on Ethereum, initiated and settled from Solana.
* **Yield**: the program deposits into an Ethereum yield vault; the verified outcome reports the shares received. Exiting the position later works the same way.
* **Anything else**: any transaction an Ethereum account can send, your Solana program can initiate — and, crucially, verify the result of on Solana before updating state.

The pattern is always the same: build the foreign transaction → `sign_bidirectional` → broadcast → act on the MPC-verified outcome.

## Related Documentation

* [Sign Bidirectional Flow](/architecture/sign-bidirectional) — the chain-agnostic lifecycle
* [Per-chain documentation](/architecture/sign-bidirectional#per-chain-documentation) — contract/template APIs for each source chain
