# How to do gasless USDC transfers on Base from a Motoko canister?

**URL:** <https://forum.dfinity.org/t/how-to-do-gasless-usdc-transfers-on-base-from-a-motoko-canister/55806>\
**Category:** Developers\
**Created:** [August 21, 2025, 9:51am UTC](https://forum.dfinity.org/t/how-to-do-gasless-usdc-transfers-on-base-from-a-motoko-canister/55806 "2025-08-21T09:51:06Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Abdullah-1057](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/abdullah-1057/32/15197_2.png) [@Abdullah-1057](https://forum.dfinity.org/u/Abdullah-1057)\
**Post date:** [August 21, 2025, 9:51am UTC](https://forum.dfinity.org/t/how-to-do-gasless-usdc-transfers-on-base-from-a-motoko-canister/55806/1 "2025-08-21T09:51:07Z")

</div>

**Context**

- I have an Internet Identity–based dapp. Previously each user got an EVM address derived via canister tECDSA and could:

- This works end-to-end already.

**Goal (what I want now)**

Move custody from individuals to **multiple Motoko canisters** (each canister owns one EVM address via tECDSA) and still enable **gasless USDC sends on Base**. The canister owner triggers transfers; users shouldn’t need ETH.

**Canister API I’m exposing (update calls only)**  
public shared ({ caller }) func ethereum\_pubkey() : async Text; // 0x-hex SEC1 pubkey  
public shared ({ caller }) func new\_nonce() : async Text; // 0x-hex 32B nonce (from raw\_rand)  
public shared ({ caller }) func sign\_digest(digest32 : Blob) : async Text; // 0x[r||s] (64B)  
public shared ({ caller }) func relay\_submit(json : Text)  
: async { status : Nat; body : Text }; // optional HTTPS outcall to my relayer

- **Derivation path** is tied to the canister (not caller):  
`["custody:usdc:v1", <canister_principal_bytes>]` on mainnet

- EIP-712 hashing (domain/types/message for **USDC Base** , chainId 8453, token `0x833589f...2913`) is done **client-side** with ethers to keep the canister simple and fast.

- For signing, the canister calls `sign_with_ecdsa` and returns `0x[r||s]`; I recover `v` client-side and broadcast either from an admin wallet or via a relayer endpoint (optionally using `relay_submit` HTTPS outcall).

**What I need help with**

1. **Recommended pattern for gasless USDC transaction from a canister on Base (EIP-3009):**

2. **Cycle budgeting guidance (realistic numbers on mainnet):**

3. **Nonce & replay protection best practices:**

4. **Multi-canister setup tips:**

**Constraints / intent**

- Must be **Base mainnet** (chainId **8453** ) and **USDC** token (`0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`).

- End-user must be **gasless** ; I’m fine paying ETH (on Base) via admin wallet or relayer.

- I’d like to keep the on-chain Motoko side minimal (no on-canister EVM tx building), but I’m open to adding hashing/validation if there are good libraries.

Thanks in advance for any pointers, example code, cycle numbers, or “don’t do this” gotchas from teams who’ve shipped gasless EIP-3009 with tECDSA!
