A Complete Example

Below is a complete example using `hardhat.js for onchain interaction, and node-fetch for the pathfinder API query.

require("@nomiclabs/hardhat-ethers");
const { assert } = require("console");
const fs = require("fs")
const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args));

async function main() {

    const ONE_ETH = ethers.constants.WeiPerEther;

    // First, we query the BrainDex Pathfinder service for a route.

    // Construct pathfinder query data
    const data =
    {
        "chain_id": 1284,
        "amount_in": ONE_ETH._hex,
        "token_in": "0xAcc15dC74880C9944775448304B263D191c6077F",
        "token_out": "0x818ec0a7fe18ff94269904fced6ae3dae6d6dc0b",
        "max_hops": 3,
        "min_splits": 0,    
        "max_splits": 3,
        "count": 5
    }

    // Make the route request
    const response = await fetch('https://api.braindex.io/app/myAppId', {
        method: 'post',
        body: JSON.stringify(data),
        headers: { 'Content-Type': 'application/json' }
    });

    // Parse our response
    const res = await response.json(); // parses JSON response into native JavaScript objects

    console.log(res.amount_out);

    // Now that we have our route response, we can query the chain to confirm our price.

    // Load the contract ABI interface
    const bdexAbiFile = fs.readFileSync('./abi/brainDexRouterAbi.json', "utf-8")
    const bdexAbi = JSON.parse(bdexAbiFile);

    // Get onchain signer
    const [signer] = await ethers.getSigners();

    // Initialize the router contract
    const BrainDexRouter = "0xe2eA8cb03481B83402e6159cf95A63A934255C6b";
    const router = new ethers.Contract(BrainDexRouter, bdexAbi, signer);

    const amtOutQuote = ethers.BigNumber.from(res.amount_out);

    // Confirm our price quote by passing the swap_paths 
    // field of the pathfinder response to the contract.
    const priceConfirm = await router.getMultiSwapAmountOut(res.swap_paths);

    // Note that there may be some small differences due to price movements 
    // between query and confirmation times.
    assert(amtOutQuote.eq(priceConfirm), "Price mismatch!");

    // We have found that the gas estimate can be underneath of what is expected, 
    // so we buffer by 1.2x

    const gasEstimate = await router.estimateGas.multiSwapTokensForTokens(
        data.token_in,
        data.token_out,
        signer.address,
        ONE_ETH,
        ethers.BigNumber.from(1), // Must be at least 1.
        ethers.BigNumber.from(1775120065),
        res.swap_paths,
    )

    const bufferedGasEstimate = gasEstimate.mul(12).div(10);

    // Perform a swap. Note that this requires that the signer have approved 
    // the contract beforehand.
    const tx = await router.multiSwapTokensForTokens(
        data.token_in,
        data.token_out,
        signer.address,
        ONE_ETH,
        ethers.BigNumber.from(1), // In production, this value should be propagated by user slippage settings. Must be at least 1.
        ethers.BigNumber.from(1775120065),
        res.swap_paths,
        {
            gasLimit: bufferedGasEstimate,
        }
    )

    console.log(tx.hash);
}

main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});

Last updated