Skip to content

Commit

Permalink
Merge pull request #250 from balancer-labs/develop
Browse files Browse the repository at this point in the history
Release 0.1.43
  • Loading branch information
johngrantuk authored Dec 19, 2022
2 parents a6e426c + 949dd7d commit f53bb7d
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 125 deletions.
4 changes: 2 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.41",
"version": "0.1.43",
"description": "JavaScript SDK for interacting with the Balancer Protocol V2",
"license": "GPL-3.0-only",
"homepage": "https://github.com/balancer-labs/balancer-sdk#readme",
Expand Down Expand Up @@ -89,7 +89,7 @@
"typescript": "^4.0.2"
},
"dependencies": {
"@balancer-labs/sor": "^4.0.1-beta.15",
"@balancer-labs/sor": "^4.0.1-beta.16",
"@balancer-labs/typechain": "^1.0.0",
"axios": "^0.24.0",
"graphql": "^15.6.1",
Expand Down
11 changes: 11 additions & 0 deletions balancer-js/src/lib/utils/poolHelper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { parseFixed } from '@ethersproject/bignumber';
import { Pool } from '../../types';
import { _computeScalingFactor } from '@/lib/utils/solidityMaths';

const AMP_PRECISION = 3; // number of decimals -> precision 1000

Expand All @@ -14,9 +15,17 @@ export const parsePoolInfo = (pool: Pool) => {
const parsedDecimals = pool.tokens.map((token) => {
return token.decimals ? token.decimals.toString() : undefined;
});
const scalingFactors = parsedDecimals.map((decimals) =>
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
_computeScalingFactor(BigInt(decimals!))
);
const parsedBalances = pool.tokens.map((token) =>
parseFixed(token.balance, token.decimals).toString()
);
// This assumes token.balance is in human scale (e.g. from SG)
const upScaledBalances = pool.tokens.map((token) =>
parseFixed(token.balance, 18).toString()
);
const parsedWeights = pool.tokens.map((token) => {
return token.weight ? parseFixed(token.weight, 18).toString() : undefined;
});
Expand All @@ -39,5 +48,7 @@ export const parsePoolInfo = (pool: Pool) => {
parsedAmp,
parsedTotalShares,
parsedSwapFee,
upScaledBalances,
scalingFactors,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -172,48 +172,45 @@ describe('exit stable pools execution', async () => {
});

context('exitExactTokensOut', async () => {
// FIXME: test scenario not working due to stable math issues with non-proportional inputs
// Frontend currently does not support exiting with more than one exact token out

// context('all tokens out', async () => {
// before(async function () {
// amountsOut = pool.tokens.map((t, i) =>
// parseFixed(t.balance, t.decimals)
// .div(amountsOutDiv)
// .mul(i + 1)
// .toString()
// );

// await testFlow(
// controller.buildExitExactTokensOut(
// signerAddress,
// tokensOut.map((t) => t.address),
// amountsOut,
// slippage
// ),
// pool.tokensList
// );
// });

// it('should work', async () => {
// expect(transactionReceipt.status).to.eql(1);
// });

// it('tokens balance should increase by exact amountsOut', async () => {
// for (let i = 0; i < tokensBalanceAfter.length; i++) {
// expect(
// tokensBalanceAfter[i]
// .sub(tokensBalanceBefore[i])
// .eq(tokensMinBalanceIncrease[i])
// ).to.be.true;
// }
// });

// it('bpt balance should decrease by max bptMaxBalanceDecrease', async () => {
// expect(bptBalanceBefore.sub(bptBalanceAfter).lte(bptMaxBalanceDecrease))
// .to.be.true;
// });
// });
context('all tokens out', async () => {
before(async function () {
amountsOut = pool.tokens.map((t, i) =>
parseFixed(t.balance, t.decimals)
.div(amountsOutDiv)
.mul(i + 1)
.toString()
);

await testFlow(
controller.buildExitExactTokensOut(
signerAddress,
tokensOut.map((t) => t.address),
amountsOut,
slippage
),
pool.tokensList
);
});

it('should work', async () => {
expect(transactionReceipt.status).to.eql(1);
});

it('tokens balance should increase by exact amountsOut', async () => {
for (let i = 0; i < tokensBalanceAfter.length; i++) {
expect(
tokensBalanceAfter[i]
.sub(tokensBalanceBefore[i])
.eq(tokensMinBalanceIncrease[i])
).to.be.true;
}
});

it('bpt balance should decrease by max bptMaxBalanceDecrease', async () => {
expect(bptBalanceBefore.sub(bptBalanceAfter).lte(bptMaxBalanceDecrease))
.to.be.true;
});
});

context('single token out', async () => {
before(async function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { addSlippage, subSlippage } from '@/lib/utils/slippageHelper';
import { balancerVault } from '@/lib/constants/config';
import { BalancerError, BalancerErrorCode } from '@/balancerErrors';
import { StablePoolEncoder } from '@/pool-stable';
import { _downscaleDownArray, _upscaleArray } from '@/lib/utils/solidityMaths';

export class StablePoolExit implements ExitConcern {
buildExitExactBPTIn = ({
Expand Down Expand Up @@ -49,10 +50,11 @@ export class StablePoolExit implements ExitConcern {
// Parse pool info into EVM amounts in order to match amountsIn scalling
const {
parsedTokens,
parsedBalances,
parsedAmp,
parsedTotalShares,
parsedSwapFee,
upScaledBalances,
scalingFactors,
} = parsePoolInfo(pool);

// Replace WETH address with ETH - required for exiting with ETH
Expand All @@ -62,10 +64,12 @@ export class StablePoolExit implements ExitConcern {

// Sort pool info based on tokens addresses
const assetHelpers = new AssetHelpers(wrappedNativeAsset);
const [sortedTokens, sortedBalances] = assetHelpers.sortTokens(
shouldUnwrapNativeAsset ? unwrappedTokens : parsedTokens,
parsedBalances
) as [string[], string[]];
const [sortedTokens, sortedUpscaledBalances, sortedScalingFactors] =
assetHelpers.sortTokens(
shouldUnwrapNativeAsset ? unwrappedTokens : parsedTokens,
upScaledBalances,
scalingFactors
) as [string[], string[], string[]];

let minAmountsOut = Array(parsedTokens.length).fill('0');
let userData: string;
Expand All @@ -78,7 +82,7 @@ export class StablePoolExit implements ExitConcern {
// Calculate amount out given BPT in
const amountOut = SOR.StableMathBigInt._calcTokenOutGivenExactBptIn(
BigInt(parsedAmp as string),
sortedBalances.map((b) => BigInt(b)),
sortedUpscaledBalances.map((b) => BigInt(b)),
singleTokenMaxOutIndex,
BigInt(bptIn),
BigInt(parsedTotalShares),
Expand All @@ -100,13 +104,18 @@ export class StablePoolExit implements ExitConcern {

// Calculate amount out given BPT in
const amountsOut = SOR.StableMathBigInt._calcTokensOutGivenExactBptIn(
sortedBalances.map((b) => BigInt(b)),
sortedUpscaledBalances.map((b) => BigInt(b)),
BigInt(bptIn),
BigInt(parsedTotalShares)
).map((amount) => amount.toString());

// Maths return numbers scaled to 18 decimals. Must scale down to token decimals.
const amountsOutScaledDown = _downscaleDownArray(
amountsOut.map((a) => BigInt(a)),
sortedScalingFactors.map((a) => BigInt(a))
);
// Apply slippage tolerance
minAmountsOut = amountsOut.map((amount) => {
minAmountsOut = amountsOutScaledDown.map((amount) => {
const minAmount = subSlippage(
BigNumber.from(amount),
BigNumber.from(slippage)
Expand Down Expand Up @@ -173,28 +182,37 @@ export class StablePoolExit implements ExitConcern {
// Parse pool info into EVM amounts in order to match amountsOut scalling
const {
parsedTokens,
parsedBalances,
parsedAmp,
parsedTotalShares,
parsedSwapFee,
upScaledBalances,
scalingFactors,
} = parsePoolInfo(pool);

// Sort pool info based on tokens addresses
const assetHelpers = new AssetHelpers(wrappedNativeAsset);
const [, sortedBalances] = assetHelpers.sortTokens(
parsedTokens,
parsedBalances
) as [string[], string[]];
const [sortedTokens, sortedAmounts] = assetHelpers.sortTokens(
const [, sortedUpScaledBalances, sortedScalingFactors] =
assetHelpers.sortTokens(
parsedTokens,
upScaledBalances,
scalingFactors
) as [string[], string[], string[]];
const [sortedTokens, sortedAmountsOut] = assetHelpers.sortTokens(
tokensOut,
amountsOut
) as [string[], string[]];

// Maths should use upscaled amounts, e.g. 1USDC => 1e18 not 1e6
const upScaledAmountsOut = _upscaleArray(
sortedAmountsOut.map((a) => BigInt(a)),
sortedScalingFactors.map((a) => BigInt(a))
);

// Calculate expected BPT in given tokens out
const bptIn = SOR.StableMathBigInt._calcBptInGivenExactTokensOut(
BigInt(parsedAmp as string),
sortedBalances.map((b) => BigInt(b)),
sortedAmounts.map((a) => BigInt(a)),
sortedUpScaledBalances.map((b) => BigInt(b)),
upScaledAmountsOut,
BigInt(parsedTotalShares),
BigInt(parsedSwapFee)
).toString();
Expand All @@ -206,7 +224,7 @@ export class StablePoolExit implements ExitConcern {
).toString();

const userData = StablePoolEncoder.exitBPTInForExactTokensOut(
sortedAmounts,
sortedAmountsOut,
maxBPTIn
);

Expand All @@ -218,7 +236,7 @@ export class StablePoolExit implements ExitConcern {
recipient: exiter,
exitPoolRequest: {
assets: sortedTokens,
minAmountsOut: sortedAmounts,
minAmountsOut: sortedAmountsOut,
userData,
toInternalBalance: false,
},
Expand All @@ -238,7 +256,7 @@ export class StablePoolExit implements ExitConcern {
functionName,
attributes,
data,
minAmountsOut: sortedAmounts,
minAmountsOut: sortedAmountsOut,
maxBPTIn,
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ describe('join execution', async () => {
minBPTOut,
true
);
expect(priceImpact).to.eql('100000444261607');
expect(priceImpact).to.eql('100000000006037');
});

it('should increase BPT balance', async () => {
Expand Down

This file was deleted.

Loading

0 comments on commit f53bb7d

Please sign in to comment.