@ethersproject/constants#Zero TypeScript Examples

The following examples show how to use @ethersproject/constants#Zero. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: byterepr.ts    From clarity with Apache License 2.0 6 votes vote down vote up
toBytesNumber = (
  bitSize: number,
  signed: boolean,
  value: BigNumberish
) => {
  let v = BigNumber.from(value);

  // Check bounds are safe for encoding
  const maxUintValue = MaxUint256.mask(bitSize);
  if (signed) {
    const bounds = maxUintValue.mask(bitSize - 1); // 1 bit for signed
    if (v.gt(bounds) || v.lt(bounds.add(One).mul(NegativeOne))) {
      throw new Error('value out-of-bounds, value: ' + value);
    }
  } else if (v.lt(Zero) || v.gt(maxUintValue.mask(bitSize))) {
    throw new Error('value out-of-bounds, value: ' + value);
  }
  v = v.toTwos(bitSize).mask(bitSize);
  const bytes = arrayify(v);
  if (v.gte(0)) {
    // for positive number, we had to deal with paddings
    if (bitSize > 64) {
      // for u128, u256, u512, we have to and append extra byte for length
      return concat([bytes, Uint8Array.from([bytes.length])]).reverse();
    } else {
      // for other types, we have to add padding 0s
      const byteLength = bitSize / 8;
      return concat([
        bytes.reverse(),
        new Uint8Array(byteLength - bytes.length)
      ]);
    }
  } else {
    return bytes.reverse();
  }
}
Example #2
Source File: App.tsx    From ether-swr with MIT License 6 votes vote down vote up
TokenList = ({ chainId }: { chainId: number }) => {
  const { account } = useWeb3React<Web3Provider>()
  const tokens = TOKENS_BY_NETWORK[chainId]

  // Multiple calls example
  const { data: balances } = useBalanceOf<BigNumber[]>(
    tokens.map(t => t.address),
    account!
  )
  return (
    <>
      {balances &&
        TOKENS_BY_NETWORK[chainId]
          .filter((t, index) => balances[index].gt(Zero))
          .map(token => <TokenBalance key={token.address} {...token} />)}
    </>
  )
}
Example #3
Source File: normalizedWeights.ts    From balancer-v2-monorepo with GNU General Public License v3.0 6 votes vote down vote up
/**
 * Normalize an array of token weights to ensure they sum to `1e18`
 * @param weights - an array of token weights to be normalized
 * @returns an equivalent set of normalized weights
 */
