⌨️Submit Order

Below we provide some example code for making a trade on Bebop.

Bebop submits order on chain having received maker and taker signatures. This means that Bebop pays the network (gas) fees as they are already included in the price. This is the default mode.

Bebop web interface users and most API users would choose Bebop's default mode where user signs the order transaction and Bebop sends it on-chain.

In some cases, API users may need to submit the transaction themselves, and we have a mode for that too.

Example

import axios from "axios";
import {ethers} from "ethers"; //ethers-v6

// Trade Info (Insert your values)
const privateKey = ""
const tokensAddressesSell = ["0x4200000000000000000000000000000000000006"] // WETH
const tokensSellAmounts = [ethers.parseEther("0.001")] // 0.001 WETH
const tokensAddressBuy = ["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"] // USDC
const chain = {
    chainId: 8453,
    name: "base" // "polygon" | "ethereum" | "arbitrum" | "blast" | "optimism"
}

// Constants
const BEBOP_ADDRESS = "0xbbbbbBB520d69a9775E85b458C58c648259FAD5F"
const SINGLE_ORDER_TYPES = {
    "SingleOrder": [
        { "name": "partner_id", "type": "uint64" },
        { "name": "expiry", "type": "uint256" },
        { "name": "taker_address", "type": "address" },
        { "name": "maker_address", "type": "address" },
        { "name": "maker_nonce", "type": "uint256" },
        { "name": "taker_token", "type": "address" },
        { "name": "maker_token", "type": "address" },
        { "name": "taker_amount", "type": "uint256" },
        { "name": "maker_amount", "type": "uint256" },
        { "name": "receiver", "type": "address" },
        { "name": "packed_commands", "type": "uint256" },
    ]
}

const MULTI_ORDER_TYPES = {
    "MultiOrder": [
        { "name": "partner_id", "type": "uint64" },
        { "name": "expiry", "type": "uint256" },
        { "name": "taker_address", "type": "address" },
        { "name": "maker_address", "type": "address" },
        { "name": "maker_nonce", "type": "uint256" },
        { "name": "taker_tokens", "type": "address[]" },
        { "name": "maker_tokens", "type": "address[]" },
        { "name": "taker_amounts", "type": "uint256[]" },
        { "name": "maker_amounts", "type": "uint256[]" },
        { "name": "receiver", "type": "address" },
        { "name": "commands", "type": "bytes" },
    ]
}

const AGGREGATE_ORDER_TYPES = {
    "AggregateOrder": [
        { "name": "partner_id", "type": "uint64" },
        { "name": "expiry", "type": "uint256" },
        { "name": "taker_address", "type": "address" },
        { "name": "maker_addresses", "type": "address[]" },
        { "name": "maker_nonces", "type": "uint256[]" },
        { "name": "taker_tokens", "type": "address[][]" },
        { "name": "maker_tokens", "type": "address[][]" },
        { "name": "taker_amounts", "type": "uint256[][]" },
        { "name": "maker_amounts", "type": "uint256[][]" },
        { "name": "receiver", "type": "address" },
        { "name": "commands", "type": "bytes" },
    ]
}
const PARAM_DOMAIN = {
    name: "BebopSettlement",
    version: "2",
    chainId: chain.chainId,
    verifyingContract: BEBOP_ADDRESS,
}


// Getting quote and submitting it onchain
async function sendTx() {

    // Init you wallet
    let account = new ethers.Wallet(privateKey)

    // Get quote
    let quote = (await axios.get(`https://api.bebop.xyz/pmm/${chain.name}/v3/quote`, {
        params: {
            buy_tokens: tokensAddressBuy.toString(),
            sell_tokens: tokensAddressesSell.toString(),
            sell_amounts: tokensSellAmounts.toString(),
            taker_address: account.address
        }
    })).data
    console.log(quote)
    if (quote.error !== undefined) {
        return
    }

    // Choosing order-type for signing 
    let PARAM_TYPES;
    switch (quote.onchainOrderType) {
        case "SingleOrder":
            PARAM_TYPES = SINGLE_ORDER_TYPES
            break
        case "MultiOrder":
            PARAM_TYPES = MULTI_ORDER_TYPES
            break
        case "AggregateOrder":
            PARAM_TYPES = AGGREGATE_ORDER_TYPES
            break
        default:
            throw Error("Unknown quote type")
    }
    // Sign quote
    let signature = await account.signTypedData(PARAM_DOMAIN, PARAM_TYPES, quote.toSign)
    console.log("Signature", signature)

    // Send Transaction
    let response = (await axios.post(`https://api.bebop.xyz/pmm/${chain.name}/v3/order`, {
        signature: signature,
        quote_id: quote.quoteId,
    })).data
    console.log(response)
}

