Swap
Swap lets a client exchange USDC and EURe directly on-chain using a short-lived quote signed by Monerium. The feature is currently in preview and available only in the sandbox environment on Arbitrum Sepolia.
Swap is currently in preview and available only in the sandbox environment on Arbitrum Sepolia. The API is subject to change before general availability. Check this page again before integrating or updating your implementation.
How it works
The client asks Monerium for a quote bound to a wallet, accepts that quote to get a signature and settlement calldata, approves the settlement contract to spend the sell token, then executes the signed swap on-chain.
- Quote: Request a price for exactly one
sellAmountorbuyAmount. The response includes anX-Quote-Tokenheader. - Accept: Send the quote token back to Monerium to receive a signed quote and complete settlement calldata.
- Approve: Approve the returned settlement contract to spend the sell token if allowance is too low.
- Execute: Send the returned calldata to the settlement contract before the quote expires.
Preview configuration
Use these values in sandbox while swap is in preview:
| Field | Value |
|---|---|
| Chain | Arbitrum Sepolia |
| Chain name | arbitrumsepolia |
| Chain ID | 421614 |
| Supported pair | USDC and EURe |
Token and settlement contract addresses are resolved by Monerium for the requested chain and returned by the API. Use the returned addresses rather than hard-coding them.
The API accepts decimal strings of at least 1 token, such as 1 or 10.00. Display amounts remain decimal strings. Base-unit amounts are returned separately as integer strings and are authoritative for on-chain operations.
Get a quote
Pass the chain and token symbols in the path. Pass the wallet address and exactly one amount of at least 1 token in the query string. sellAmount means "sell this amount". buyAmount means "buy this amount".
const url = new URL(
'https://api.monerium.dev/swap/arbitrumsepolia/USDC/EURe',
);
url.search = new URLSearchParams({
sellAmount: '10.00',
walletAddress,
}).toString();
const response = await fetch(url, {
method: 'GET',
headers: {
Authorization: `Bearer ${access_token}`,
Accept: 'application/vnd.monerium.api-v2+json',
},
});
const quoteToken = response.headers.get('X-Quote-Token');
if (!quoteToken) throw new Error('Missing quote token');
const quote = await response.json();
The response includes:
| Field | Description |
|---|---|
id | Quote UUID used for reconciliation. |
chain | Chain name used for settlement. |
walletAddress | Wallet bound to the quote. |
sellToken, buyToken | Normalized token symbols. |
sellTokenAddress, buyTokenAddress | Token contract addresses on the selected chain. |
sellTokenDecimals, buyTokenDecimals | Token decimals on the selected chain. |
sellAmount, buyAmount | Quoted decimal token amounts. |
sellAmountBaseUnits, buyAmountBaseUnits | Quoted amounts in token base units. |
requiredAllowanceBaseUnits | Minimum sell-token allowance in base units. |
sellAmountUsd, buyAmountUsd | Quoted USD values. |
price, priceImpact | Quoted price and percentage price impact. |
expiry | Unix timestamp when the quote expires. |
The X-Quote-Token header is opaque. Store it only long enough to accept this quote, and do not modify it.
Accept the quote
Send the quote token in the X-Quote-Token header. The request has no JSON body. Monerium checks liquidity and token balances, then returns a signed quote.
A successful quote does not reserve liquidity or guarantee that acceptance will succeed. Treat /swap/accept as the authoritative check before asking the wallet to approve or execute the swap.
const response = await fetch('https://api.monerium.dev/swap/accept', {
method: 'POST',
headers: {
Authorization: `Bearer ${access_token}`,
Accept: 'application/vnd.monerium.api-v2+json',
'X-Quote-Token': quoteToken,
},
});
const acceptedQuote = await response.json();
acceptedQuote contains the quote fields plus:
| Field | Description |
|---|---|
chainId | Chain ID the quote was signed for. |
settlementAddress | Contract that must receive the settlement transaction. |
nonce | Settlement nonce. It can only be used once. |
signature | Monerium signature authorizing the swap. |
calldata | Complete ABI-encoded swap(...) call. |
Execute on-chain
The settlement contract exposes:
function swap(
address walletAddress,
address sellToken,
address buyToken,
uint256 sellAmount,
uint256 buyAmount,
uint256 expiry,
uint256 nonce,
bytes16 quoteId,
bytes calldata signature
) external;
The caller must be walletAddress, must be connected to chainId, and must execute before expiry. The contract verifies Monerium's signature, marks the nonce as used, transfers sellAmount of sellToken from the wallet to the maker, and transfers buyAmount of buyToken from the maker to the wallet.
Submit the returned calldata unchanged to settlementAddress:
import { maxUint256, parseAbi } from 'viem';
const erc20Abi = parseAbi([
'function allowance(address owner, address spender) view returns (uint256)',
'function approve(address spender, uint256 amount) returns (bool)',
]);
const requiredAllowance = BigInt(
acceptedQuote.requiredAllowanceBaseUnits,
);
const allowance = await publicClient.readContract({
address: acceptedQuote.sellTokenAddress,
abi: erc20Abi,
functionName: 'allowance',
args: [walletAddress, acceptedQuote.settlementAddress],
});
if (allowance < requiredAllowance) {
const { request } = await publicClient.simulateContract({
account: walletAddress,
address: acceptedQuote.sellTokenAddress,
abi: erc20Abi,
functionName: 'approve',
args: [acceptedQuote.settlementAddress, maxUint256],
});
const approveHash = await walletClient.writeContract(request);
await publicClient.waitForTransactionReceipt({ hash: approveHash });
}
const swapHash = await walletClient.sendTransaction({
account: walletAddress,
to: acceptedQuote.settlementAddress,
data: acceptedQuote.calldata,
});
const receipt = await publicClient.waitForTransactionReceipt({ hash: swapHash });
Approving maxUint256 avoids repeated approval transactions. If your product prefers tighter allowances, approve requiredAllowance instead.
Monitor completion
The swap is complete when the settlement transaction is confirmed successfully. The settlement contract emits Swap(bytes16 quoteId), and the token contracts emit the corresponding Transfer events.
Use the transaction hash and quote ID for reconciliation in your client.