⌨️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