sendTx()

Example for many-to-one swap ( 1 USDC + 2 USDbC -> WETH):

let WETH = "0x4200000000000000000000000000000000000006"
let USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
let USDbC = "0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA"
let quote = (await axios.get(`https://api.bebop.xyz/pmm/${chain.name}/v3/quote`, {
        params: {
            buy_tokens: WETH,
            sell_tokens: USDC + "," + USDbC,
            sell_amounts: "1000000,2000000",
            taker_address: account.address
        }
    })).data

Example for one-to-many swap ( WETH -> USDC + USDbC):

let WETH = "0x4200000000000000000000000000000000000006"
let USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
let USDbC = "0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA"
let quote = (await axios.get(`https://api.bebop.xyz/pmm/${chain.name}/v3/quote`, {
        params: {
            buy_tokens: USDC + "," + USDbC,
            sell_tokens: WETH,
            sell_amounts: "100000000000000000000000000000000",
            buy_tokens_ratios: "0.5,0.5"
            taker_address: account.address
        }
    })).data

Executing Permit2+gasless PMM-quote from router

import axios from "axios";
import {ethers} from "ethers";

// Trade Info (Insert your values)
let privateKey = ""
let tokensAddressesSell = ["0xaf88d065e77c8cC2239327C5EDb3A432268e5831"] // USDC
let tokensSellAmounts = [ethers.parseUnits("1", 6)] // 1 USDC
let tokensAddressBuy = ["0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"] // USDT
let chain = {
    chainId: 42161,
    name: "arbitrum" // "polygon" / "ethereum" / "arbitrum" / etc
}

// Constants
const SETTLEMENT_ADDRESS = "0xbeb0b0623f66bE8cE162EbDfA2ec543A522F4ea6"
const SINGLE_ORDER_WITH_PERMIT2_TYPES = {
    'PermitWitnessTransferFrom': [
        { 'name': 'permitted', 'type': 'TokenPermissions' },
        { 'name': 'spender', 'type': 'address' },
        { 'name': 'nonce', 'type': 'uint256' },
        { 'name': 'deadline', 'type': 'uint256' },
        { 'name': 'witness', 'type': 'SingleOrder' }
    ],
    'TokenPermissions': [
        { 'name': 'token', 'type': 'address' },
        { 'name': 'amount', 'type': 'uint256' }
    ],
    'SingleOrder': [
        { 'name': 'partner_id', 'type': 'uint64' },
        { 'name': 'expiry', 'type': 'uint256' },
        { 'name': 'taker_address', 'type': 'address' },
        { 'name': 'maker_address', 'type': 'address' },
        { 'name': 'maker_nonce', 'type': 'uint256' },
        { 'name': 'taker_token', 'type': 'address' },
        { 'name': 'maker_token', 'type': 'address' },
        { 'name': 'taker_amount', 'type': 'uint256' },
        { 'name': 'maker_amount', 'type': 'uint256' },
        { 'name': 'receiver', 'type': 'address' },
        { 'name': 'packed_commands', 'type': 'uint256' },
        { 'name': 'hooksHash', 'type': 'bytes32' }
    ]
}
const MULTI_ORDER_WITH_PERMIT2_TYPES = {
    'PermitBatchWitnessTransferFrom': [
        { 'name': 'permitted', 'type': 'TokenPermissions[]' },
        { 'name': 'spender', 'type': 'address' },
        { 'name': 'nonce', 'type': 'uint256' },
        { 'name': 'deadline', 'type': 'uint256' },
        { 'name': 'witness', 'type': 'JamOrder' }
    ],
    'TokenPermissions': [
        { 'name': 'token', 'type': 'address' },
        { 'name': 'amount', 'type': 'uint256' }
    ],
    'MultiOrder': [
        { 'name': 'partner_id', 'type': 'uint64' },
        { 'name': 'expiry', 'type': 'uint256' },
        { 'name': 'taker_address', 'type': 'address' },
        { 'name': 'maker_address', 'type': 'address' },
        { 'name': 'maker_nonce', 'type': 'uint256' },
        { 'name': 'taker_tokens', 'type': 'address[]' },
        { 'name': 'maker_tokens', 'type': 'address[]' },
        { 'name': 'taker_amounts', 'type': 'uint256[]' },
        { 'name': 'maker_amounts', 'type': 'uint256[]' },
        { 'name': 'receiver', 'type': 'address' },
        { 'name': 'commands', 'type': 'bytes' },
        { 'name': 'hooksHash', 'type': 'bytes32' }
  ]
}
const AGGREGATE_ORDER_WITH_PERMIT2_TYPES = {
    'PermitBatchWitnessTransferFrom': [
        { 'name': 'permitted', 'type': 'TokenPermissions[]' },
        { 'name': 'spender', 'type': 'address' },
        { 'name': 'nonce', 'type': 'uint256' },
        { 'name': 'deadline', 'type': 'uint256' },
        { 'name': 'witness', 'type': 'JamOrder' }
    ],
    'TokenPermissions': [
        { 'name': 'token', 'type': 'address' },
        { 'name': 'amount', 'type': 'uint256' }
    ],
    'AggregateOrder': [
        { 'name': 'partner_id', 'type': 'uint64' },
        { 'name': 'expiry', 'type': 'uint256' },
        { 'name': 'taker_address', 'type': 'address' },
        { 'name': 'maker_addresses', 'type': 'address[]' },
        { 'name': 'maker_nonces', 'type': 'uint256[]' },
        { 'name': 'taker_tokens', 'type': 'address[][]' },
        { 'name': 'maker_tokens', 'type': 'address[][]' },
        { 'name': 'taker_amounts', 'type': 'uint256[][]' },
        { 'name': 'maker_amounts', 'type': 'uint256[][]' },
        { 'name': 'receiver', 'type': 'address' },
        { 'name': 'commands', 'type': 'bytes' },
        { 'name': 'hooksHash', 'type': 'bytes32' }
      ]
}

