Skip to content

Add BalancerV1ExchangeAdapter tests #72

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ contract BalancerV1ExchangeAdapter {

/* ============ State Variables ============ */

// Address of Uniswap V2 Router02 contract
// Address of Balancer V1 Proxy contract
address public immutable balancerProxy;
// Balancer proxy function string for swapping exact tokens for a minimum of receive tokens
string internal constant EXACT_IN = "smartSwapExactIn(address,address,uint256,uint256,uint256)";
Expand Down Expand Up @@ -99,15 +99,15 @@ contract BalancerV1ExchangeAdapter {
/**
* Generate data parameter to be passed to `getTradeCallData`. Returns encoded bool to select trade function.
*
* @param _sellComponent Address of the token to be sold
* @param _buyComponent Address of the token to be bought
* @param _sourceToken Address of the source token to be sold
* @param _destinationToken Address of the destination token to buy
* @param _fixIn Boolean representing if input tokens amount is fixed
*
* @return bytes Data parameter to be passed to `getTradeCallData`
*/
function generateDataParam(address _sellComponent, address _buyComponent, bool _fixIn)
function generateDataParam(address _sourceToken, address _destinationToken, bool _fixIn)
external
view
pure
returns (bytes memory)
{
return abi.encode(_fixIn);
Expand All @@ -121,4 +121,13 @@ contract BalancerV1ExchangeAdapter {
function getSpender() external view returns (address) {
return balancerProxy;
}

/**
* Helper that returns the encoded data of boolean indicating the Balancer function to use
*
* @return bytes Encoded data used for trading on Balancer
*/
function getBalancerExchangeData(bool _shouldSwapFixedInputAmount) external pure returns (bytes memory) {
return abi.encode(_shouldSwapFixedInputAmount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,20 @@ contract UniswapV2ExchangeAdapterV2 {
/**
* Generate data parameter to be passed to `getTradeCallData`. Returns encoded trade paths and bool to select trade function.
*
* @param _sellComponent Address of the token to be sold
* @param _buyComponent Address of the token to be bought
* @param _sourceToken Address of the source token to be sold
* @param _destinationToken Address of the destination token to buy
* @param _fixIn Boolean representing if input tokens amount is fixed
*
* @return bytes Data parameter to be passed to `getTradeCallData`
*/
function generateDataParam(address _sellComponent, address _buyComponent, bool _fixIn)
function generateDataParam(address _sourceToken, address _destinationToken, bool _fixIn)
external
view
pure
returns (bytes memory)
{
address[] memory path = new address[](2);
path[0] = _sellComponent;
path[1] = _buyComponent;
path[0] = _sourceToken;
path[1] = _destinationToken;
return abi.encode(path, _fixIn);
}

Expand All @@ -135,7 +135,7 @@ contract UniswapV2ExchangeAdapterV2 {
*
* @return bytes Encoded data used for trading on Uniswap
*/
function getUniswapExchangeData(address[] memory _path, bool _shouldSwapExactTokensForTokens) external view returns (bytes memory) {
function getUniswapExchangeData(address[] memory _path, bool _shouldSwapExactTokensForTokens) external pure returns (bytes memory) {
return abi.encode(_path, _shouldSwapExactTokensForTokens);
}
}
250 changes: 250 additions & 0 deletions test/protocol/integration/balancerV1ExchangeAdapter.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
import "module-alias/register";

import { BigNumber } from "@ethersproject/bignumber";
import { defaultAbiCoder } from "ethers/lib/utils";

import { Address, Bytes } from "@utils/types";
import { Account } from "@utils/test/types";
import {
EMPTY_BYTES,
THREE,
ZERO,
} from "@utils/constants";
import { BalancerV1ExchangeAdapter } from "@utils/contracts";
import DeployHelper from "@utils/deploys";
import {
ether,
} from "@utils/index";
import {
addSnapshotBeforeRestoreAfterEach,
getAccounts,
getSystemFixture,
getBalancerFixture,
getWaffleExpect
} from "@utils/test/index";

import { SystemFixture, BalancerFixture } from "@utils/fixtures";

const expect = getWaffleExpect();

describe("BalancerV1ExchangeAdapter", () => {
let owner: Account;
let mockSetToken: Account;
let deployer: DeployHelper;
let setup: SystemFixture;
let balancerSetup: BalancerFixture;

let balancerV1ExchangeAdapter: BalancerV1ExchangeAdapter;

before(async () => {
[
owner,
mockSetToken,
] = await getAccounts();

deployer = new DeployHelper(owner.wallet);
setup = getSystemFixture(owner.address);
await setup.initialize();

balancerSetup = getBalancerFixture(owner.address);
await balancerSetup.initialize(
owner,
setup.weth,
setup.wbtc,
setup.dai
);

balancerV1ExchangeAdapter = await deployer.adapters.deployBalancerV1ExchangeAdapter(balancerSetup.exchange.address);
});

addSnapshotBeforeRestoreAfterEach();

describe("constructor", async () => {
let subjectBalancerProxyAddress: Address;

beforeEach(async () => {
subjectBalancerProxyAddress = balancerSetup.exchange.address;
});

async function subject(): Promise<any> {
return await deployer.adapters.deployBalancerV1ExchangeAdapter(subjectBalancerProxyAddress);
}

it("should have the correct proxy address", async () => {
const deployedBalancerV1ExchangeAdapter = await subject();

const actualProxyAddress = await deployedBalancerV1ExchangeAdapter.balancerProxy();
expect(actualProxyAddress).to.eq(subjectBalancerProxyAddress);
});
});

describe("getSpender", async () => {
async function subject(): Promise<any> {
return await balancerV1ExchangeAdapter.getSpender();
}

it("should return the correct spender address", async () => {
const spender = await subject();

expect(spender).to.eq(balancerSetup.exchange.address);
});
});

describe("getBalancerExchangeData", async () => {
let subjectShouldSwapFixedInputAmount: boolean;

beforeEach(async () => {
subjectShouldSwapFixedInputAmount = true;
});

async function subject(): Promise<any> {
return await balancerV1ExchangeAdapter.getBalancerExchangeData(subjectShouldSwapFixedInputAmount);
}

it("should return the correct data", async () => {
const balancerData = await subject();
const expectedData = defaultAbiCoder.encode(
["bool"],
[subjectShouldSwapFixedInputAmount]
);

expect(balancerData).to.eq(expectedData);
});
});

describe("generateDataParam", async () => {
let sourceToken: Address;
let destinationToken: Address;

let subjectSourceToken: Address;
let subjectDestinationToken: Address;
let subjectFixIn: boolean;

beforeEach(async () => {
sourceToken = setup.wbtc.address;
destinationToken = setup.dai.address;

subjectSourceToken = sourceToken;
subjectDestinationToken = destinationToken;
});

async function subject(): Promise<any> {
return await balancerV1ExchangeAdapter.generateDataParam(
subjectSourceToken,
subjectDestinationToken,
subjectFixIn
);
}

describe("when boolean fixed input amount is true", async () => {
beforeEach(async () => {
subjectFixIn = true;
});

it("should return the correct trade calldata", async () => {
const dataParam = await subject();

const expectedDataParam = defaultAbiCoder.encode(
["bool"],
[subjectFixIn]
);
expect(JSON.stringify(dataParam)).to.eq(JSON.stringify(expectedDataParam));
});
});

describe("when boolean fixed input amount is false", async () => {
beforeEach(async () => {
subjectFixIn = false;
});

it("should return the correct trade calldata", async () => {
const dataParam = await subject();

const expectedDataParam = defaultAbiCoder.encode(
["bool"],
[subjectFixIn]
);
expect(JSON.stringify(dataParam)).to.eq(JSON.stringify(expectedDataParam));
});
});
});

describe("getTradeCalldata", async () => {
let sourceToken: Address;
let destinationToken: Address;
let sourceQuantity: BigNumber;
let destinationQuantity: BigNumber;

let subjectMockSetToken: Address;
let subjectSourceToken: Address;
let subjectDestinationToken: Address;
let subjectSourceQuantity: BigNumber;
let subjectMinDestinationQuantity: BigNumber;
let subjectData: Bytes;

beforeEach(async () => {
sourceToken = setup.wbtc.address; // WBTC Address
sourceQuantity = BigNumber.from(100000000); // Trade 1 WBTC
destinationToken = setup.dai.address; // DAI Address
destinationQuantity = ether(30000); // Receive at least 30k DAI

subjectSourceToken = sourceToken;
subjectDestinationToken = destinationToken;
subjectMockSetToken = mockSetToken.address;
subjectSourceQuantity = sourceQuantity;
subjectMinDestinationQuantity = destinationQuantity;
subjectData = EMPTY_BYTES;
});

async function subject(): Promise<any> {
return await balancerV1ExchangeAdapter.getTradeCalldata(
subjectSourceToken,
subjectDestinationToken,
subjectMockSetToken,
subjectSourceQuantity,
subjectMinDestinationQuantity,
subjectData,
);
}

describe("when boolean fixed input amount is true", async () => {
beforeEach(async () => {
const shouldSwapFixedInputAmount = true;
subjectData = defaultAbiCoder.encode(["bool"], [shouldSwapFixedInputAmount]);
});

it("should return the correct trade calldata", async () => {
const calldata = await subject();

const expectedCallData = balancerSetup.exchange.interface.encodeFunctionData("smartSwapExactIn", [
sourceToken,
destinationToken,
sourceQuantity,
destinationQuantity,
THREE,
]);
expect(JSON.stringify(calldata)).to.eq(JSON.stringify([balancerSetup.exchange.address, ZERO, expectedCallData]));
});
});

describe("when boolean fixed input amount is false", async () => {
beforeEach(async () => {
const shouldSwapFixedInputAmount = false;
subjectData = defaultAbiCoder.encode(["bool"], [shouldSwapFixedInputAmount]);
});

it("should return the correct trade calldata", async () => {
const calldata = await subject();

const expectedCallData = balancerSetup.exchange.interface.encodeFunctionData("smartSwapExactOut", [
sourceToken,
destinationToken,
destinationQuantity, // Source and destination quantity are flipped for smartSwapExactOut
sourceQuantity,
THREE,
]);
expect(JSON.stringify(calldata)).to.eq(JSON.stringify([balancerSetup.exchange.address, ZERO, expectedCallData]));
});
});
});
});
Loading