export function toNormalizedWeights(weights: BigNumber[]): BigNumber[] {
  // When the number is exactly equal to the max, normalizing with common inputs
  // leads to a value < 0.01, which reverts. In this case fill in the weights exactly.
  if (weights.length == MaxWeightedTokens) {
    return Array(MaxWeightedTokens).fill(ONE.div(MaxWeightedTokens));
  }

  const sum = weights.reduce((total, weight) => total.add(weight), Zero);
  if (sum.eq(ONE)) return weights;

  const normalizedWeights = [];
  let normalizedSum = Zero;
  for (let index = 0; index < weights.length; index++) {
    if (index < weights.length - 1) {
      normalizedWeights[index] = weights[index].mul(ONE).div(sum);
      normalizedSum = normalizedSum.add(normalizedWeights[index]);
    } else {
      normalizedWeights[index] = ONE.sub(normalizedSum);
    }
  }

  return normalizedWeights;
}
Example #4
Source File: parseTransaction.ts    From bodhi.js with Apache License 2.0 5 votes vote down vote up
function handleNumber(value: string): BigNumber {
  if (value === '0x') {
    return Zero;
  }
  return BigNumber.from(value);
}
Example #5
Source File: normalizedWeights.ts    From balancer-v2-monorepo with GNU General Public License v3.0 5 votes vote down vote up
isNormalizedWeights = (weights: BigNumberish[]): boolean => {
  const totalWeight = weights.reduce((total: BigNumber, weight) => total.add(weight), Zero);
  return totalWeight.eq(ONE);
}
Example #6
Source File: ByteConverters.ts    From casper-js-sdk with Apache License 2.0 5 votes vote down vote up
toBytesNumber = (bitSize: number, signed: boolean) => (
  value: BigNumberish
): Uint8Array => {
  const val = BigNumber.from(value);

  // Check bounds are safe for encoding
  const maxUintValue = MaxUint256.mask(bitSize);

  if (signed) {
    const bounds = maxUintValue.mask(bitSize - 1); // 1 bit for signed
    if (val.gt(bounds) || val.lt(bounds.add(One).mul(NegativeOne))) {
      throw new Error('value out-of-bounds, value: ' + value);
    }
  } else if (val.lt(Zero) || val.gt(maxUintValue.mask(bitSize))) {
    throw new Error('value out-of-bounds, value: ' + value);
  }

  const valTwos = val.toTwos(bitSize).mask(bitSize);

  const bytes = arrayify(valTwos);

  if (valTwos.gte(0)) {
    // for positive number, we had to deal with paddings
    if (bitSize > 64) {
      // if zero just return zero
      if (valTwos.eq(0)) {
        return bytes;
      }
      // for u128, u256, u512, we have to and append extra byte for length
      return concat([bytes, Uint8Array.from([bytes.length])])
        .slice()
        .reverse();
    } else {
      // for other types, we have to add padding 0s
      const byteLength = bitSize / 8;
      return concat([
        bytes.slice().reverse(),
        new Uint8Array(byteLength - bytes.length)
      ]);
    }
  } else {
    return bytes.reverse();
  }
}
Example #7
Source File: index.ts    From snapshot-strategies with MIT License 5 votes vote down vote up
async function getVaultBalance(network, provider, addresses, blockTag) {
  const vaultMulti = new Multicaller(network, provider, vaultAbi, { blockTag });

  vaultMulti.call(
    CAKE_VAULT_ADDRESS,
    CAKE_VAULT_ADDRESS,
    'getPricePerFullShare'
  );

  addresses.forEach((address) =>
    vaultMulti.call(
      `${CAKE_VAULT_ADDRESS}-${address}`,
      CAKE_VAULT_ADDRESS,
      'userInfo',
      [address]
    )
  );

  if (blockTag >= IFO_POOL_START_BLOCK) {
    vaultMulti.call(IFO_POOL_ADDRESS, IFO_POOL_ADDRESS, 'getPricePerFullShare');

    addresses.forEach((address) => {
      vaultMulti.call(
        `${IFO_POOL_ADDRESS}-${address}`,
        IFO_POOL_ADDRESS,
        'userInfo',
        [address]
      );
    });
  }

  const vaultMultiRes = await vaultMulti.execute();

  return Object.fromEntries<BigNumber>(
    addresses.map((address) => [
      address,
      (vaultMultiRes[CAKE_VAULT_ADDRESS] || Zero)
        .mul(vaultMultiRes[`${CAKE_VAULT_ADDRESS}-${address}`]?.shares || Zero)
        .div(WeiPerEther)
        .add(
          (vaultMultiRes[IFO_POOL_ADDRESS] || Zero)
            .mul(
              vaultMultiRes[`${IFO_POOL_ADDRESS}-${address}`]?.shares || Zero
            )
            .div(WeiPerEther)
        )
    ])
  );
}
Example #8
Source File: index.ts    From sdk with ISC License 5 votes vote down vote up
expectZero    = (data: BigNumber): Chai.Assertion => expectBnEqual(data, Zero)
Example #9
Source File: index.ts    From sdk with ISC License 5 votes vote down vote up
expectGteZero = (data: BigNumber): Chai.Assertion => expectGte(data, Zero)
Example #10
Source File: index.ts    From sdk with ISC License 5 votes vote down vote up
expectNotZero = (data: BigNumber): Chai.Assertion => expectGt(data, Zero)
Example #11
Source File: VaultActions.test.ts    From balancer-v2-monorepo with GNU General Public License v3.0 4 votes vote down vote up
describe('VaultActions', function () {
  let vault: Vault;
  let tokens: TokenList;
  let relayer: Contract, relayerLibrary: Contract;
  let admin: SignerWithAddress, sender: SignerWithAddress;

  let poolIdA: string, poolIdB: string, poolIdC: string;
  let tokensA: TokenList, tokensB: TokenList, tokensC: TokenList;

  before('get signers', async () => {
    [, admin, sender] = await ethers.getSigners();
  });

  sharedBeforeEach('set up relayer', async () => {
    // Deploy Balancer Vault
    vault = await Vault.create({ admin });

    // Deploy Relayer
    relayerLibrary = await deploy('MockBatchRelayerLibrary', { args: [vault.address, ZERO_ADDRESS] });
    relayer = await deployedAt('BalancerRelayer', await relayerLibrary.getEntrypoint());

    // Authorize Relayer for all actions
    const relayerActionIds = await Promise.all(
      ['swap', 'batchSwap', 'joinPool', 'exitPool', 'setRelayerApproval', 'manageUserBalance'].map((action) =>
        actionId(vault.instance, action)
      )
    );
    await vault.grantPermissionsGlobally(relayerActionIds, relayer);

    // Approve relayer by sender
    await vault.setRelayerApproval(sender, relayer, true);
  });

  sharedBeforeEach('set up pools', async () => {
    tokens = (await TokenList.create(['DAI', 'MKR', 'SNX', 'BAT'])).sort();
    await tokens.mint({ to: sender });
    await tokens.approve({ to: vault, from: sender });

    // Pool A: DAI-MKR
    tokensA = new TokenList([tokens.DAI, tokens.MKR]).sort();
    const poolA = await WeightedPool.create({
      poolType: WeightedPoolType.WEIGHTED_POOL,
      tokens: tokensA,
      vault,
    });
    await poolA.init({ initialBalances: fp(1000), from: sender });

    poolIdA = await poolA.getPoolId();

    // Pool B: MKR-SNX
    tokensB = new TokenList([tokens.MKR, tokens.SNX]).sort();
    const poolB = await WeightedPool.create({
      poolType: WeightedPoolType.WEIGHTED_POOL,
      tokens: tokensB,
      vault,
    });
    await poolB.init({ initialBalances: fp(1000), from: sender });

    poolIdB = await poolB.getPoolId();

    // Pool C: SNX-BAT
    tokensC = new TokenList([tokens.SNX, tokens.BAT]).sort();
    const poolC = await WeightedPool.create({
      poolType: WeightedPoolType.WEIGHTED_POOL,
      tokens: tokensC,
      vault,
    });
    await poolC.init({ initialBalances: fp(1000), from: sender });

    poolIdC = await poolC.getPoolId();
  });

  function encodeSwap(params: {
    poolId: string;
    tokenIn: Token;
    tokenOut: Token;
    amount: BigNumberish;
    fromInternalBalance?: boolean;
    outputReference?: BigNumberish;
  }): string {
    return relayerLibrary.interface.encodeFunctionData('swap', [
      {
        poolId: params.poolId,
        kind: SwapKind.GivenIn,
        assetIn: params.tokenIn.address,
        assetOut: params.tokenOut.address,
        amount: params.amount,
        userData: '0x',
      },
      {
        sender: sender.address,
        recipient: sender.address,
        fromInternalBalance: params.fromInternalBalance ?? false,
        toInternalBalance: false,
      },
      0,
      MAX_UINT256,
      0,
      params.outputReference ?? 0,
    ]);
  }

  function encodeBatchSwap(params: {
    swaps: Array<{
      poolId: string;
      tokenIn: Token;
      tokenOut: Token;
      amount: BigNumberish;
    }>;
    outputReferences?: Dictionary<BigNumberish>;
  }): string {
    const outputReferences = Object.entries(params.outputReferences ?? {}).map(([symbol, key]) => ({
      index: tokens.findIndexBySymbol(symbol),
      key,
    }));

    return relayerLibrary.interface.encodeFunctionData('batchSwap', [
      SwapKind.GivenIn,
      params.swaps.map((swap) => ({
        poolId: swap.poolId,
        assetInIndex: tokens.indexOf(swap.tokenIn),
        assetOutIndex: tokens.indexOf(swap.tokenOut),
        amount: swap.amount,
        userData: '0x',
      })),
      tokens.addresses,
      { sender: sender.address, recipient: sender.address, fromInternalBalance: false, toInternalBalance: false },
      new Array(tokens.length).fill(MAX_INT256),
      MAX_UINT256,
      0,
      outputReferences,
    ]);
  }

  async function encodeJoinPool(params: {
    poolId: string;
    userData: string;
    outputReference?: BigNumberish;
  }): Promise<string> {
    const { tokens } = await vault.getPoolTokens(params.poolId);

    return relayerLibrary.interface.encodeFunctionData('joinPool', [
      params.poolId,
      0,
      sender.address,
      sender.address,
      {
        assets: tokens,
        maxAmountsIn: new Array(tokens.length).fill(MAX_UINT256),
        userData: params.userData,
        fromInternalBalance: false,
      },
      0,
      params.outputReference ?? 0,
    ]);
  }

  async function encodeExitPool(params: {
    poolId: string;
    userData: string;
    toInternalBalance: boolean;
    outputReferences?: Dictionary<BigNumberish>;
  }): Promise<string> {
    const { tokens: poolTokens } = await vault.getPoolTokens(params.poolId);
    const outputReferences = Object.entries(params.outputReferences ?? {}).map(([symbol, key]) => ({
      index: poolTokens.findIndex((tokenAddress) => tokenAddress === tokens.findBySymbol(symbol).address),
      key,
    }));

    return relayerLibrary.interface.encodeFunctionData('exitPool', [
      params.poolId,
      0,
      sender.address,
      sender.address,
      {
        assets: poolTokens,
        minAmountsOut: new Array(poolTokens.length).fill(0),
        userData: params.userData,
        toInternalBalance: params.toInternalBalance,
      },
      outputReferences,
    ]);
  }

  function getJoinExitAmounts(poolTokens: TokenList, tokenAmounts: Dictionary<BigNumberish>): Array<BigNumberish> {
    return poolTokens.map((token) => tokenAmounts[token.symbol] ?? 0);
  }

  describe('simple swap', () => {
    const amountIn = fp(2);

    it('swaps with immediate amounts', async () => {
      await expectBalanceChange(
        () =>
          relayer
            .connect(sender)
            .multicall([encodeSwap({ poolId: poolIdA, tokenIn: tokens.DAI, tokenOut: tokens.MKR, amount: amountIn })]),
        tokens,
        { account: sender, changes: { DAI: amountIn.mul(-1), MKR: ['near', amountIn] } }
      );
    });

    it('stores swap output as chained reference', async () => {
      const receipt = await (
        await relayer.connect(sender).multicall([
          encodeSwap({
            poolId: poolIdA,
            tokenIn: tokens.DAI,
            tokenOut: tokens.MKR,
            amount: amountIn,
            outputReference: toChainedReference(0),
          }),
        ])
      ).wait();

      const {
        args: { amountOut },
      } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', { poolId: poolIdA });
      await expectChainedReferenceContents(relayer, toChainedReference(0), amountOut);
    });

    it('swaps with chained references', async () => {
      await setChainedReferenceContents(relayer, toChainedReference(0), amountIn);

      const receipt = await (
        await relayer.connect(sender).multicall([
          encodeSwap({
            poolId: poolIdA,
            tokenIn: tokens.DAI,
            tokenOut: tokens.MKR,
            amount: toChainedReference(0),
          }),
        ])
      ).wait();

      const swapEvent = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', { poolId: poolIdA });
      expect(swapEvent.args.amountIn).to.equal(amountIn);
    });

    it('is chainable via multicall', async () => {
      const receipt = await (
        await expectBalanceChange(
          () =>
            relayer.connect(sender).multicall([
              encodeSwap({
                poolId: poolIdA,
                tokenIn: tokens.DAI,
                tokenOut: tokens.MKR,
                amount: amountIn,
                outputReference: toChainedReference(0),
              }),
              encodeSwap({
                poolId: poolIdB,
                tokenIn: tokens.MKR,
                tokenOut: tokens.SNX,
                amount: toChainedReference(0),
              }),
            ]),
          tokens,
          { account: sender, changes: { DAI: amountIn.mul(-1), SNX: ['near', amountIn] } }
        )
      ).wait();

      const {
        args: { amountOut: amountOutA },
      } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', { poolId: poolIdA });
      const {
        args: { amountIn: amountInB },
      } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', { poolId: poolIdB });

      expect(amountOutA).to.equal(amountInB);
    });
  });

  describe('batch swap', () => {
    const amountInA = fp(2);
    const amountInC = fp(5);

    it('swaps with immediate amounts', async () => {
      await expectBalanceChange(
        () =>
          relayer.connect(sender).multicall([
            encodeBatchSwap({
              swaps: [
                { poolId: poolIdA, tokenIn: tokens.DAI, tokenOut: tokens.MKR, amount: amountInA },
                { poolId: poolIdC, tokenIn: tokens.SNX, tokenOut: tokens.BAT, amount: amountInC },
              ],
            }),
          ]),
        tokens,
        {
          account: sender,
          changes: {
            DAI: amountInA.mul(-1),
            MKR: ['near', amountInA],
            SNX: amountInC.mul(-1),
            BAT: ['near', amountInC],
          },
        }
      );
    });

    it('stores absolute vault deltas as chained reference', async () => {
      const receipt = await (
        await relayer.connect(sender).multicall([
          encodeBatchSwap({
            swaps: [
              { poolId: poolIdA, tokenIn: tokens.DAI, tokenOut: tokens.MKR, amount: amountInA },
              { poolId: poolIdC, tokenIn: tokens.SNX, tokenOut: tokens.BAT, amount: amountInC },
            ],
            outputReferences: {
              MKR: toChainedReference(0),
              SNX: toChainedReference(1),
            },
          }),
        ])
      ).wait();

      // Note that the ouput references are for MKR (an output) and for SNX (an input)

      const {
        args: { amountOut: amountOutMKR },
      } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', { poolId: poolIdA });

      const {
        args: { amountIn: amountInSNX },
      } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', { poolId: poolIdC });

      await expectChainedReferenceContents(relayer, toChainedReference(0), amountOutMKR);

      await expectChainedReferenceContents(relayer, toChainedReference(1), amountInSNX);
    });

    it('swaps with chained references', async () => {
      await setChainedReferenceContents(relayer, toChainedReference(0), amountInC);

      const receipt = await (
        await relayer.connect(sender).multicall([
          encodeBatchSwap({
            swaps: [
              { poolId: poolIdA, tokenIn: tokens.DAI, tokenOut: tokens.MKR, amount: amountInA },
              {
                poolId: poolIdC,
                tokenIn: tokens.SNX,
                tokenOut: tokens.BAT,
                amount: toChainedReference(0),
              },
            ],
          }),
        ])
      ).wait();

      const swapEvent = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', { poolId: poolIdC });
      expect(swapEvent.args.amountIn).to.equal(amountInC);
    });

    it('is chainable via multicall', async () => {
      const receipt = await (
        await expectBalanceChange(
          () =>
            relayer.connect(sender).multicall([
              encodeBatchSwap({
                swaps: [
                  { poolId: poolIdA, tokenIn: tokens.DAI, tokenOut: tokens.MKR, amount: amountInA },
                  { poolId: poolIdC, tokenIn: tokens.SNX, tokenOut: tokens.BAT, amount: amountInC },
                ],
                outputReferences: {
                  MKR: toChainedReference(0),
                  BAT: toChainedReference(1),
                },
              }),
              encodeBatchSwap({
                swaps: [
                  // Swap previously acquired MKR for SNX
                  {
                    poolId: poolIdB,
                    tokenIn: tokens.MKR,
                    tokenOut: tokens.SNX,
                    amount: toChainedReference(0),
                  },
                  // Undo first SNX-BAT swap
                  {
                    poolId: poolIdC,
                    tokenIn: tokens.BAT,
                    tokenOut: tokens.SNX,
                    amount: toChainedReference(1),
                  },
                ],
              }),
            ]),
          tokens,
          {
            account: sender,
            changes: {
              DAI: amountInA.mul(-1),
              SNX: ['near', amountInA],
            },
          }
        )
      ).wait();

      const {
        args: { amountOut: amountOutA },
      } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', { poolId: poolIdA });
      const {
        args: { amountIn: amountInB },
      } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', { poolId: poolIdB });

      expect(amountOutA).to.equal(amountInB);

      const {
        args: { amountOut: amountOutBAT },
      } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', {
        poolId: poolIdC,
        tokenIn: tokens.SNX.address,
      });
      const {
        args: { amountIn: amountInBAT },
      } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', {
        poolId: poolIdC,
        tokenIn: tokens.BAT.address,
      });

      expect(amountOutBAT).to.equal(amountInBAT);
    });
  });

  describe('join pool', () => {
    const amountInDAI = fp(2);
    const amountInMKR = fp(5);

    describe('weighted pool', () => {
      describe('exact tokens in for bpt out', () => {
        it('joins with immediate amounts', async () => {
          await expectBalanceChange(
            async () =>
              relayer.connect(sender).multicall([
                await encodeJoinPool({
                  poolId: poolIdA,
                  userData: WeightedPoolEncoder.joinExactTokensInForBPTOut(
                    getJoinExitAmounts(tokensA, { DAI: amountInDAI, MKR: amountInMKR }),
                    0
                  ),
                }),
              ]),
            tokens,
            {
              account: sender,
              changes: {
                DAI: amountInDAI.mul(-1),
                MKR: amountInMKR.mul(-1),
              },
            }
          );
        });

        it('stores BPT amount out as chained reference', async () => {
          const receipt = await (
            await relayer.connect(sender).multicall([
              await encodeJoinPool({
                poolId: poolIdA,
                userData: WeightedPoolEncoder.joinExactTokensInForBPTOut(
                  getJoinExitAmounts(tokensA, { DAI: amountInDAI, MKR: amountInMKR }),
                  0
                ),
                outputReference: toChainedReference(0),
              }),
            ])
          ).wait();

          const {
            args: { value: BPTAmountOut },
          } = expectTransferEvent(
            receipt,
            { from: ZERO_ADDRESS, to: sender.address },
            await Token.deployedAt(getPoolAddress(poolIdA))
          );

          await expectChainedReferenceContents(relayer, toChainedReference(0), BPTAmountOut);
        });

        it('joins with exact amounts in chained references', async () => {
          await setChainedReferenceContents(relayer, toChainedReference(0), amountInMKR);

          await expectBalanceChange(
            async () =>
              relayer.connect(sender).multicall([
                await encodeJoinPool({
                  poolId: poolIdA,
                  userData: WeightedPoolEncoder.joinExactTokensInForBPTOut(
                    getJoinExitAmounts(tokensA, { DAI: amountInDAI, MKR: toChainedReference(0) }),
                    0
                  ),
                }),
              ]),
            tokens,
            {
              account: sender,
              changes: {
                DAI: amountInDAI.mul(-1),
                MKR: amountInMKR.mul(-1),
              },
            }
          );
        });

        it('is chainable with swaps via multicall', async () => {
          const receipt = await (
            await expectBalanceChange(
              () =>
                relayer.connect(sender).multicall([
                  encodeSwap({
                    poolId: poolIdA,
                    tokenIn: tokens.DAI,
                    tokenOut: tokens.MKR,
                    amount: amountInDAI,
                    outputReference: toChainedReference(0),
                  }),
                  encodeJoinPool({
                    poolId: poolIdB,
                    userData: WeightedPoolEncoder.joinExactTokensInForBPTOut(
                      getJoinExitAmounts(tokensB, { MKR: toChainedReference(0) }),
                      0
                    ),
                  }),
                ]),
              tokens,
              { account: sender, changes: { DAI: amountInDAI.mul(-1) } }
            )
          ).wait();

          const {
            args: { amountOut: amountOutMKR },
          } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', { poolId: poolIdA });

          const {
            args: { deltas },
          } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'PoolBalanceChanged', {
            poolId: poolIdB,
          });

          expect(deltas[tokensB.indexOf(tokens.MKR)]).to.equal(amountOutMKR);
          expect(deltas[tokensB.indexOf(tokens.SNX)]).to.equal(0);
        });
      });

      describe('token in for exact bpt out', () => {
        it('joins with immediate amounts', async () => {
          const bptOut = fp(2);
          const mkrIndex = tokensA.indexOf(tokens.MKR);

          await expectBalanceChange(
            async () =>
              relayer.connect(sender).multicall([
                await encodeJoinPool({
                  poolId: poolIdA,
                  userData: WeightedPoolEncoder.joinTokenInForExactBPTOut(bptOut, mkrIndex),
                }),
              ]),
            tokens,
            {
              account: sender,
              changes: {
                MKR: ['near', bptOut.mul(-1)], // In a balanced pool, BPT should roughly represent the underlying tokens
              },
            }
          );
        });
      });

      describe('all tokens in for exact bpt out', () => {
        it('joins with immediate amounts', async () => {
          const bptOut = fp(2);

          await expectBalanceChange(
            async () =>
              relayer.connect(sender).multicall([
                await encodeJoinPool({
                  poolId: poolIdA,
                  userData: WeightedPoolEncoder.joinAllTokensInForExactBPTOut(bptOut),
                }),
              ]),
            tokens,
            {
              account: sender,
              changes: {
                // In a balanced pool, BPT should roughly represent the underlying tokens
                DAI: ['near', bptOut.div(2).mul(-1)],
                MKR: ['near', bptOut.div(2).mul(-1)],
              },
            }
          );
        });
      });
    });
  });

  describe('exit pool', () => {
    const amountInBPT = fp(1);

    async function getBPT(poolId: string): Promise<TokenList> {
      return new TokenList([await Token.deployedAt(getPoolAddress(poolId))]);
    }

    describe('weighted pool', () => {
      function testExitPool(useInternalBalance: boolean): void {
        describe('exact bpt in for tokens', () => {
          it('exits with immediate amounts', async () => {
            await expectBalanceChange(
              async () =>
                relayer.connect(sender).multicall([
                  await encodeExitPool({
                    poolId: poolIdA,
                    userData: WeightedPoolEncoder.exitExactBPTInForTokensOut(fp(1)),
                    toInternalBalance: useInternalBalance,
                  }),
                ]),
              await getBPT(poolIdA),
              {
                account: sender,
                changes: {
                  BPT: amountInBPT.mul(-1),
                },
              }
            );
          });

          it('stores token amount out as chained reference', async () => {
            const receipt = await (
              await relayer.connect(sender).multicall([
                await encodeExitPool({
                  poolId: poolIdA,
                  userData: WeightedPoolEncoder.exitExactBPTInForTokensOut(amountInBPT),
                  toInternalBalance: useInternalBalance,
                  outputReferences: {
                    DAI: toChainedReference(0),
                    MKR: toChainedReference(1),
                  },
                }),
              ])
            ).wait();

            let daiAmountOut = Zero;
            let mkrAmountOut = Zero;
            if (useInternalBalance) {
              const daiTransfer = expectEvent.inIndirectReceipt(
                receipt,
                vault.instance.interface,
                'InternalBalanceChanged',
                {
                  user: sender.address,
                  token: tokens.DAI.address,
                }
              );
              const mkrTransfer = expectEvent.inIndirectReceipt(
                receipt,
                vault.instance.interface,
                'InternalBalanceChanged',
                {
                  user: sender.address,
                  token: tokens.MKR.address,
                }
              );

              daiAmountOut = daiTransfer.args.delta;
              mkrAmountOut = mkrTransfer.args.delta;
            } else {
              const daiTransfer = expectTransferEvent(receipt, { from: vault.address, to: sender.address }, tokens.DAI);
              const mkrTransfer = expectTransferEvent(receipt, { from: vault.address, to: sender.address }, tokens.MKR);

              daiAmountOut = daiTransfer.args.value;
              mkrAmountOut = mkrTransfer.args.value;
            }

            await expectChainedReferenceContents(relayer, toChainedReference(0), daiAmountOut);
            await expectChainedReferenceContents(relayer, toChainedReference(1), mkrAmountOut);
          });

          it('exits with exact bpt in chained reference', async () => {
            await setChainedReferenceContents(relayer, toChainedReference(0), amountInBPT);

            await expectBalanceChange(
              async () =>
                relayer.connect(sender).multicall([
                  await encodeExitPool({
                    poolId: poolIdA,
                    userData: WeightedPoolEncoder.exitExactBPTInForTokensOut(toChainedReference(0)),
                    toInternalBalance: useInternalBalance,
                  }),
                ]),
              await getBPT(poolIdA),
              {
                account: sender,
                changes: {
                  BPT: amountInBPT.mul(-1),
                },
              }
            );
          });

          it('is chainable with swaps via multicall', async () => {
            const receipt = await (
              await expectBalanceChange(
                async () =>
                  relayer.connect(sender).multicall([
                    await encodeExitPool({
                      poolId: poolIdA,
                      userData: WeightedPoolEncoder.exitExactBPTInForTokensOut(amountInBPT),
                      toInternalBalance: useInternalBalance,
                      outputReferences: {
                        MKR: toChainedReference(0),
                      },
                    }),
                    encodeSwap({
                      poolId: poolIdA,
                      tokenIn: tokens.MKR,
                      tokenOut: tokens.DAI,
                      fromInternalBalance: useInternalBalance,
                      amount: toChainedReference(0),
                    }),
                  ]),
                await getBPT(poolIdA),
                {
                  account: sender,
                  changes: {
                    BPT: amountInBPT.mul(-1),
                  },
                }
              )
            ).wait();

            const {
              args: { deltas },
            } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'PoolBalanceChanged', {
              poolId: poolIdA,
            });

            const {
              args: { amountIn: amountInMKR },
            } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', { poolId: poolIdA });

            expect(deltas[tokensA.indexOf(tokens.MKR)].mul(-1)).to.equal(amountInMKR);
          });
        });

        describe('exact bpt in for one token', () => {
          it('exits with immediate amounts', async () => {
            await expectBalanceChange(
              async () =>
                relayer.connect(sender).multicall([
                  await encodeExitPool({
                    poolId: poolIdA,
                    userData: WeightedPoolEncoder.exitExactBPTInForOneTokenOut(fp(1), 0),
                    toInternalBalance: useInternalBalance,
                  }),
                ]),
              await getBPT(poolIdA),
              {
                account: sender,
                changes: {
                  BPT: amountInBPT.mul(-1),
                },
              }
            );
          });

          it('stores token amount out as chained reference', async () => {
            const receipt = await (
              await relayer.connect(sender).multicall([
                await encodeExitPool({
                  poolId: poolIdA,
                  userData: WeightedPoolEncoder.exitExactBPTInForOneTokenOut(
                    amountInBPT,
                    tokensA.findIndexBySymbol('MKR')
                  ),
                  toInternalBalance: useInternalBalance,
                  outputReferences: {
                    MKR: toChainedReference(0),
                  },
                }),
              ])
            ).wait();

            let mkrAmountOut = Zero;
            if (useInternalBalance) {
              const mkrTransfer = expectEvent.inIndirectReceipt(
                receipt,
                vault.instance.interface,
                'InternalBalanceChanged',
                {
                  user: sender.address,
                  token: tokens.MKR.address,
                }
              );

              mkrAmountOut = mkrTransfer.args.delta;
            } else {
              const mkrTransfer = expectTransferEvent(receipt, { from: vault.address, to: sender.address }, tokens.MKR);

              mkrAmountOut = mkrTransfer.args.value;
            }

            await expectChainedReferenceContents(relayer, toChainedReference(0), mkrAmountOut);
          });

          it('exits with exact bpt in chained reference', async () => {
            await setChainedReferenceContents(relayer, toChainedReference(0), amountInBPT);

            await expectBalanceChange(
              async () =>
                relayer.connect(sender).multicall([
                  await encodeExitPool({
                    poolId: poolIdA,
                    userData: WeightedPoolEncoder.exitExactBPTInForOneTokenOut(
                      toChainedReference(0),
                      tokensA.findIndexBySymbol('MKR')
                    ),
                    toInternalBalance: useInternalBalance,
                  }),
                ]),
              await getBPT(poolIdA),
              {
                account: sender,
                changes: {
                  BPT: amountInBPT.mul(-1),
                },
              }
            );
          });

          it('is chainable with swaps via multicall', async () => {
            const receipt = await (
              await expectBalanceChange(
                async () =>
                  relayer.connect(sender).multicall([
                    await encodeExitPool({
                      poolId: poolIdA,
                      userData: WeightedPoolEncoder.exitExactBPTInForOneTokenOut(
                        amountInBPT,
                        tokensA.findIndexBySymbol('MKR')
                      ),
                      toInternalBalance: useInternalBalance,
                      outputReferences: {
                        MKR: toChainedReference(0),
                      },
                    }),
                    encodeSwap({
                      poolId: poolIdA,
                      tokenIn: tokens.MKR,
                      tokenOut: tokens.DAI,
                      amount: toChainedReference(0),
                      fromInternalBalance: useInternalBalance,
                    }),
                  ]),
                await getBPT(poolIdA),
                {
                  account: sender,
                  changes: {
                    BPT: amountInBPT.mul(-1),
                  },
                }
              )
            ).wait();

            const {
              args: { deltas },
            } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'PoolBalanceChanged', {
              poolId: poolIdA,
            });

            const {
              args: { amountIn: amountInMKR },
            } = expectEvent.inIndirectReceipt(receipt, vault.instance.interface, 'Swap', { poolId: poolIdA });

            expect(deltas[tokensA.indexOf(tokens.MKR)].mul(-1)).to.equal(amountInMKR);
          });
        });

        describe('bpt in for exact tokens out', () => {
          const amountOutMKR = fp(1);
          const amountOutDAI = fp(2);

          it('exits with immediate amounts', async () => {
            await expectBalanceChange(
              async () =>
                relayer.connect(sender).multicall([
                  await encodeExitPool({
                    poolId: poolIdA,
                    userData: WeightedPoolEncoder.exitBPTInForExactTokensOut([amountOutMKR, amountOutDAI], MAX_UINT256),
                    toInternalBalance: useInternalBalance,
                  }),
                ]),
              await getBPT(poolIdA),
              {
                account: sender,
                changes: {
                  BPT: ['lt', 0],
                  MKR: amountOutMKR,
                  DAI: amountOutDAI,
                },
              }
            );
          });
        });
      }

      describe('exit to external balance', () => {
        const toInternalBalance = false;
        testExitPool(toInternalBalance);
      });

      describe('exit to internal balance', () => {
        const toInternalBalance = true;
        testExitPool(toInternalBalance);
      });
    });
  });
});
Example #12
Source File: index.ts    From snapshot-strategies with MIT License 4 votes vote down vote up
export async function strategy(
  space,
  network,
  provider,
  addresses,
  options,
  snapshot
) {
  const pools = await getPools(provider, snapshot);

  const userPoolBalance = await getSmartChefStakedCakeAmount(
    snapshot,
    pools.map((p) => p.id),
    addresses
  );

  const blockTag = typeof snapshot === 'number' ? snapshot : 'latest';
  if (
    blockTag === 'latest' ||
    (typeof blockTag === 'number' &&
      blockTag >= onChainVotingPower.v0.blockNumber)
  ) {
    let callData = addresses.map((address: any) => [
      typeof blockTag === 'number' &&
      blockTag < onChainVotingPower.v1.blockNumber
        ? onChainVotingPower.v0.address
        : onChainVotingPower.v1.address,
      'getVotingPowerWithoutPool',
      [address.toLowerCase()]
    ]);

    callData = [...chunk(callData, options.max || 300)];
    const response: any[] = [];
    for (const call of callData) {
      const multiRes = await multicall(network, provider, abi, call, {
        blockTag
      });
      response.push(...multiRes);
    }
    return Object.fromEntries(
      response.map((value, i) => [
        addresses[i],
        parseFloat(
          formatEther(
            (userPoolBalance[addresses[i].toLowerCase()] || Zero).add(
              value.toString()
            )
          )
        )
      ])
    );
  }

  const erc20Balance = await erc20BalanceOfStrategy(
    space,
    network,
    provider,
    addresses,
    {
      address: CAKE_ADDRESS,
      symbol: 'CAKE',
      decimals: 18
    },
    snapshot
  );

  const cakeBnbLpBalance = await masterChefPoolBalanceStrategy(
    space,
    network,
    provider,
    addresses,
    {
      chefAddress: MASTER_CHEF_ADDRESS.v1,
      uniPairAddress: CAKE_BNB_LP_ADDRESS,
      pid: '251',
      symbol: 'CAKE-BNB LP',
      tokenIndex: 0
    },
    snapshot
  );

  const cakeVaultBalance = await getVaultBalance(
    network,
    provider,
    addresses,
    blockTag
  );

  return Object.fromEntries(
    addresses.map((address) => [
      address,
      erc20Balance[address] +
        cakeBnbLpBalance[address] +
        parseFloat(
          formatEther(
            (userPoolBalance[address.toLowerCase()] || Zero).add(
              cakeVaultBalance[address] || Zero
            )
          )
        )
    ])
  );
}
Example #13
Source File: ContractWrapperFunctions-test.ts    From sdk with ISC License 4 votes vote down vote up
describe("SynapseBridge - Contract Wrapper Functions tests", function(this: Mocha.Suite) {
    const ALL_CHAIN_IDS = supportedChainIds();

    describe(".bridgeVersion()", function(this: Mocha.Suite) {
        const expected = 6;

        ALL_CHAIN_IDS.forEach(network => {
            const
                provider          = rpcProviderForChain(network),
                bridgeInstance    = new Bridge.SynapseBridge({ network, provider}),
                testTitle: string = `Should return ${expected.toString()} on Chain ID ${network}`;

            it(testTitle, async function(this: Mocha.Context) {
                this.timeout(DEFAULT_TEST_TIMEOUT);
                let prom = bridgeInstance.bridgeVersion();
                return wrapExpectAsync(expectBnEqual(await prom, expected), prom)
            })
        })
    })

    describe(".WETH_ADDRESS", function(this: Mocha.Suite) {
        ALL_CHAIN_IDS.forEach(network => {
            const
                provider = rpcProviderForChain(network),
                bridgeInstance = new Bridge.SynapseBridge({ network, provider }),
                expected: string = ((): string => {
                    switch (network) {
                        case ChainId.ETH:
                            return "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                        case ChainId.OPTIMISM:
                            return "0x121ab82b49B2BC4c7901CA46B8277962b4350204"
                        case ChainId.BOBA:
                            return "0xd203De32170130082896b4111eDF825a4774c18E"
                        case ChainId.ARBITRUM:
                            return "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
                        default:
                            return "0x0000000000000000000000000000000000000000"
                    }})(),
                testTitle: string = `Should return ${expected} for Chain ID ${network}`;

            it(testTitle, async function(this: Mocha.Context) {
                this.timeout(DEFAULT_TEST_TIMEOUT);
                let prom = bridgeInstance.WETH_ADDRESS();
                return wrapExpectAsync(expectEqual(await prom, expected), prom)
            })
        })
    })

    describe(".getAllowanceForAddress", function(this: Mocha.Suite) {
        interface TestCase {
            provider:   Provider,
            chainId:    number,
            address:    string,
            token:      Token,
            want:       BigNumber,
            isInfinite: boolean,
        }

        const
            addr1: string = "0x7145a092158c215ff10cce4ddcb84b3a090bdd4e",
            // addr2: string = "0x41fe2231639268f01383b86cc8b64fbf24b5e156",
            addr3: string = "0x89a2a295174d899c6d68dfc03535993ee15ff72e",
            addr4: string = "0x39c46cFD4711d1B4D7141d87f057C89C9D2d7019",
            addr5: string = "0xDF681Fe10B2fb7B5605107098EA3867187851DCe",
            infiniteCheckAmt: BigNumber = MaxUint256.div(2);

        const makeTestCase = (c: number, t: Token, a: string, n: BigNumberish): TestCase => {
            return {
                provider:   rpcProviderForChain(c),
                chainId:    c,
                token:      t,
                address:    a,
                want:       BigNumber.from(n),
                isInfinite: MaxUint256.eq(n),
            }
        }

        function runTestCase(tc: TestCase) {
            const
                {provider, chainId: network} = tc,
                chainName: string = Networks.fromChainId(network).name,
                wantNum:   string = parseUnits(tc.want.toString(), tc.token.decimals(network)).toString();

            const
                spendAllowanceTitle: string = `should have a spend allowance of ${tc.isInfinite ? "unlimited" : wantNum} wei`,
                title:               string = `SynapseBridge on chain ${chainName} ${spendAllowanceTitle} for ${tc.token.name} holdings of ${tc.address}`;

            it(title, async function (this: Mocha.Context) {
                this.timeout(DEFAULT_TEST_TIMEOUT);

                let bridgeInstance = new Bridge.SynapseBridge({network, provider});

                const
                    {address, token} = tc,
                    decimals = token.decimals(network),
                    checkAmt: BigNumber = tc.isInfinite ? infiniteCheckAmt : tc.want;

                let prom = bridgeInstance
                    .getAllowanceForAddress({address, token})
                    .then(res => getActualWei(res, decimals));

                try {
                    const res = await prom;
                    return tc.isInfinite
                        ? expect(res).to.be.gte(checkAmt)
                        : expect(res).to.be.eq(checkAmt)
                } catch (err) {
                    return (await expectFulfilled(prom))
                }
            })
        }

        describe("- infinite approval", function(this: Mocha.Suite) {
            step("Ensure infinite approval test address has infinite approval", async function(this: Mocha.Context) {
                this.timeout(EXECUTORS_TEST_TIMEOUT);

                dotenv.config();

                const bscZapAddr: string = contractAddressFor(ChainId.BSC, "bridgeZap");
                const tokenParams = {tokenAddress: Tokens.BUSD.address(ChainId.BSC), chainId: ChainId.BSC};

                try {
                    const allowance = await ERC20.allowanceOf(
                        infiniteApprovalsPrivkey.address,
                        bscZapAddr,
                        tokenParams
                    );

                    if (allowance.lte(infiniteCheckAmt)) {
                        const wallet = new Wallet(
                            infiniteApprovalsPrivkey.privkey,
                            rpcProviderForChain(ChainId.BSC)
                        );

                        const approveArgs = {spender: bscZapAddr};

                        let txn: ContractTransaction = (await ERC20.approve(
                            approveArgs,
                            tokenParams,
                            wallet
                        )) as ContractTransaction;

                        await txn.wait(1);

                        const newAllowance = await ERC20.allowanceOf(
                            infiniteApprovalsPrivkey.address,
                            bscZapAddr,
                            tokenParams
                        );

                        expect(newAllowance).to.be.gte(infiniteCheckAmt);
                    }

                    return
                } catch (err) {
                    const e: Error = err instanceof Error ? err : new Error(err);
                    expect(e.message).to.eq("");
                }
            })

            runTestCase(makeTestCase(
                ChainId.BSC,
                Tokens.BUSD,
                infiniteApprovalsPrivkey.address,
                MaxUint256
            ));
        })

        describe("- zero approval", function(this: Mocha.Suite) {
            [
                makeTestCase(ChainId.AURORA,    Tokens.DAI,  addr4, Zero),
                makeTestCase(ChainId.BOBA,      Tokens.NUSD, addr3, Zero),
                makeTestCase(ChainId.MOONRIVER, Tokens.SYN,  addr1, Zero),
                makeTestCase(ChainId.HARMONY,   Tokens.NUSD, addr5, Zero),
            ].forEach(runTestCase);
        })
    })
})
Example #14
Source File: getEstimatedBridgeOutput-test.ts    From sdk with ISC License 4 votes vote down vote up
describe("SynapseBridge - getEstimatedBridgeOutput tests", function(this: Mocha.Suite) {
    interface Expected {
        notZero:   boolean,
        wantError: boolean,
        noAddrTo:  boolean,
    }

    type TestCase = BridgeSwapTestCase<Expected>

    const makeTestCase = (
        t1: Token, t2: Token,
        c1: number, c2: number,
        amt?:      string,
        notZero?:  boolean,
        wantErr?:  boolean,
        noAddrTo?: boolean,
    ): TestCase => {
        const expected: Expected = {
            notZero:   valueIfUndefined(notZero,  true),
            wantError: valueIfUndefined(wantErr,  false),
            noAddrTo:  valueIfUndefined(noAddrTo, false),
        };

        return makeBridgeSwapTestCase(c1, t1, c2, t2, expected, getTestAmount(t1, c1, amt))
    }

    function makeTestName(tc: TestCase): [string, string, string] {
        let {
            args: {
                amountFrom,
                tokenFrom,
                tokenFrom: { symbol: tokFrom },
                tokenTo:   { symbol: tokTo   },
                chainIdFrom: chainFrom,
                chainIdTo:   chainTo,
            },
            expected: {
                notZero,
                wantError
            }
        } = tc;

        const
            amt             = formatUnits(amountFrom, tokenFrom.decimals(chainFrom)),
            netFrom         = Networks.networkName(chainFrom),
            netTo           = Networks.networkName(chainTo);

        const
            titleSuffix:     string = notZero ? "a value greater than zero" : "a value === zero",
            passFailSuffix:  string =  wantError ? "should fail" : "should pass",
            testParamsTitle: string = `with params ${amt} ${tokFrom} on ${netFrom} to ${tokTo} on ${netTo}`;

        const
            bridgeOutputTestTitle: string = `getEstimatedBridgeOutput ${testParamsTitle} should return ${titleSuffix}`,
            transactionTestTitle: string  = `buildBridgeTokenTransaction ${testParamsTitle} ${passFailSuffix}`,
            approveTestTitle:      string = `buildApproveTransaction ${testParamsTitle} ${passFailSuffix}`;

        return [bridgeOutputTestTitle, transactionTestTitle, approveTestTitle]
    }

    [
        makeTestCase(Tokens.DAI,       Tokens.USDC,      ChainId.ETH,       ChainId.BSC, "500"),
        makeTestCase(Tokens.DAI,       Tokens.USDC,      ChainId.ETH,       ChainId.BSC, "50"),
        makeTestCase(Tokens.DAI,       Tokens.USDC,      ChainId.ETH,       ChainId.BSC, "1",   false),
        makeTestCase(Tokens.NETH,      Tokens.ETH,       ChainId.BOBA,      ChainId.ETH, "555"),
        makeTestCase(Tokens.NETH,      Tokens.NETH,      ChainId.BOBA,      ChainId.ETH, "555"),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.BOBA,      ChainId.BSC, "20"),
        makeTestCase(Tokens.USDC,      Tokens.USDT,      ChainId.BSC,       ChainId.BOBA,"500"),
        makeTestCase(Tokens.FRAX,      Tokens.FRAX,      ChainId.MOONRIVER, ChainId.ETH),
        makeTestCase(Tokens.FRAX,      Tokens.FRAX,      ChainId.ETH,       ChainId.MOONRIVER),
        makeTestCase(Tokens.SYN,       Tokens.SYN,       ChainId.MOONRIVER, ChainId.ETH),
        makeTestCase(Tokens.SYN,       Tokens.SYN,       ChainId.ETH,       ChainId.MOONRIVER),
        makeTestCase(Tokens.WETH_E,    Tokens.NETH,      ChainId.OPTIMISM,  ChainId.ETH, "500", false, true),
        makeTestCase(Tokens.WETH_E,    Tokens.WETH,      ChainId.OPTIMISM,  ChainId.ETH, "500", false, true),
        makeTestCase(Tokens.WETH,      Tokens.NETH,      ChainId.ETH,       ChainId.OPTIMISM,  "2500"),
        makeTestCase(Tokens.ETH,       Tokens.NETH,      ChainId.ETH,       ChainId.AVALANCHE, "4200"),
        makeTestCase(Tokens.WETH_E,    Tokens.USDC,      ChainId.AVALANCHE, ChainId.ETH, "2500", false, true),
        makeTestCase(Tokens.WETH_E,    Tokens.ETH,       ChainId.AVALANCHE, ChainId.ETH, "2500"),
        makeTestCase(Tokens.WETH_E,    Tokens.ETH,       ChainId.AVALANCHE, ChainId.ARBITRUM),
        makeTestCase(Tokens.ETH,       Tokens.WETH_E,    ChainId.ETH,       ChainId.AVALANCHE),
        makeTestCase(Tokens.ETH,       Tokens.WETH_E,    ChainId.ETH,       ChainId.ETH, "101", true, true),
        makeTestCase(Tokens.NUSD,      Tokens.DAI,       ChainId.AVALANCHE, ChainId.ETH),
        makeTestCase(Tokens.NUSD,      Tokens.DAI,       ChainId.AVALANCHE, ChainId.POLYGON),
        makeTestCase(Tokens.DOG,       Tokens.DOG,       ChainId.POLYGON,   ChainId.ETH, "3133731337"),
        makeTestCase(Tokens.ETH,       Tokens.ETH,       ChainId.ARBITRUM,  ChainId.OPTIMISM),
        makeTestCase(Tokens.NETH,      Tokens.ETH,       ChainId.ARBITRUM,  ChainId.OPTIMISM),
        makeTestCase(Tokens.JUMP,      Tokens.JUMP,      ChainId.FANTOM,    ChainId.BSC),
        makeTestCase(Tokens.GOHM,      Tokens.GOHM,      ChainId.AVALANCHE, ChainId.OPTIMISM,  "1"),
        makeTestCase(Tokens.GOHM,      Tokens.GOHM,      ChainId.ETH,       ChainId.AVALANCHE, "69"),
        makeTestCase(Tokens.GOHM,      Tokens.GOHM,      ChainId.HARMONY,   ChainId.MOONBEAM),
        makeTestCase(Tokens.GOHM,      Tokens.GOHM,      ChainId.HARMONY,   ChainId.MOONRIVER),
        makeTestCase(Tokens.GOHM,      Tokens.GOHM,      ChainId.ETH,       ChainId.AVALANCHE),
        makeTestCase(Tokens.GOHM,      Tokens.GOHM,      ChainId.CRONOS,    ChainId.AURORA,    undefined, false, true),
        makeTestCase(Tokens.USDC,      Tokens.USDC,      ChainId.AURORA,    ChainId.AVALANCHE, "69"),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.BSC,       ChainId.AURORA,    "69"),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.AURORA,    ChainId.ETH,       "69"),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.AURORA,    ChainId.ETH,       "31337"),
        makeTestCase(Tokens.USDC,      Tokens.USDC,      ChainId.AURORA,    ChainId.AVALANCHE, "0", false),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.BSC,       ChainId.AURORA,    "0", false),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.AURORA,    ChainId.ETH,       "0", false),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.AURORA,    ChainId.ETH,       "0", false),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.ETH,       ChainId.AURORA),
        makeTestCase(Tokens.WETH,      Tokens.WETH_E,    ChainId.ETH,       ChainId.AVALANCHE),
        makeTestCase(Tokens.NUSD,      Tokens.NUSD,      ChainId.ETH,       ChainId.AVALANCHE),
        makeTestCase(Tokens.WETH_E,    Tokens.WETH,      ChainId.AVALANCHE, ChainId.OPTIMISM),
        makeTestCase(Tokens.WETH,      Tokens.ONE_ETH,   ChainId.ETH,       ChainId.HARMONY),
        makeTestCase(Tokens.ONE_ETH,   Tokens.WETH_E,    ChainId.HARMONY,   ChainId.AVALANCHE),
        makeTestCase(Tokens.HIGH,      Tokens.HIGH,      ChainId.BSC,       ChainId.ETH),
        makeTestCase(Tokens.JUMP,      Tokens.JUMP,      ChainId.BSC,       ChainId.FANTOM),
        makeTestCase(Tokens.DOG,       Tokens.DOG,       ChainId.BSC,       ChainId.POLYGON,   "3133731337"),
        makeTestCase(Tokens.NFD,       Tokens.NFD,       ChainId.POLYGON,   ChainId.AVALANCHE, "3133731337"),
        makeTestCase(Tokens.GMX,       Tokens.GMX,       ChainId.ARBITRUM,  ChainId.AVALANCHE),
        makeTestCase(Tokens.GMX,       Tokens.GMX,       ChainId.AVALANCHE, ChainId.ARBITRUM),
        makeTestCase(Tokens.SOLAR,     Tokens.SOLAR,     ChainId.MOONRIVER, ChainId.MOONBEAM),
        makeTestCase(Tokens.WAVAX,     Tokens.AVAX,      ChainId.MOONBEAM,  ChainId.AVALANCHE),
        makeTestCase(Tokens.AVAX,      Tokens.WAVAX,     ChainId.AVALANCHE, ChainId.MOONBEAM),
        makeTestCase(Tokens.WMOVR,     Tokens.MOVR,      ChainId.MOONBEAM,  ChainId.MOONRIVER),
        makeTestCase(Tokens.MOVR,      Tokens.WMOVR,     ChainId.MOONRIVER, ChainId.MOONBEAM),
        makeTestCase(Tokens.FTM_ETH,   Tokens.WETH,      ChainId.FANTOM,    ChainId.ETH),
        makeTestCase(Tokens.FTM_ETH,   Tokens.ETH,       ChainId.FANTOM,    ChainId.ETH),
        makeTestCase(Tokens.FTM_ETH,   Tokens.WETH_E,    ChainId.FANTOM,    ChainId.AVALANCHE),
        makeTestCase(Tokens.WETH_E,    Tokens.FTM_ETH,   ChainId.AVALANCHE, ChainId.FANTOM),
        makeTestCase(Tokens.ETH,       Tokens.FTM_ETH,   ChainId.ETH,       ChainId.FANTOM),
        makeTestCase(Tokens.WETH,      Tokens.FTM_ETH,   ChainId.ETH,       ChainId.FANTOM),
        makeTestCase(Tokens.NUSD,      Tokens.DAI,       ChainId.AVALANCHE, ChainId.POLYGON, undefined, true, false, true),
        makeTestCase(Tokens.WETH,      Tokens.FTM_ETH,   ChainId.ETH,       ChainId.FANTOM,  undefined, true, false, true),
        makeTestCase(Tokens.ETH,       Tokens.WETH_E,    ChainId.ARBITRUM,  ChainId.AVALANCHE),
        makeTestCase(Tokens.WETH,      Tokens.WETH_E,    ChainId.ARBITRUM,  ChainId.AVALANCHE),
        makeTestCase(Tokens.WETH_E,    Tokens.ETH,       ChainId.AVALANCHE, ChainId.ARBITRUM),
        makeTestCase(Tokens.WETH_E,    Tokens.WETH,      ChainId.AVALANCHE, ChainId.ARBITRUM),
        makeTestCase(Tokens.USDC,      Tokens.DAI,       ChainId.BSC,       ChainId.ETH,       "2500"),
        makeTestCase(Tokens.NUSD,      Tokens.DAI,       ChainId.BSC,       ChainId.ETH,       "2500"),
        makeTestCase(Tokens.NUSD,      Tokens.USDC,      ChainId.ETH,       ChainId.BSC,       "2500"),
        makeTestCase(Tokens.NUSD,      Tokens.USDT,      ChainId.ETH,       ChainId.BSC,       "2500"),
        makeTestCase(Tokens.NUSD,      Tokens.NUSD,      ChainId.BSC,       ChainId.POLYGON,   "2500"),
        makeTestCase(Tokens.NUSD,      Tokens.NUSD,      ChainId.POLYGON,   ChainId.BSC,       "2500"),
        makeTestCase(Tokens.UST,       Tokens.UST,       ChainId.BSC,       ChainId.POLYGON,   "2500"),
        makeTestCase(Tokens.UST,       Tokens.UST,       ChainId.POLYGON,   ChainId.ETH,       "2500"),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.AVALANCHE, ChainId.HARMONY,   undefined, false, true),
        makeTestCase(Tokens.NEWO,      Tokens.GMX,       ChainId.AVALANCHE, ChainId.ARBITRUM,  undefined, false, true),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.AVALANCHE, ChainId.ARBITRUM),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.ARBITRUM,  ChainId.BSC,       undefined, false, true),
        makeTestCase(Tokens.NEWO,      Tokens.GMX,       ChainId.ARBITRUM,  ChainId.AVALANCHE, undefined, false, true),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.ARBITRUM,  ChainId.AVALANCHE),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.AURORA,    ChainId.HARMONY,   undefined, false, true),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.ETH,       ChainId.BSC,       undefined, false, true),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.ETH,       ChainId.ARBITRUM),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.ETH,       ChainId.AVALANCHE),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.ARBITRUM,  ChainId.ETH,       "800"),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.AVALANCHE, ChainId.ETH,       "800"),
        makeTestCase(Tokens.NEWO,      Tokens.NEWO,      ChainId.AURORA,    ChainId.HARMONY,   undefined, false, true),
        makeTestCase(Tokens.NEWO,      Tokens.SDT,       ChainId.FANTOM,    ChainId.AVALANCHE, undefined, false, true),
        makeTestCase(Tokens.SDT,       Tokens.SDT,       ChainId.AVALANCHE, ChainId.HARMONY),
        makeTestCase(Tokens.SDT,       Tokens.SDT,       ChainId.AURORA,    ChainId.HARMONY,   undefined, false, true),
        makeTestCase(Tokens.SDT,       Tokens.SDT,       ChainId.ETH,       ChainId.BSC,       undefined, false, true),
        makeTestCase(Tokens.LUNA,      Tokens.LUNA,      ChainId.ARBITRUM,  ChainId.OPTIMISM),
        makeTestCase(Tokens.LUNA,      Tokens.LUNA,      ChainId.OPTIMISM,  ChainId.ARBITRUM),
        makeTestCase(Tokens.LUNA,      Tokens.LUNA,      ChainId.OPTIMISM,  ChainId.HARMONY,   undefined, false, true),
        makeTestCase(Tokens.METIS_ETH, Tokens.ETH,       ChainId.METIS,     ChainId.ETH),
        makeTestCase(Tokens.METIS_ETH, Tokens.ETH,       ChainId.METIS,     ChainId.ETH),
        makeTestCase(Tokens.ETH,       Tokens.METIS_ETH, ChainId.ETH,       ChainId.METIS),
        makeTestCase(Tokens.METIS_ETH, Tokens.ETH,       ChainId.METIS,     ChainId.BOBA),
        makeTestCase(Tokens.NETH,      Tokens.ETH,       ChainId.METIS,     ChainId.ETH),
        makeTestCase(Tokens.METIS_ETH, Tokens.ETH,       ChainId.METIS,     ChainId.ARBITRUM),
        makeTestCase(Tokens.METIS_ETH, Tokens.ETH,       ChainId.METIS,     ChainId.ARBITRUM),
        makeTestCase(Tokens.METIS_ETH, Tokens.WETH_E,    ChainId.METIS,     ChainId.AVALANCHE),
        makeTestCase(Tokens.ONE_ETH,   Tokens.METIS_ETH, ChainId.HARMONY,   ChainId.METIS),
        makeTestCase(Tokens.FTM_ETH,   Tokens.METIS_ETH, ChainId.FANTOM,    ChainId.METIS),
        makeTestCase(Tokens.USDC,      Tokens.USDC,      ChainId.FANTOM,    ChainId.METIS,    "100"),
        makeTestCase(Tokens.USDC,      Tokens.USDC,      ChainId.FANTOM,    ChainId.ETH,      "100"),
        makeTestCase(Tokens.USDT,      Tokens.USDC,      ChainId.FANTOM,    ChainId.METIS,    "100"),
        makeTestCase(Tokens.USDT,      Tokens.USDT,      ChainId.FANTOM,    ChainId.AVALANCHE,"100"),
        makeTestCase(Tokens.USDC,      Tokens.NUSD,      ChainId.FANTOM,    ChainId.METIS,    "100"),
        makeTestCase(Tokens.USDC,      Tokens.USDC,      ChainId.ETH,       ChainId.METIS,    "100"),
    ].forEach((tc: TestCase) => {
        const [bridgeOutputTestTitle, transactionTestTitle, approveTestTitle] = makeTestName(tc)

        let amountTo: BigNumber;

        it(bridgeOutputTestTitle, async function(this: Mocha.Context) {
            this.timeout(DEFAULT_TEST_TIMEOUT)

            let {args: { chainIdFrom, ...testArgs }, expected: {notZero, wantError}} = tc;

            const bridgeInstance = new Bridge.SynapseBridge({ network: chainIdFrom });

            let prom: Promise<Bridge.BridgeOutputEstimate> = bridgeInstance.estimateBridgeTokenOutput(testArgs);

            let amountToReceive: BigNumber;

            try {
                const {amountToReceive: amt} = await prom;
                amountToReceive = amt;
            } catch (e) {
                return (await expectPromiseResolve(prom, !wantError))
            }

            amountTo = amountToReceive;

            if (notZero) {
                return expect(amountToReceive).to.be.gt(Zero);
            } else {
                return expect(amountToReceive).to.equal(Zero)
            }
        });

        it(approveTestTitle, async function(this: Mocha.Context) {
            if (tc.expected.wantError) return

            this.timeout(DEFAULT_TEST_TIMEOUT);

            let {
                args: {
                    chainIdFrom,
                    tokenFrom,
                    amountFrom,
                },
            } = tc;

            const bridgeInstance = new Bridge.SynapseBridge({ network: chainIdFrom });

            switch (tokenSwitch(tokenFrom)) {
                case Tokens.ETH:
                    tokenFrom = Tokens.WETH;
                    break;
                case Tokens.AVAX:
                    tokenFrom = Tokens.WAVAX;
                    break;
                case Tokens.MOVR:
                    tokenFrom = Tokens.WMOVR;
                    break;
            }

            let prom = bridgeInstance.buildApproveTransaction({token:  tokenFrom, amount: amountFrom});

            return (await expectFulfilled(prom))
        });

        const undefEmptyArr = [
            "", "", undefined, "", undefined,
            undefined, "", "", undefined, undefined, ""
        ];

        it(transactionTestTitle, async function(this: Mocha.Context) {
            this.timeout(DEFAULT_TEST_TIMEOUT);

            let {args: { chainIdFrom }, args, expected: {wantError, noAddrTo}} = tc;

            const
                bridgeInstance    = new Bridge.SynapseBridge({ network: chainIdFrom }),
                addressTo: string = noAddrTo
                    ? _.shuffle(undefEmptyArr)[0]
                    : makeWalletSignerWithProvider(chainIdFrom, bridgeTestPrivkey1).address;

            let prom = bridgeInstance.buildBridgeTokenTransaction({...args, amountTo, addressTo});

            return (await (
                wantError
                    ? expectRejected(prom)
                    : expectPromiseResolve(prom, !noAddrTo)
            ))
        });
    });
});
Example #15
Source File: SwapRate-test.ts    From sdk with ISC License 4 votes vote down vote up
describe("TokenSwap -- Asynchronous Tests", function(this: Mocha.Suite) {
    describe("calculateSwapRate() tests", function(this: Mocha.Suite) {
        interface TestCase {
            chainId:   number,
            tokenFrom: Token,
            tokenTo:   Token,
            amountIn:  BigNumber,
            wantError: boolean,
        }

        const makeTestCase = (c: number, t1: Token, t2: Token, amt?: string, wantError?: boolean): TestCase =>
            ({
                chainId:   c,
                tokenFrom: t1,
                tokenTo:   t2,
                amountIn:  getTestAmount(t1, c, amt),
                wantError: wantError ?? false,
            });

        [
            makeTestCase(ChainId.ETH,        Tokens.DAI,        Tokens.USDC),
            makeTestCase(ChainId.ETH,        Tokens.ETH,        Tokens.NETH, null, true),
            makeTestCase(ChainId.OPTIMISM,   Tokens.WETH,       Tokens.NETH),
            makeTestCase(ChainId.BSC,        Tokens.BUSD,       Tokens.USDT),
            makeTestCase(ChainId.BSC,        Tokens.NUSD,       Tokens.BUSD),
            makeTestCase(ChainId.BSC,        Tokens.NUSD,       Tokens.DAI,  null, true),
            makeTestCase(ChainId.ARBITRUM,   Tokens.NEWO,       Tokens.UST,  null, true),
        ].forEach((tc: TestCase) => {
            const
                titleSuffix: string = tc.wantError ? "should fail" : "should pass",
                tokFrom: string     = tc.tokenFrom.symbol,
                tokTo: string       = tc.tokenTo.symbol,
                testTitle: string   = `for ${tokFrom} => ${tokTo} on ${Networks.networkName(tc.chainId)} ${titleSuffix}`,
                testTitle1: string  = `calculateSwapRate ${testTitle}`,
                testTitle2: string  = `buildSwapTokensTransaction ${testTitle}`,
                testTitle3: string  = `swapSetup ${testTitle}`;

            let amountOut: BigNumber;

            step(testTitle1, async function(this: Mocha.Context) {
                this.timeout(DEFAULT_TEST_TIMEOUT);

                let prom: Promise<TokenSwap.EstimatedSwapRate> = Promise.resolve(TokenSwap.calculateSwapRate({
                    chainId:   tc.chainId,
                    tokenFrom: tc.tokenFrom,
                    tokenTo:   tc.tokenTo,
                    amountIn:  tc.amountIn,
                })).then((res) => {
                    amountOut = res.amountOut;
                    return res
                });

                return tc.wantError
                    ? await expectRejected(prom)
                    : expectProperty(await prom, "amountOut").that.is.gt(Zero.toNumber())
            })

            step(testTitle2, async function(this: Mocha.Context) {
                this.timeout(DEFAULT_TEST_TIMEOUT);

                const args: TokenSwap.SwapTokensParams = {
                    ...tc,
                    minAmountOut: amountOut,
                };

                let prom = TokenSwap.buildSwapTokensTransaction(args);

                return (await (
                    tc.wantError
                        ? expectRejected(prom)
                        : expectFulfilled(prom)
                ))
            })

            step(testTitle3, async function(this: Mocha.Context) {
                this.timeout(DEFAULT_TEST_TIMEOUT);

                let prom = TokenSwap.swapSetup(
                    tc.tokenFrom,
                    tc.tokenTo,
                    tc.chainId,
                )

                try {
                    let res = await prom;
                    expect(res).to.have.property("swapInstance");
                    expect(res.swapInstance).to.be.an.instanceof(BaseContract);
                    return
                } catch (e) {
                    if (tc.wantError) {
                        return (await expect(prom).to.eventually.be.rejected);
                    } else {
                        expect.fail(e);
                    }
                }
            })
        })
    })
})