Skip to content

Commit

Permalink
Merge pull request #106 from balancer-labs/develop
Browse files Browse the repository at this point in the history
0.1.17
  • Loading branch information
johngrantuk authored Jul 8, 2022
2 parents 6a12856 + 6270e48 commit d4b3c33
Show file tree
Hide file tree
Showing 64 changed files with 3,605 additions and 2,029 deletions.
32 changes: 32 additions & 0 deletions balancer-js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,38 @@ async getSpotPrice(

[Example](./examples/spotPrice.ts)

## Join Pool

Exposes Join functionality allowing user to join pools.

```js
const balancer = new BalancerSDK(sdkConfig);
const pool = await balancer.poolsProvider.find(poolId);
const { to, functionName, attributes, data } = pool.buildJoin(params);
```

### #buildJoin

Builds a join transaction.

```js
/**
* @param { string } joiner - Address used to exit pool.
* @param { string[] } tokensIn - Token addresses provided for joining pool (same length and order as amountsIn).
* @param { string[] } amountsIn - Token amounts provided for joining pool in EVM amounts.
* @param { string } slippage - Maximum slippage tolerance in bps i.e. 50 = 0.5%.
* @returns { Promise<JoinPoolAttributes> } Returns join transaction ready to send with signer.sendTransaction.
*/
buildJoin: (
joiner: string,
tokensIn: string[],
amountsIn: string[],
slippage: string
) => Promise<JoinPoolAttributes>;
```

[Example](./examples/join.ts)

## RelayerService

Relayers are (user opt-in, audited) contracts that can make calls to the vault (with the transaction “sender” being any arbitrary address) and use the sender’s ERC20 vault allowance, internal balance or BPTs on their behalf.
Expand Down
101 changes: 101 additions & 0 deletions balancer-js/examples/join.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import dotenv from 'dotenv';
import { Wallet } from '@ethersproject/wallet';
import { JsonRpcProvider } from '@ethersproject/providers';
import { BalancerSDK, Network, PoolModel } from '../src/index';
import { formatFixed } from '@ethersproject/bignumber';
import { forkSetup } from '../src/test/lib/utils';
import { ADDRESSES } from '../src/test/lib/constants';

dotenv.config();

const { ALCHEMY_URL: jsonRpcUrl } = process.env;

// Slots used to set the account balance for each token through hardhat_setStorageAt
// Info fetched using npm package slot20
const wBTC_SLOT = 0;
const wETH_SLOT = 3;
const slots = [wBTC_SLOT, wETH_SLOT];
const initialBalances = ['1000000000', '100000000000000000000'];

// Public test account with 10000 ETH
// publicKey = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266';
const privateKey =
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
const wallet = new Wallet(privateKey);

/*
Example showing how to use Pools module to join pools.
*/
async function join() {
const network = Network.MAINNET;
const rpcUrl = 'http://127.0.0.1:8545';
const provider = new JsonRpcProvider(rpcUrl, network);

const poolId =
'0xa6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e'; // 50/50 WBTC/WETH Pool
const tokensIn = [
ADDRESSES[network].WBTC?.address,
ADDRESSES[network].WETH?.address,
]; // Tokens that will be provided to pool by joiner
const amountsIn = ['10000000', '1000000000000000000'];
const slippage = '100'; // 100 bps = 1%

const sdkConfig = {
network,
rpcUrl,
};
const balancer = new BalancerSDK(sdkConfig);

// Sets up local fork granting signer initial balances and token approvals
await forkSetup(
balancer,
provider,
tokensIn as string[],
slots,
initialBalances,
jsonRpcUrl as string
);

// Use SDK to find pool info
const pool: PoolModel | undefined = await balancer.poolsProvider.find(poolId);
if (!pool) throw new Error('Pool not found');

// Checking balances to confirm success
const bptContract = balancer.contracts.ERC20(pool.address, provider);
const bptBalanceBefore = await bptContract.balanceOf(wallet.address);

// Use SDK to create join
const { to, data, minBPTOut } = await pool.buildJoin(
wallet.address,
tokensIn as string[],
amountsIn,
slippage
);

// Submit join tx
const transactionResponse = await wallet.connect(provider).sendTransaction({
to,
data,
// gasPrice: '6000000000', // gas inputs are optional
// gasLimit: '2000000', // gas inputs are optional
});

const transactionReceipt = await transactionResponse.wait();

const bptBalanceAfter = await bptContract.balanceOf(wallet.address);
console.log(
'BPT Balance before joining pool: ',
formatFixed(bptBalanceBefore, 18)
);
console.log(
'BPT Balance after joining pool: ',
formatFixed(bptBalanceAfter, 18)
);
console.log(
'Minimum BPT balance expected after join: ',
formatFixed(minBPTOut, 18)
);
}

// yarn examples:run ./examples/join.ts
join();
12 changes: 7 additions & 5 deletions balancer-js/examples/pools/calculateLiquidity.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import {
Liquidity,
StaticPoolProvider,
StaticPoolRepository,
StaticTokenPriceProvider,
Pool,
TokenPrices,
} from '../../src';
import { parseFixed, formatFixed } from '@ethersproject/bignumber';
import { FallbackPoolProvider } from '../../src/modules/data-providers/pool/fallback.provider';
import { formatFixed } from '@ethersproject/bignumber';
import { parseFixed } from '../../src/lib/utils/math';
import { FallbackPoolRepository } from '../../src/modules/data/pool';
import POOLS from './pools.json';
import DECORATED_POOLS from './decorated-pools.json';
import TOKENS from './tokens.json';
Expand All @@ -28,8 +29,8 @@ TOKENS.forEach((token) => {
});

// const sorPoolProvider = new SORPoolProvider(config);
const staticPoolProvider = new StaticPoolProvider(POOLS as Pool[]);
const poolProvider = new FallbackPoolProvider([
const staticPoolProvider = new StaticPoolRepository(POOLS as Pool[]);
const poolProvider = new FallbackPoolRepository([
// sorPoolProvider,
staticPoolProvider,
]);
Expand Down Expand Up @@ -78,4 +79,5 @@ async function getLiquidity(poolIds: string[]) {
process.exit(0);
}

// yarn examples:run ./examples/pools/calculateLiquidity.ts
getLiquidity(poolIds);
6 changes: 4 additions & 2 deletions balancer-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@balancer-labs/sdk",
"version": "0.1.16",
"version": "0.1.17",
"description": "JavaScript SDK for interacting with the Balancer Protocol V2",
"license": "GPL-3.0-only",
"homepage": "https://github.com/balancer-labs/balancer-sdk/balancer-js#readme",
Expand Down Expand Up @@ -39,7 +39,9 @@
"@ethersproject/constants": "^5.4.0",
"@ethersproject/contracts": "^5.4.0",
"@ethersproject/providers": "^5.4.5",
"@ethersproject/solidity": "^5.6.1",
"@ethersproject/wallet": "^5.5.0",
"@georgeroman/balancer-v2-pools": "^0.0.5",
"@graphql-codegen/add": "^3.1.0",
"@graphql-codegen/cli": "^2.3.0",
"@graphql-codegen/introspection": "^2.1.0",
Expand Down Expand Up @@ -82,7 +84,7 @@
"typescript": "^4.0.2"
},
"dependencies": {
"@balancer-labs/sor": "^4.0.1-beta.0",
"@balancer-labs/sor": "^4.0.1-beta.1",
"@balancer-labs/typechain": "^1.0.0",
"axios": "^0.24.0",
"bignumber.js": "^9.0.2",
Expand Down
9 changes: 9 additions & 0 deletions balancer-js/src/balancerErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export enum BalancerErrorCode {
UNSUPPORTED_POOL_TYPE = 'UNSUPPORTED_POOL_TYPE',
UNSUPPORTED_PAIR = 'UNSUPPORTED_PAIR',
NO_POOL_DATA = 'NO_POOL_DATA',
INPUT_LENGTH_MISMATCH = 'INPUT_LENGTH_MISMATCH',
MISSING_DECIMALS = 'MISSING_DECIMALS',
MISSING_WEIGHT = 'MISSING_WEIGHT',
}

export class BalancerError extends Error {
Expand All @@ -33,6 +36,12 @@ export class BalancerError extends Error {
return 'unsupported token pair';
case BalancerErrorCode.NO_POOL_DATA:
return 'no pool data';
case BalancerErrorCode.INPUT_LENGTH_MISMATCH:
return 'input length mismatch';
case BalancerErrorCode.MISSING_DECIMALS:
return 'missing decimals';
case BalancerErrorCode.MISSING_WEIGHT:
return 'missing weight';
default:
return 'Unknown error';
}
Expand Down
4 changes: 1 addition & 3 deletions balancer-js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ export * from './modules/swaps/swaps.module';
export * from './modules/subgraph/subgraph.module';
export * from './modules/sor/sor.module';
export * from './modules/pools/pools.module';
export * from './modules/data-providers/pool/static.provider';
export * from './modules/data-providers/token/static.provider';
export * from './modules/data-providers/token-price/static.provider';
export * from './modules/data';
export * from './balancerErrors';
export {
SwapInfo,
Expand Down
21 changes: 21 additions & 0 deletions balancer-js/src/lib/utils/math.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { expect } from 'chai';
import { parseFixed } from './math';

describe('utils/math', () => {
describe('parseFixed', () => {
it('Should work with simple integers', () => {
const result = parseFixed('15');
expect(result.toString()).to.be.eq('15');
});

it('Should work with decimal strings', () => {
const result = parseFixed('15.123', 3);
expect(result.toString()).to.be.eq('15123');
});

it('Should work with decimal strings that have too many decimals', () => {
const result = parseFixed('15.123456', 3);
expect(result.toString()).to.be.eq('15123');
});
});
});
16 changes: 16 additions & 0 deletions balancer-js/src/lib/utils/math.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {
BigNumber,
BigNumberish,
parseFixed as _parseFixed,
} from '@ethersproject/bignumber';

export function parseFixed(value: string, decimals?: BigNumberish): BigNumber {
const valueWithTrimmedDecimals = new RegExp(`[0-9]+\\.?[0-9]{0,${decimals}}`);
const result = value.match(valueWithTrimmedDecimals);
let parsedValue = value;
if (result) {
parsedValue = result[0];
}

return _parseFixed(parsedValue, decimals);
}
39 changes: 39 additions & 0 deletions balancer-js/src/lib/utils/slippageHelper.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { expect } from 'chai';
import { BigNumber } from 'ethers';
import { subSlippage, addSlippage } from './slippageHelper';

describe('slippage helper', () => {
const amount = BigNumber.from('100');
const slippageAsBasisPoints = BigNumber.from('100'); // 1%
const slippageAsPercentage = BigNumber.from('1'); // 1%

describe('subSlippage', () => {
context('when slippage input as basis points', () => {
const result = subSlippage(amount, slippageAsBasisPoints).toString();
it('should work', () => {
expect(result).to.be.equal('99');
});
});
context('when slippage input as percentage', () => {
const result = subSlippage(amount, slippageAsPercentage).toString();
it('should fail', () => {
expect(result).to.be.not.equal('99');
});
});
});

describe('addSlippage', () => {
context('when slippage input as basis points', () => {
const result = addSlippage(amount, slippageAsBasisPoints).toString();
it('should work', () => {
expect(result).to.be.equal('101');
});
});
context('when slippage input as percentage', () => {
const result = addSlippage(amount, slippageAsPercentage).toString();
it('should fail', () => {
expect(result).to.be.not.equal('101');
});
});
});
});
48 changes: 48 additions & 0 deletions balancer-js/src/lib/utils/slippageHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { BigNumber } from '@ethersproject/bignumber';

const bpsPerOne = BigNumber.from('10000'); // number of basis points in 100%

/**
* Multiplies input by slippage amount
*
* @param {BigNumber} amount Input amount (not parsed)
* @param {BigNumber} slippage Slippage value in bps - i.e. 50 = 0.5%
* @returns Result delta from multiplying amount and slippage
*/
export const mulSlippage = (
amount: BigNumber,
slippage: BigNumber
): BigNumber => {
const delta = amount.mul(slippage).div(bpsPerOne);
return delta;
};

/**
* Reduce input amount by slippage factor
*
* @param {BigNumber} amount Input in EVM amounts
* @param {BigNumber} slippage Slippage value in bps - i.e. 50 = 0.5%
* @returns Result amount subtracting slippage
*/
export const subSlippage = (
amount: BigNumber,
slippage: BigNumber
): BigNumber => {
const delta = mulSlippage(amount, slippage);
return amount.sub(delta);
};

/**
* Increase input amount by slippage factor
*
* @param {BigNumber} amount Input in EVM amounts
* @param {BigNumber} slippage Slippage value in bps - i.e. 50 = 0.5%
* @returns Result amount adding slippage
*/
export const addSlippage = (
amount: BigNumber,
slippage: BigNumber
): BigNumber => {
const delta = mulSlippage(amount, slippage);
return amount.add(delta);
};
Loading

0 comments on commit d4b3c33

Please sign in to comment.