Skip to content

Submit Proportional Exit

POST /intents/submit (type: "exitProportional")

Submit a signed proportional exit intent. The user burns LP shares and receives pool tokens proportionally.

Full Example (viem)

javascript
const MULTIHOP_ROUTER = '0x662F15226f5b6Bf8aA10512374Af3115412C04bA';
const RELAYER_URL = 'https://mainnet.relayer.ryze.pro/api/v1';

// 1. Read nonce
const nonce = await publicClient.readContract({
  address: MULTIHOP_ROUTER,
  abi: [{ name: 'exitProportionalNonces', type: 'function', inputs: [{ type: 'address' }], outputs: [{ type: 'uint256' }], stateMutability: 'view' }],
  functionName: 'exitProportionalNonces',
  args: [account.address],
});

// 2. Build intent
const deadline = BigInt(Math.floor(Date.now() / 1000) + 1800);
const sharesIn = BigInt('50000000000000000000'); // LP shares to burn

const intent = {
  user: account.address,
  pool: '0x7B41aA91947398CD9244AD4e314C253D9B1B5206',
  sharesIn,
  minAmountsOut: [
    BigInt('30000000000000000'),  // min WETH
    BigInt('49000000'),           // min USDC
  ],
  recipient: account.address,
  deadline,
  nonce,
};

// 3. Sign EIP-712
const signature = await walletClient.signTypedData({
  domain: {
    name: 'MultiHopRouter',
    version: '1',
    chainId: 8453,
    verifyingContract: MULTIHOP_ROUTER,
  },
  types: {
    ExitProportionalIntent: [
      { name: 'user', type: 'address' },
      { name: 'pool', type: 'address' },
      { name: 'sharesIn', type: 'uint256' },
      { name: 'minAmountsOut', type: 'uint256[]' },
      { name: 'recipient', type: 'address' },
      { name: 'deadline', type: 'uint256' },
      { name: 'nonce', type: 'uint256' },
    ],
  },
  primaryType: 'ExitProportionalIntent',
  message: intent,
});

// 4. Split signature and submit
const r = signature.slice(0, 66);
const s = '0x' + signature.slice(66, 130);
const v = parseInt(signature.slice(130, 132), 16);

const res = await fetch(`${RELAYER_URL}/intents/submit`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    type: 'exitProportional',
    user: intent.user,
    pool: intent.pool,
    sharesIn: intent.sharesIn.toString(),
    minAmountsOut: intent.minAmountsOut.map(a => a.toString()),
    poolTokens: [
      '0x4200000000000000000000000000000000000006', // WETH
      '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC
    ],
    recipient: intent.recipient,
    deadline: Number(intent.deadline),
    nonce: Number(intent.nonce),
    signature: { v, r, s },
  }),
});
const result = await res.json();
console.log('Intent ID:', result.intentId);

Request Body

json
{
  "type": "exitProportional",
  "user": "0xYourAddress",
  "pool": "0x7B41aA91947398CD9244AD4e314C253D9B1B5206",
  "sharesIn": "50000000000000000000",
  "minAmountsOut": [
    "30000000000000000",
    "49000000"
  ],
  "poolTokens": [
    "0x4200000000000000000000000000000000000006",
    "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
  ],
  "recipient": "0xYourAddress",
  "deadline": 1713200000,
  "nonce": 0,
  "signature": { "v": 27, "r": "0x...", "s": "0x..." }
}

Fields

FieldTypeDescription
typestringMust be "exitProportional"
useraddressSender (must match signature)
pooladdressPool to exit
sharesInstringLP shares to burn (18 decimals)
minAmountsOutstring[]Minimum amounts per token (slippage protection)
poolTokensstring[]Token addresses (same order as minAmountsOut)
recipientaddressAddress to receive tokens
deadlinenumberUnix timestamp expiry
noncenumberFrom exitProportionalNonces(user) on contract
signatureobjectEIP-712 signature {v, r, s}

INFO

The minAmountsOut and poolTokens arrays must be the same length and in the same token order.

EIP-712 Types

typescript
const types = {
  ExitProportionalIntent: [
    { name: 'user', type: 'address' },
    { name: 'pool', type: 'address' },
    { name: 'sharesIn', type: 'uint256' },
    { name: 'minAmountsOut', type: 'uint256[]' },
    { name: 'recipient', type: 'address' },
    { name: 'deadline', type: 'uint256' },
    { name: 'nonce', type: 'uint256' },
  ],
};