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, commits that quote to get a signature, approves the settlement contract to spend the taker token, then executes the signed swap on-chain.
- Quote: Request a price for either the sell amount (
takerAmount) or buy amount (makerAmount). - Commit: Request a signed quote for the connected wallet and chain.
- Approve: Approve the settlement contract to spend the taker token if allowance is too low.
- Execute: Call
swap(...)on 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 ID | 421614 |
| Settlement contract | 0x4996f35a3d07276e3d5105af0e723ee6b993296c |
| USDC | 0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d |
| EURe | 0x1DfA293078Cfb70c7AB85fa451b5A7687e50da3B |
The API accepts decimal strings such as 10.00. Contract calls use raw token units: USDC has 6 decimals and EURe has 18 decimals.
Get a quote
Send the taker token, maker token, and exactly one amount field. takerAmount means "sell this amount". makerAmount means "buy this amount".
const response = await fetch('https://api.monerium.dev/swap', {
method: 'POST',
headers: {
Authorization: `Bearer ${access_token}`,
'Content-Type': 'application/json',
Accept: 'application/vnd.monerium.api-v2+json',
},
body: JSON.stringify({
takerToken: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', // USDC
makerToken: '0x1DfA293078Cfb70c7AB85fa451b5A7687e50da3B', // EURe
takerAmount: '10.00',
}),
});
const quote = await response.json();
The response includes takerAmount, makerAmount, price, priceImpact, takerAmountUsd, and makerAmountUsd as decimal strings.
Commit the quote
Commit with the same quote input, plus the taker wallet address and chain ID. Monerium checks liquidity, checks token balances, and returns a signed quote.
A successful quote does not reserve liquidity or guarantee that commit will succeed. Treat /swap/commit as the authoritative check before asking the wallet to approve or execute the swap.
const response = await fetch('https://api.monerium.dev/swap/commit', {
method: 'POST',
headers: {
Authorization: `Bearer ${access_token}`,
'Content-Type': 'application/json',
Accept: 'application/vnd.monerium.api-v2+json',
},
body: JSON.stringify({
chainId: 421614,
taker: walletAddress,
takerToken: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
makerToken: '0x1DfA293078Cfb70c7AB85fa451b5A7687e50da3B',
takerAmount: '10.00',
}),
});
const committedQuote = await response.json();
committedQuote contains the quote fields plus:
| Field | Description |
|---|---|
id | Quote UUID. Convert this to bytes16 for the contract call. |
chainId | Chain ID the quote was signed for. |
nonce | Settlement nonce. Can only be used once. |
expiry | Unix timestamp when the quote expires. |
signature | Monerium signature authorizing the swap. |
Execute on-chain
The settlement contract exposes:
function swap(
address taker,
address takerToken,
address makerToken,
uint256 takerAmount,
uint256 makerAmount,
uint256 expiry,
uint256 nonce,
bytes16 quoteId,
bytes signature
)
The caller must be the taker, and the call must happen before expiry. The contract verifies Monerium's signature, marks the nonce as used, transfers takerAmount of takerToken from the taker to the maker, and transfers makerAmount of makerToken from the maker to the taker.
import { maxUint256, parseAbi, parseUnits } from 'viem';
const settlementAddress = '0x4996f35a3d07276e3d5105af0e723ee6b993296c';
const erc20Abi = parseAbi([
'function allowance(address owner, address spender) view returns (uint256)',
'function approve(address spender, uint256 amount) returns (bool)',
]);
const swapAbi = parseAbi([
'function swap(address taker, address takerToken, address makerToken, uint256 takerAmount, uint256 makerAmount, uint256 expiry, uint256 nonce, bytes16 quoteId, bytes signature)',
]);
const takerAmount = parseUnits(committedQuote.takerAmount, 6); // USDC
const makerAmount = parseUnits(committedQuote.makerAmount, 18); // EURe
const quoteId = `0x${committedQuote.id.replace(/-/g, '')}`;
const allowance = await publicClient.readContract({
address: committedQuote.takerToken,
abi: erc20Abi,
functionName: 'allowance',
args: [walletAddress, settlementAddress],
});
if (allowance < takerAmount) {
const { request } = await publicClient.simulateContract({
account: walletAddress,
address: committedQuote.takerToken,
abi: erc20Abi,
functionName: 'approve',
args: [settlementAddress, maxUint256],
});
const approveHash = await walletClient.writeContract(request);
await publicClient.waitForTransactionReceipt({ hash: approveHash });
}
const { request } = await publicClient.simulateContract({
account: walletAddress,
address: settlementAddress,
abi: swapAbi,
functionName: 'swap',
args: [
walletAddress,
committedQuote.takerToken,
committedQuote.makerToken,
takerAmount,
makerAmount,
BigInt(committedQuote.expiry),
BigInt(committedQuote.nonce),
quoteId,
committedQuote.signature,
],
});
const swapHash = await walletClient.writeContract(request);
const receipt = await publicClient.waitForTransactionReceipt({ hash: swapHash });
Approving maxUint256 avoids repeated approval transactions. If your product prefers tighter allowances, approve the exact takerAmount 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.