const PERMIT2_DOMAIN = {
    name: "Permit2",
    chainId: chain.chainId,
    verifyingContract: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
}


// Getting quote and submitting it onchain
async function sendTx() {

    // Init you wallet and provider
    let account = new ethers.Wallet(privateKey)

    // Get quote
    let quotes = (await axios.get(`https://api.bebop.xyz/router/${chain.name}/v1/quote`, {
        params: {
            buy_tokens: tokensAddressBuy.toString(),
            sell_tokens: tokensAddressesSell.toString(),
            sell_amounts: tokensSellAmounts.toString(),
            taker_address: account.address,
            approval_type: "Permit2",
            gasless: true
        }
    })).data

    let pmmQuote = undefined
    for (let route of quotes.routes){
        if (route.type === "PMMv3"){
            pmmQuote = route.quote
            break
        }
    }
    if (!pmmQuote){
        throw new Error("No PMMv3 quote found")
    }
    console.log(pmmQuote)
    
    
    // Sign quote
    let signature
    if (pmmQuote.onchainOrderType === 'SingleOrder') {
        signature = await account.signTypedData(PERMIT2_DOMAIN, SINGLE_ORDER_WITH_PERMIT2_TYPES, pmmQuote.toSign)
    } else if (pmmQuote.onchainOrderType === 'MultiOrder') {
        signature = await account.signTypedData(PERMIT2_DOMAIN, MULTI_ORDER_WITH_PERMIT2_TYPES, pmmQuote.toSign)
    } else if (pmmQuote.onchainOrderType === 'AggregateOrder') {
        signature = await account.signTypedData(PERMIT2_DOMAIN, AGGREGATE_ORDER_WITH_PERMIT2_TYPES, pmmQuote.toSign)
    } else {
        throw new Error("Unknown onchain order type")
    }

    // Send Transaction
    let response = (await axios.post(`https://api.bebop.xyz/pmm/${chain.name}/v3/order`, {
        signature: signature,
        quote_id: pmmQuote.quoteId,
    }, {
        headers: {
            'Content-Type': 'application/json; charset=utf-8'
        }
    })).data
    console.log(response)
}

sendTx()

Last updated