@ethersproject/abi#defaultAbiCoder TypeScript Examples

The following examples show how to use @ethersproject/abi#defaultAbiCoder. 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: permits.ts    From hypertext with GNU General Public License v3.0 6 votes vote down vote up
DAIPermitGatherer: PermitGathererFunction = async (address, deadline, _, library) => {
  const Permit = [
    { name: 'holder', type: 'address' },
    { name: 'spender', type: 'address' },
    { name: 'nonce', type: 'uint256' },
    { name: 'expiry', type: 'uint256' },
    { name: 'allowed', type: 'bool' },
  ]
  const domain = {
    name: 'Dai Stablecoin',
    version: '1',
  }
  const DAIContract = new Contract(
    DAI.address,
    ['function nonces(address holder) view returns (uint256 nonce)'],
    library
  )
  const nonce: BigNumber = await DAIContract.nonces(address)
  const message = {
    holder: address,
    spender: PERMIT_AND_CALL_ADDRESS,
    nonce: await Promise.resolve(nonce.toNumber()).catch(() => nonce.toString()),
    expiry: deadline,
    allowed: true, // DAI only allows unlimited approves
  }
  const inputs = ['address', 'address', 'uint256', 'uint256', 'bool', 'uint8', 'bytes32', 'bytes32']
  return {
    types: {
      EIP712Domain,
      Permit,
    },
    domain,
    message,
    permitSelector: hexDataSlice(id(`permit(${inputs.join(',')})`), 0, 4),
    getPermitData: ({ v, r, s }) =>
      defaultAbiCoder.encode(inputs, [address, PERMIT_AND_CALL_ADDRESS, nonce, deadline, true, v, r, s]),
  }
}
Example #2
Source File: logs.ts    From solana-solidity.js with Apache License 2.0 6 votes vote down vote up
/** @internal */
export function parseTransactionError(
    encoded: Buffer | null,
    computeUnitsUsed: number,
    log: string | null,
    logs: string[]
): TransactionError {
    let error: TransactionError;

    if (log) {
        error = new TransactionError(log);
    } else if (!encoded) {
        const failedMatch = logs[logs.length - 1].match(LOG_FAILED_REGEX);
        error = failedMatch ? new TransactionError(failedMatch[2]) : new TransactionError('return data or log not set');
    } else if (encoded.readUInt32BE(0) != 0x08c379a0) {
        error = new TransactionError('signature not correct');
    } else {
        const revertReason = defaultAbiCoder.decode(['string'], hexDataSlice(encoded, 4));
        error = new TransactionError(revertReason.toString());
    }

    error.logs = logs;
    error.computeUnitsUsed = computeUnitsUsed;

    return error;
}
Example #3
Source File: transaction.ts    From tx2uml with MIT License 6 votes vote down vote up
addConstructorParamsToTrace = (trace: Trace, contracts: Contracts) => {
    // Do we have the ABI for the deployed contract?
    const constructor = contracts[trace.to]?.ethersContract?.interface?.deploy
    if (!constructor?.inputs) {
        // No ABI so we don't know the constructor params which comes from verified contracts on Etherscan
        return
    }
    // we need this flag to determine if there was no constructor params or they are unknown
    trace.parsedConstructorParams = true

    // if we don't have the ABI then we won't have the constructorInputs but we'll double check anyway
    if (!contracts[trace.to]?.constructorInputs?.length) {
        return
    }
    const constructorParams = defaultAbiCoder.decode(
        constructor.inputs,
        "0x" + contracts[trace.to]?.constructorInputs
    )
    // For each constructor param, add to the trace input params
    constructorParams.forEach((param, i) => {
        const components = addValuesToComponents(constructor.inputs[i], param)

        trace.inputParams.push({
            name: constructor.inputs[i].name,
            type: constructor.inputs[i].type,
            value: param,
            components,
        })
    })
    debug(`Decoded ${trace.inputParams.length} constructor params.`)
}
Example #4
Source File: transaction.ts    From tx2uml with MIT License 6 votes vote down vote up
addOutputParamsToTrace = (
    trace: Trace,
    txDescription: TransactionDescription
): void => {
    // Undefined outputs can happen with failed transactions
    if (!trace.outputs || trace.outputs === "0x" || trace.error) return

    const functionFragments = txDescription.functionFragment.outputs
    const outputParams = defaultAbiCoder.decode(
        functionFragments,
        trace.outputs
    )
    // For each output, add to the trace output params
    outputParams.forEach((param, i) => {
        const components = addValuesToComponents(functionFragments[i], param)

        trace.outputParams.push({
            name: functionFragments[i].name,
            type: functionFragments[i].type,
            value: param,
            components,
        })
    })
    debug(
        `Decoded ${trace.outputParams.length} output params for ${trace.funcName} with selector ${trace.funcSelector}`
    )
}
Example #5
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 6 votes vote down vote up
/**
   * Encodes the userData parameter for exiting a WeightedPool by removing exact amounts of tokens
   * @param amountsOut - the amounts of each token to be withdrawn from the pool
   * @param maxBPTAmountIn - the minimum acceptable BPT to burn in return for withdrawn tokens
   */
  static exitBPTInForExactTokensOut = (amountsOut: BigNumberish[], maxBPTAmountIn: BigNumberish): string =>
    defaultAbiCoder.encode(
      ['uint256', 'uint256[]', 'uint256'],
      [WeightedPoolExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT, amountsOut, maxBPTAmountIn]
    );
Example #6
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 6 votes vote down vote up
/**
   * Encodes the userData parameter for exiting a WeightedPool by removing a single token in return for an exact amount of BPT
   * @param bptAmountIn - the amount of BPT to be burned
   * @param enterTokenIndex - the index of the token to removed from the pool
   */
  static exitExactBPTInForOneTokenOut = (bptAmountIn: BigNumberish, exitTokenIndex: number): string =>
    defaultAbiCoder.encode(
      ['uint256', 'uint256', 'uint256'],
      [WeightedPoolExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT, bptAmountIn, exitTokenIndex]
    );
Example #7
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 6 votes vote down vote up
/**
   * Encodes the userData parameter for joining a WeightedPool proportionally to receive an exact amount of BPT
   * @param bptAmountOut - the amount of BPT to be minted
   */
  static joinAllTokensInForExactBPTOut = (bptAmountOut: BigNumberish): string =>
    defaultAbiCoder.encode(
      ['uint256', 'uint256'],
      [WeightedPoolJoinKind.ALL_TOKENS_IN_FOR_EXACT_BPT_OUT, bptAmountOut]
    );
Example #8
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 6 votes vote down vote up
/**
   * Encodes the userData parameter for joining a WeightedPool with a single token to receive an exact amount of BPT
   * @param bptAmountOut - the amount of BPT to be minted
   * @param enterTokenIndex - the index of the token to be provided as liquidity
   */
  static joinTokenInForExactBPTOut = (bptAmountOut: BigNumberish, enterTokenIndex: number): string =>
    defaultAbiCoder.encode(
      ['uint256', 'uint256', 'uint256'],
      [WeightedPoolJoinKind.TOKEN_IN_FOR_EXACT_BPT_OUT, bptAmountOut, enterTokenIndex]
    );
Example #9
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 6 votes vote down vote up
/**
   * Encodes the userData parameter for joining a WeightedPool with exact token inputs
   * @param amountsIn - the amounts each of token to deposit in the pool as liquidity
   * @param minimumBPT - the minimum acceptable BPT to receive in return for deposited tokens
   */
  static joinExactTokensInForBPTOut = (amountsIn: BigNumberish[], minimumBPT: BigNumberish): string =>
    defaultAbiCoder.encode(
      ['uint256', 'uint256[]', 'uint256'],
      [WeightedPoolJoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT, amountsIn, minimumBPT]
    );
Example #10
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 6 votes vote down vote up
/**
   * Encodes the userData parameter for exiting a StablePool by removing exact amounts of tokens
   * @param amountsOut - the amounts of each token to be withdrawn from the pool
   * @param maxBPTAmountIn - the minimum acceptable BPT to burn in return for withdrawn tokens
   */
  static exitBPTInForExactTokensOut = (amountsOut: BigNumberish[], maxBPTAmountIn: BigNumberish): string =>
    defaultAbiCoder.encode(
      ['uint256', 'uint256[]', 'uint256'],
      [StablePoolExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT, amountsOut, maxBPTAmountIn]
    );
Example #11
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 6 votes vote down vote up
/**
   * Encodes the userData parameter for exiting a StablePool by removing a single token in return for an exact amount of BPT
   * @param bptAmountIn - the amount of BPT to be burned
   * @param enterTokenIndex - the index of the token to removed from the pool
   */
  static exitExactBPTInForOneTokenOut = (bptAmountIn: BigNumberish, exitTokenIndex: number): string =>
    defaultAbiCoder.encode(
      ['uint256', 'uint256', 'uint256'],
      [StablePoolExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT, bptAmountIn, exitTokenIndex]
    );
Example #12
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 6 votes vote down vote up
/**
   * Encodes the userData parameter for joining a StablePool with to receive an exact amount of BPT
   * @param bptAmountOut - the amount of BPT to be minted
   * @param enterTokenIndex - the index of the token to be provided as liquidity
   */
  static joinTokenInForExactBPTOut = (bptAmountOut: BigNumberish, enterTokenIndex: number): string =>
    defaultAbiCoder.encode(
      ['uint256', 'uint256', 'uint256'],
      [StablePoolJoinKind.TOKEN_IN_FOR_EXACT_BPT_OUT, bptAmountOut, enterTokenIndex]
    );
Example #13
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 6 votes vote down vote up
/**
   * Encodes the userData parameter for joining a StablePool with exact token inputs
   * @param amountsIn - the amounts each of token to deposit in the pool as liquidity
   * @param minimumBPT - the minimum acceptable BPT to receive in return for deposited tokens
   */
  static joinExactTokensInForBPTOut = (amountsIn: BigNumberish[], minimumBPT: BigNumberish): string =>
    defaultAbiCoder.encode(
      ['uint256', 'uint256[]', 'uint256'],
      [StablePoolJoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT, amountsIn, minimumBPT]
    );
Example #14
Source File: permits.ts    From hypertext with GNU General Public License v3.0 6 votes vote down vote up
USDCPermitGatherer: PermitGathererFunction = async (address, deadline, approveAmount, library) => {
  const Permit = [
    { name: 'owner', type: 'address' },
    { name: 'spender', type: 'address' },
    { name: 'value', type: 'uint256' },
    { name: 'nonce', type: 'uint256' },
    { name: 'deadline', type: 'uint256' },
  ]
  const domain = {
    name: 'USD Coin',
    version: '2',
  }
  const USDCContract = new Contract(
    USDC.address,
    ['function nonces(address owner) view returns (uint256 nonce)'],
    library
  )
  const nonce: BigNumber = await USDCContract.nonces(address)
  const value = `0x${approveAmount.toString(16)}`
  const message = {
    owner: address,
    spender: PERMIT_AND_CALL_ADDRESS,
    value,
    nonce: await Promise.resolve(nonce.toNumber()).catch(() => nonce.toString()),
    deadline,
  }
  const inputs = ['address', 'address', 'uint256', 'uint256', 'uint8', 'bytes32', 'bytes32']
  return {
    types: {
      EIP712Domain,
      Permit,
    },
    domain,
    message,
    permitSelector: hexDataSlice(id(`permit(${inputs.join(',')})`), 0, 4),
    getPermitData: ({ v, r, s }) =>
      defaultAbiCoder.encode(inputs, [address, PERMIT_AND_CALL_ADDRESS, value, deadline, v, r, s]),
  }
}
Example #15
Source File: permits.ts    From hypertext with GNU General Public License v3.0 6 votes vote down vote up
UNIPermitGatherer: PermitGathererFunction = async (address, deadline, approveAmount, library) => {
  const Permit = [
    { name: 'owner', type: 'address' },
    { name: 'spender', type: 'address' },
    { name: 'value', type: 'uint256' },
    { name: 'nonce', type: 'uint256' },
    { name: 'deadline', type: 'uint256' },
  ]
  const domain = { name: 'Uniswap' }
  const UNIContract = new Contract(
    UNI.address,
    ['function nonces(address holder) view returns (uint256 nonce)'],
    library
  )
  const nonce: BigNumber = await UNIContract.nonces(address)
  const value = `0x${approveAmount.toString(16)}`
  const message = {
    owner: address,
    spender: PERMIT_AND_CALL_ADDRESS,
    value,
    nonce: await Promise.resolve(nonce.toNumber()).catch(() => nonce.toString()),
    deadline,
  }
  const inputs = ['address', 'address', 'uint256', 'uint256', 'uint8', 'bytes32', 'bytes32']
  return {
    types: {
      EIP712Domain: EIP712DomainWithoutVersion,
      Permit,
    },
    domain,
    message,
    permitSelector: hexDataSlice(id(`permit(${inputs.join(',')})`), 0, 4),
    getPermitData: ({ v, r, s }) =>
      defaultAbiCoder.encode(inputs, [address, PERMIT_AND_CALL_ADDRESS, value, deadline, v, r, s]),
  }
}
Example #16
Source File: engine.ts    From aurora.js with Creative Commons Zero v1.0 Universal 6 votes vote down vote up
async getStorageAt(
    address: Address,
    key: U256 | number | string,
    options?: ViewOptions
  ): Promise<Result<U256, Error>> {
    const args = new GetStorageAtArgs(
      address.toBytes(),
      parseHexString(defaultAbiCoder.encode(['uint256'], [key]))
    );
    const result = await this.callFunction(
      'get_storage_at',
      args.encode(),
      options
    );
    return result.map(toBigIntBE);
  }
Example #17
Source File: engine.ts    From aurora.js with Creative Commons Zero v1.0 Universal 6 votes vote down vote up
async initialize(options: any): Promise<Result<TransactionID, Error>> {
    const newArgs = new NewCallArgs(
      parseHexString(defaultAbiCoder.encode(['uint256'], [options.chain || 0])),
      options.owner || '',
      options.bridgeProver || '',
      new BN(options.upgradeDelay || 0)
    );
    const default_ft_metadata = FungibleTokenMetadata.default();
    const given_ft_metadata = options.metadata || default_ft_metadata;
    const ft_metadata = new FungibleTokenMetadata(
      given_ft_metadata.spec || default_ft_metadata.spec,
      given_ft_metadata.name || default_ft_metadata.name,
      given_ft_metadata.symbol || default_ft_metadata.symbol,
      given_ft_metadata.icon || default_ft_metadata.icon,
      given_ft_metadata.reference || default_ft_metadata.reference,
      given_ft_metadata.reference_hash || default_ft_metadata.reference_hash,
      given_ft_metadata.decimals || default_ft_metadata.decimals
    );
    // default values are the testnet values
    const connectorArgs = new InitCallArgs(
      options.prover || 'prover.ropsten.testnet',
      options.ethCustodian || '9006a6D7d08A388Eeea0112cc1b6b6B15a4289AF',
      ft_metadata
    );

    // TODO: this should be able to be a single transaction with multiple actions,
    // but there doesn't seem to be a good way to do that in `near-api-js` presently.
    const tx = await this.promiseAndThen(
      this.callMutativeFunction('new', newArgs.encode()),
      (_) =>
        this.callMutativeFunction('new_eth_connector', connectorArgs.encode())
    );

    return tx.map(({ id }) => id);
  }
Example #18
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 5 votes vote down vote up
/**
   * Encodes the userData parameter for exiting a StablePool by removing tokens in return for an exact amount of BPT
   * @param bptAmountIn - the amount of BPT to be burned
   */
  static exitExactBPTInForTokensOut = (bptAmountIn: BigNumberish): string =>
    defaultAbiCoder.encode(['uint256', 'uint256'], [StablePoolExitKind.EXACT_BPT_IN_FOR_TOKENS_OUT, bptAmountIn]);
Example #19
Source File: index.ts    From ccip-read with MIT License 5 votes vote down vote up
async function handleCall(
  provider: CCIPReadProvider,
  params: { transaction: TransactionRequest; blockTag?: BlockTag },
  maxCalls = 4
): Promise<{ transaction: TransactionRequest; result: BytesLike }> {
  for (let i = 0; i < maxCalls; i++) {
    let result;
    let bytes: Uint8Array;
    try {
      result = await provider.parent.perform('call', params);
      bytes = arrayify(result);
    } catch (e) {
      if (isRevertError(e)) {
        bytes = arrayify(e.error.data.originalError.data);
      } else {
        return logger.throwError('The error message does not contain originalError', Logger.errors.UNKNOWN_ERROR);
      }
    }
    if (bytes.length % 32 !== 4 || hexlify(bytes.slice(0, 4)) !== CCIP_READ_INTERFACE.getSighash('OffchainLookup')) {
      return { transaction: params.transaction, result: bytes };
    }
    const { sender, urls, callData, callbackFunction, extraData } = CCIP_READ_INTERFACE.decodeErrorResult(
      'OffchainLookup',
      bytes
    );
    if (params.transaction.to === undefined || sender.toLowerCase() !== params.transaction.to.toLowerCase()) {
      return logger.throwError('OffchainLookup thrown in nested scope', Logger.errors.UNSUPPORTED_OPERATION, {
        to: params.transaction.to,
        sender,
        urls,
        callData,
        callbackFunction,
        extraData,
      });
    }
    const response = await sendRPC(provider.fetcher, urls, params.transaction.to, callData);
    const data = hexConcat([
      callbackFunction,
      defaultAbiCoder.encode(CCIP_READ_INTERFACE.getFunction('callback').inputs, [response, extraData]),
    ]);
    params = Object.assign({}, params, {
      transaction: Object.assign({}, params.transaction, { data }),
    });
  }
  return logger.throwError('Too many redirects', Logger.errors.TIMEOUT, { to: params.transaction.to });
}
Example #20
Source File: StablePhantomPool.ts    From balancer-v2-monorepo with GNU General Public License v3.0 5 votes vote down vote up
private _encodeExitExactBPTInForTokensOut(bptAmountIn: BigNumberish): string {
    const EXACT_BPT_IN_FOR_TOKENS_OUT = 0;
    return defaultAbiCoder.encode(['uint256', 'uint256'], [EXACT_BPT_IN_FOR_TOKENS_OUT, bptAmountIn]);
  }
Example #21
Source File: LinearPool.ts    From balancer-v2-monorepo with GNU General Public License v3.0 5 votes vote down vote up
private _encodeExitEmergencyExactBPTInForTokensOut(bptAmountIn: BigNumberish): string {
    const EMERGENCY_EXACT_BPT_IN_FOR_TOKENS_OUT = 0;
    return defaultAbiCoder.encode(['uint256', 'uint256'], [EMERGENCY_EXACT_BPT_IN_FOR_TOKENS_OUT, bptAmountIn]);
  }
Example #22
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 5 votes vote down vote up
/**
   * Encodes the userData parameter for exiting a ManagedPool to remove a token.
   * This can only be done by the pool owner.
   */
  static exitForRemoveToken = (tokenIndex: BigNumberish): string =>
    defaultAbiCoder.encode(['uint256', 'uint256'], [WeightedPoolExitKind.REMOVE_TOKEN, tokenIndex]);
Example #23
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 5 votes vote down vote up
/**
   * Encodes the userData parameter for adding a new token to a WeightedPool
   * @param amountIn - the amount of the tokens to send to the pool as its initial balance
   */
  static joinForAddToken = (amountIn: BigNumberish): string =>
    defaultAbiCoder.encode(['uint256', 'uint256'], [WeightedPoolJoinKind.ADD_TOKEN, amountIn]);
Example #24
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 5 votes vote down vote up
/**
   * Encodes the userData parameter for exiting a WeightedPool by removing tokens in return for an exact amount of BPT
   * @param bptAmountIn - the amount of BPT to be burned
   */
  static exitExactBPTInForTokensOut = (bptAmountIn: BigNumberish): string =>
    defaultAbiCoder.encode(['uint256', 'uint256'], [WeightedPoolExitKind.EXACT_BPT_IN_FOR_TOKENS_OUT, bptAmountIn]);
Example #25
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 5 votes vote down vote up
/**
   * Encodes the userData parameter for providing the initial liquidity to a StablePool
   * @param initialBalances - the amounts of tokens to send to the pool to form the initial balances
   */
  static joinInit = (amountsIn: BigNumberish[]): string =>
    defaultAbiCoder.encode(['uint256', 'uint256[]'], [StablePoolJoinKind.INIT, amountsIn]);
Example #26
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 5 votes vote down vote up
/**
   * Encodes the userData parameter for collecting protocol fees for StablePhantomPool
   */
  static joinCollectProtocolFees = (): string =>
    defaultAbiCoder.encode(['uint256'], [StablePhantomPoolJoinKind.COLLECT_PROTOCOL_FEES]);
Example #27
Source File: encoder.ts    From balancer-v2-monorepo with GNU General Public License v3.0 5 votes vote down vote up
/**
   * Encodes the userData parameter for providing the initial liquidity to a WeightedPool
   * @param initialBalances - the amounts of tokens to send to the pool to form the initial balances
   */
  static joinInit = (amountsIn: BigNumberish[]): string =>
    defaultAbiCoder.encode(['uint256', 'uint256[]'], [WeightedPoolJoinKind.INIT, amountsIn]);
Example #28
Source File: L2DaiGateway.ts    From arbitrum-dai-bridge with GNU Affero General Public License v3.0 4 votes vote down vote up
describe('L2DaiGateway', () => {
  describe('finalizeInboundTransfer', () => {
    const depositAmount = 100
    const defaultData = ethers.utils.defaultAbiCoder.encode(['bytes', 'bytes'], ['0x12', '0x'])

    it('mints tokens', async () => {
      const [sender, l1Dai, router] = await ethers.getSigners()
      const { l2Dai, l2DaiGateway, l2Deployer } = await setupTest({
        l1Dai,
        l1DaiBridge: sender,
        router,
        deployer: sender,
      })
      const receiverAddress = sender.address

      const tx = await l2DaiGateway
        .connect(l2Deployer)
        .finalizeInboundTransfer(l1Dai.address, sender.address, receiverAddress, depositAmount, defaultData)

      expect(await l2Dai.balanceOf(receiverAddress)).to.be.eq(depositAmount)
      expect(await l2Dai.totalSupply()).to.be.eq(depositAmount)
      await expect(tx)
        .to.emit(l2DaiGateway, 'DepositFinalized')
        .withArgs(l1Dai.address, sender.address, receiverAddress, depositAmount)
      // await expect(tx).not.to.emit(l2DaiGateway, 'TransferAndCallTriggered')
    })

    it('mints tokens for a 3rd party', async () => {
      const [sender, receiver, l1Dai, router] = await ethers.getSigners()
      const { l2Dai, l2DaiGateway, l2Deployer } = await setupTest({
        l1Dai,
        l1DaiBridge: sender,
        router,
        deployer: sender,
      })

      const tx = await l2DaiGateway
        .connect(l2Deployer)
        .finalizeInboundTransfer(l1Dai.address, sender.address, receiver.address, depositAmount, defaultData)

      expect(await l2Dai.balanceOf(receiver.address)).to.be.eq(depositAmount)
      expect(await l2Dai.totalSupply()).to.be.eq(depositAmount)
      await expect(tx)
        .to.emit(l2DaiGateway, 'DepositFinalized')
        .withArgs(l1Dai.address, sender.address, receiver.address, depositAmount)
      // await expect(tx).not.to.emit(l2DaiGateway, 'TransferAndCallTriggered')
    })

    it('mints tokens even when closed', async () => {
      const [sender, l1Dai, router] = await ethers.getSigners()
      const { l2Dai, l2DaiGateway, l2Deployer } = await setupTest({
        l1Dai,
        l1DaiBridge: sender,
        router,
        deployer: sender,
      })
      const receiverAddress = sender.address

      await l2DaiGateway.close()
      const tx = await l2DaiGateway
        .connect(l2Deployer)
        .finalizeInboundTransfer(l1Dai.address, sender.address, receiverAddress, depositAmount, defaultData)

      expect(await l2Dai.balanceOf(receiverAddress)).to.be.eq(depositAmount)
      expect(await l2Dai.totalSupply()).to.be.eq(depositAmount)
      await expect(tx)
        .to.emit(l2DaiGateway, 'DepositFinalized')
        .withArgs(l1Dai.address, sender.address, receiverAddress, depositAmount)
    })

    it('reverts when withdrawing not supported tokens', async () => {
      const [sender, l1Dai, router, dummyAcc] = await ethers.getSigners()
      const { l2DaiGateway, l2Deployer } = await setupTest({ l1Dai, l1DaiBridge: sender, router, deployer: sender })
      const receiverAddress = sender.address

      await expect(
        l2DaiGateway
          .connect(l2Deployer)
          .finalizeInboundTransfer(dummyAcc.address, sender.address, receiverAddress, depositAmount, defaultData),
      ).to.be.revertedWith(errorMessages.tokenMismatch)
    })

    it('reverts when DAI minting access was revoked', async () => {
      const [sender, l1Dai, router] = await ethers.getSigners()
      const { l2DaiGateway, l2Dai, l2Deployer } = await setupTest({
        l1Dai,
        l1DaiBridge: sender,
        router,
        deployer: sender,
      })
      const receiverAddress = sender.address

      await l2Dai.deny(l2DaiGateway.address)

      await expect(
        l2DaiGateway
          .connect(l2Deployer)
          .finalizeInboundTransfer(l1Dai.address, sender.address, receiverAddress, depositAmount, defaultData),
      ).to.be.revertedWith(errorMessages.notOwnerOfDai)
    })

    it('reverts when called not relying message from l1DaiGateway', async () => {
      const [sender, l1Dai, router, dummyAcc] = await ethers.getSigners()
      const { l2DaiGateway } = await setupTest({ l1Dai, l1DaiBridge: sender, router, deployer: sender })

      await expect(
        l2DaiGateway
          .connect(dummyAcc)
          .finalizeInboundTransfer(dummyAcc.address, sender.address, sender.address, depositAmount, defaultData),
      ).to.be.revertedWith(errorMessages.l1CounterpartMismatch)
    })

    it('reverts when called directly by l1 counterpart', async () => {
      // this should fail b/c we require address translation
      const [sender, l1Dai, router] = await ethers.getSigners()
      const { l2DaiGateway } = await setupTest({ l1Dai, l1DaiBridge: sender, router, deployer: sender })
      const receiverAddress = sender.address

      await expect(
        l2DaiGateway.finalizeInboundTransfer(
          l1Dai.address,
          sender.address,
          receiverAddress,
          depositAmount,
          defaultData,
        ),
      ).to.be.revertedWith(errorMessages.l1CounterpartMismatch)
    })
  })

  describe('outboundTransfer(address,address,uint256,bytes)', () => {
    const withdrawAmount = 100
    const defaultData = '0x'
    const defaultDataWithNotEmptyCallHookData = '0x12'
    const expectedWithdrawalId = 0

    it('sends xdomain message and burns tokens', async () => {
      const [deployer, l1DaiBridge, l1Dai, router, sender] = await ethers.getSigners()
      const { l2Dai, l2DaiGateway, arbSysMock } = await setupWithdrawalTest({
        l1Dai,
        l1DaiBridge,
        router,
        user1: sender,
        deployer,
      })

      const tx = await l2DaiGateway
        .connect(sender)
        ['outboundTransfer(address,address,uint256,bytes)'](l1Dai.address, sender.address, withdrawAmount, defaultData)
      const withdrawCrossChainCall = arbSysMock.smocked.sendTxToL1.calls[0]

      expect(await l2Dai.balanceOf(sender.address)).to.be.eq(initialTotalL2Supply - withdrawAmount)
      expect(await l2Dai.totalSupply()).to.be.eq(initialTotalL2Supply - withdrawAmount)
      await expect(tx)
        .to.emit(l2DaiGateway, 'WithdrawalInitiated')
        .withArgs(
          l1Dai.address,
          sender.address,
          sender.address,
          expectedWithdrawalId,
          expectedWithdrawalId,
          withdrawAmount,
        )
      expect(withdrawCrossChainCall.destAddr).to.eq(l1DaiBridge.address)
      expect(withdrawCrossChainCall.calldataForL1).to.eq(
        new L1DaiGateway__factory().interface.encodeFunctionData('finalizeInboundTransfer', [
          l1Dai.address,
          sender.address,
          sender.address,
          withdrawAmount,
          ethers.utils.defaultAbiCoder.encode(['uint256', 'bytes'], [expectedWithdrawalId, defaultData]),
        ]),
      )
    })

    it('sends xdomain message and burns tokens for 3rd party', async () => {
      const [deployer, , l1DaiBridge, l1Dai, router, sender, receiver] = await ethers.getSigners()
      const { l2Dai, l2DaiGateway, arbSysMock } = await setupWithdrawalTest({
        l1Dai,
        l1DaiBridge,
        router,
        user1: sender,
        deployer,
      })

      const tx = await l2DaiGateway
        .connect(sender)
        ['outboundTransfer(address,address,uint256,bytes)'](
          l1Dai.address,
          receiver.address,
          withdrawAmount,
          defaultData,
        )
      const withdrawCrossChainCall = arbSysMock.smocked.sendTxToL1.calls[0]

      expect(await l2Dai.balanceOf(sender.address)).to.be.eq(initialTotalL2Supply - withdrawAmount)
      expect(await l2Dai.balanceOf(receiver.address)).to.be.eq(0)
      expect(await l2Dai.totalSupply()).to.be.eq(initialTotalL2Supply - withdrawAmount)
      await expect(tx)
        .to.emit(l2DaiGateway, 'WithdrawalInitiated')
        .withArgs(
          l1Dai.address,
          sender.address,
          receiver.address,
          expectedWithdrawalId,
          expectedWithdrawalId,
          withdrawAmount,
        )
      expect(withdrawCrossChainCall.destAddr).to.eq(l1DaiBridge.address)
      expect(withdrawCrossChainCall.calldataForL1).to.eq(
        new L1DaiGateway__factory().interface.encodeFunctionData('finalizeInboundTransfer', [
          l1Dai.address,
          sender.address,
          receiver.address,
          withdrawAmount,
          ethers.utils.defaultAbiCoder.encode(['uint256', 'bytes'], [expectedWithdrawalId, defaultData]),
        ]),
      )
    })

    it('sends xdomain message and burns tokens when called through router', async () => {
      const [deployer, , l1DaiBridge, l1Dai, router, sender, receiver] = await ethers.getSigners()
      const { l2Dai, l2DaiGateway, arbSysMock } = await setupWithdrawalTest({
        l1Dai,
        l1DaiBridge,
        router,
        user1: sender,
        deployer,
      })
      const routerEncodedData = defaultAbiCoder.encode(['address', 'bytes'], [sender.address, defaultData])

      const tx = await l2DaiGateway
        .connect(router)
        ['outboundTransfer(address,address,uint256,bytes)'](
          l1Dai.address,
          receiver.address,
          withdrawAmount,
          routerEncodedData,
        )
      const withdrawCrossChainCall = arbSysMock.smocked.sendTxToL1.calls[0]

      expect(await l2Dai.balanceOf(sender.address)).to.be.eq(initialTotalL2Supply - withdrawAmount)
      expect(await l2Dai.balanceOf(receiver.address)).to.be.eq(0)
      expect(await l2Dai.totalSupply()).to.be.eq(initialTotalL2Supply - withdrawAmount)
      await expect(tx)
        .to.emit(l2DaiGateway, 'WithdrawalInitiated')
        .withArgs(
          l1Dai.address,
          sender.address,
          receiver.address,
          expectedWithdrawalId,
          expectedWithdrawalId,
          withdrawAmount,
        )
      expect(withdrawCrossChainCall.destAddr).to.eq(l1DaiBridge.address)
      expect(withdrawCrossChainCall.calldataForL1).to.eq(
        new L1DaiGateway__factory().interface.encodeFunctionData('finalizeInboundTransfer', [
          l1Dai.address,
          sender.address,
          receiver.address,
          withdrawAmount,
          ethers.utils.defaultAbiCoder.encode(['uint256', 'bytes'], [expectedWithdrawalId, defaultData]),
        ]),
      )
    })

    it('reverts when called with a different token', async () => {
      const [sender, l1DaiBridge, l1Dai, router] = await ethers.getSigners()
      const { l2Dai, l2DaiGateway } = await setupWithdrawalTest({
        l1Dai,
        l1DaiBridge,
        router,
        user1: sender,
        deployer: sender,
      })

      await expect(
        l2DaiGateway['outboundTransfer(address,address,uint256,bytes)'](
          l2Dai.address,
          sender.address,
          withdrawAmount,
          defaultData,
        ),
      ).to.be.revertedWith(errorMessages.tokenMismatch)
    })

    it('reverts when called with callHookData', async () => {
      const [sender, l1DaiBridge, l1Dai, router] = await ethers.getSigners()
      const { l2DaiGateway } = await setupWithdrawalTest({
        l1Dai,
        l1DaiBridge,
        router,
        user1: sender,
        deployer: sender,
      })

      await expect(
        l2DaiGateway['outboundTransfer(address,address,uint256,bytes)'](
          l1Dai.address,
          sender.address,
          withdrawAmount,
          defaultDataWithNotEmptyCallHookData,
        ),
      ).to.be.revertedWith(errorMessages.callHookDataNotAllowed)
    })

    it('reverts when bridge closed', async () => {
      const [sender, l1DaiBridge, l1Dai, router] = await ethers.getSigners()
      const { l2DaiGateway } = await setupWithdrawalTest({
        l1Dai,
        l1DaiBridge,
        router,
        user1: sender,
        deployer: sender,
      })

      await l2DaiGateway.connect(sender).close()

      await expect(
        l2DaiGateway['outboundTransfer(address,address,uint256,bytes)'](
          l1Dai.address,
          sender.address,
          withdrawAmount,
          defaultData,
        ),
      ).to.be.revertedWith(errorMessages.closed)
    })

    it('reverts when bridge doesnt have burn permissions on DAI', async () => {
      const [sender, l1DaiBridge, l1Dai, router] = await ethers.getSigners()
      const { l2Dai, l2DaiGateway } = await setupWithdrawalTest({
        l1Dai,
        l1DaiBridge,
        router,
        user1: sender,
        deployer: sender,
      })

      // remove burn permissions
      await l2Dai.deny(l2DaiGateway.address)

      await expect(
        l2DaiGateway['outboundTransfer(address,address,uint256,bytes)'](
          l1Dai.address,
          sender.address,
          withdrawAmount,
          defaultData,
        ),
      ).to.be.revertedWith(errorMessages.insufficientAllowance)
    })

    it('reverts when user funds too low', async () => {
      const [sender, l1DaiBridge, l1Dai, router, user2] = await ethers.getSigners()
      const { l2DaiGateway } = await setupWithdrawalTest({
        l1Dai,
        l1DaiBridge,
        router,
        user1: sender,
        deployer: sender,
      })

      await expect(
        l2DaiGateway
          .connect(user2)
          ['outboundTransfer(address,address,uint256,bytes)'](
            l1Dai.address,
            sender.address,
            withdrawAmount,
            defaultData,
          ),
      ).to.be.revertedWith(errorMessages.insufficientFunds)
    })
  })

  describe('outboundTransfer(address,address,uint256,uint256,uint256,bytes)', () => {
    const withdrawAmount = 100
    const defaultData = '0x'
    const expectedWithdrawalId = 0
    const maxGas = 100
    const gasPriceBid = 200

    it('sends xdomain message and burns tokens', async () => {
      const [deployer, l1DaiBridge, l1Dai, router, sender] = await ethers.getSigners()
      const { l2Dai, l2DaiGateway, arbSysMock } = await setupWithdrawalTest({
        l1Dai,
        l1DaiBridge,
        router,
        user1: sender,
        deployer,
      })

      const tx = await l2DaiGateway
        .connect(sender)
        ['outboundTransfer(address,address,uint256,uint256,uint256,bytes)'](
          l1Dai.address,
          sender.address,
          withdrawAmount,
          maxGas,
          gasPriceBid,
          defaultData,
        )
      const withdrawCrossChainCall = arbSysMock.smocked.sendTxToL1.calls[0]

      expect(await l2Dai.balanceOf(sender.address)).to.be.eq(initialTotalL2Supply - withdrawAmount)
      expect(await l2Dai.totalSupply()).to.be.eq(initialTotalL2Supply - withdrawAmount)
      await expect(tx)
        .to.emit(l2DaiGateway, 'WithdrawalInitiated')
        .withArgs(
          l1Dai.address,
          sender.address,
          sender.address,
          expectedWithdrawalId,
          expectedWithdrawalId,
          withdrawAmount,
        )
      expect(withdrawCrossChainCall.destAddr).to.eq(l1DaiBridge.address)
      expect(withdrawCrossChainCall.calldataForL1).to.eq(
        new L1DaiGateway__factory().interface.encodeFunctionData('finalizeInboundTransfer', [
          l1Dai.address,
          sender.address,
          sender.address,
          withdrawAmount,
          ethers.utils.defaultAbiCoder.encode(['uint256', 'bytes'], [expectedWithdrawalId, defaultData]),
        ]),
      )
    })
  })

  describe('close', () => {
    it('can be called by owner', async () => {
      const [owner, l1Dai, router] = await ethers.getSigners()
      const { l2DaiGateway } = await setupTest({ l1Dai, l1DaiBridge: owner, router, deployer: owner })

      expect(await l2DaiGateway.isOpen()).to.be.eq(1)
      const closeTx = await l2DaiGateway.connect(owner).close()

      await expect(closeTx).to.emit(l2DaiGateway, 'Closed')

      expect(await l2DaiGateway.isOpen()).to.be.eq(0)
    })

    it('can be called multiple times by the owner but nothing changes', async () => {
      const [owner, l1Dai, router] = await ethers.getSigners()
      const { l2DaiGateway } = await setupTest({ l1Dai, l1DaiBridge: owner, router, deployer: owner })

      await l2DaiGateway.connect(owner).close()
      expect(await l2DaiGateway.isOpen()).to.be.eq(0)

      await l2DaiGateway.connect(owner).close()
      expect(await l2DaiGateway.isOpen()).to.be.eq(0)
    })

    it('reverts when called not by the owner', async () => {
      const [owner, l1Dai, router, user1] = await ethers.getSigners()
      const { l2DaiGateway } = await setupTest({ l1Dai, l1DaiBridge: owner, router, deployer: owner })

      await expect(l2DaiGateway.connect(user1).close()).to.be.revertedWith(errorMessages.notOwner)
    })
  })

  describe('calculateL2TokenAddress', () => {
    it('return l2Dai address when asked about dai', async () => {
      const [owner, l1Dai, router] = await ethers.getSigners()
      const { l2DaiGateway, l2Dai } = await setupTest({ l1Dai, l1DaiBridge: owner, router, deployer: owner })

      expect(await l2DaiGateway.calculateL2TokenAddress(l1Dai.address)).to.eq(l2Dai.address)
    })

    it('returns zero address for unknown tokens', async () => {
      const [owner, l1Dai, router] = await ethers.getSigners()
      const randomToken = await getRandomAddress()
      const { l2DaiGateway } = await setupTest({ l1Dai, l1DaiBridge: owner, router, deployer: owner })

      expect(await l2DaiGateway.calculateL2TokenAddress(randomToken)).to.eq(ethers.constants.AddressZero)
    })
  })

  describe('constructor', () => {
    it('assigns all variables properly', async () => {
      const [l1Counterpart, router, l1Dai, l2Dai] = await getRandomAddresses()

      const l2DaiGateway = await simpleDeploy<L2DaiGateway__factory>('L2DaiGateway', [
        l1Counterpart,
        router,
        l1Dai,
        l2Dai,
      ])

      expect(await l2DaiGateway.l1Counterpart()).to.be.eq(l1Counterpart)
      expect(await l2DaiGateway.l2Router()).to.be.eq(router)
      expect(await l2DaiGateway.l1Dai()).to.be.eq(l1Dai)
      expect(await l2DaiGateway.l2Dai()).to.be.eq(l2Dai)
      expect(await l2DaiGateway.isOpen()).to.be.eq(1)
    })
  })

  it('has correct public interface', async () => {
    await assertPublicMutableMethods('L2DaiGateway', [
      'finalizeInboundTransfer(address,address,address,uint256,bytes)', // finalize deposit
      'outboundTransfer(address,address,uint256,bytes)', // withdraw
      'outboundTransfer(address,address,uint256,uint256,uint256,bytes)', // withdrawTo
      'close()',
      'rely(address)',
      'deny(address)',
    ])
    await assertPublicNotMutableMethods('L2DaiGateway', [
      'getOutboundCalldata(address,address,address,uint256,bytes)',
      'calculateL2TokenAddress(address)',

      // storage variables:
      'l1Counterpart()',
      'isOpen()',
      'l1Dai()',
      'l2Dai()',
      'l2Router()',
      'wards(address)',
      'counterpartGateway()',
    ])
  })

  testAuth({
    name: 'L2DaiGateway',
    getDeployArgs: async () => {
      const [l1Counterpart, router, l1Dai, l2Dai] = await getRandomAddresses()

      return [l1Counterpart, router, l1Dai, l2Dai]
    },
    authedMethods: [(c) => c.close()],
  })
})
Example #29
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 PRECISION = BigNumber.from('1000000000000000000000');
  const blockTag = typeof snapshot === 'number' ? snapshot : 'latest';
  const eip1155OwnersParams = {
    accounts: {
      __args: {
        where: {
          id_in: addresses.map((a) => a.toLowerCase())
        }
      },
      id: true,
      balances: {
        value: true,
        token: {
          registry: {
            id: true
          },
          identifier: true
        }
      }
    }
  };
  if (snapshot !== 'latest') {
    // @ts-ignore
    eip1155OwnersParams.accounts.__args.block = { number: snapshot };
  }
  const idsToCheck = new Set<string>();

  const result = await subgraphRequest(
    SUBGRAPH_URL[network],
    eip1155OwnersParams
  );
  result.accounts.forEach((element) => {
    element.relBal = element.balances.filter((balance) => {
      const isRightAddress =
        balance.token.registry.id.toLowerCase() ===
          options.address.toLowerCase() && balance.value != '0';
      if (isRightAddress) {
        idsToCheck.add(balance.token.identifier);
      }
      return isRightAddress;
    });
  });
  let ids = Array.from(idsToCheck);
  const response = await multicall(
    network,
    _provider,
    abi2,
    ids.map((id: any) => [options.staking, 'getDisplayValues', [id, 0]]),
    { blockTag }
  );

  const fnfts = Object.fromEntries(
    response.map((value, i) => [
      ids[i],
      defaultAbiCoder.decode(['uint', 'uint'], value[0])[0]
    ])
  );
  Object.keys(fnfts).forEach((element) => {
    if (fnfts[element].eq('0')) {
      delete fnfts[element];
    }
  });
  ids = Object.keys(fnfts);
  const response2 = await multicall(
    network,
    _provider,
    abi,
    ids.map((id: any) => [options.tokenVault, 'getFNFT', [id]]),
    { blockTag }
  );
  const completeFNFTs = Object.fromEntries(
    response2.map((value, i) => [
      ids[i],
      {
        allocPoints: fnfts[ids[i]],
        isRVST: value[0].asset.toLowerCase() == options.token.toLowerCase()
      }
    ])
  );
  let rewards = await multicall(
    network,
    _provider,
    abi2,
    [''].map(() => [options.staking, 'rewardsHandlerAddress', []]),
    { blockTag }
  );
  rewards = rewards[0][0];
  let allocLP = await multicall(
    network,
    _provider,
    abi3,
    [
      [rewards, 'totalLPAllocPoint', []],
      [rewards, 'totalBasicAllocPoint', []]
    ],
    { blockTag }
  );
  const allocToken = allocLP[1][0];
  allocLP = allocLP[0][0];

  //allocToken = allocToken[0][0];

  const finalResult = {};
  result.accounts.forEach((account) => {
    account.relBal.forEach((relBalEle) => {
      if (completeFNFTs.hasOwnProperty(relBalEle.token.identifier)) {
        const score = completeFNFTs[relBalEle.token.identifier].allocPoints
          .mul(PRECISION)
          .div(
            completeFNFTs[relBalEle.token.identifier].isRVST
              ? allocToken
              : allocLP
          );
        if (finalResult.hasOwnProperty(getAddress(account.id))) {
          finalResult[getAddress(account.id)].add(score);
        } else {
          finalResult[getAddress(account.id)] = score;
        }
      }
    });
  });
  const returnVals = {};
  Object.keys(finalResult).forEach((element) => {
    returnVals[element] = parseInt(finalResult[element].toString(), 10);
  });
  return returnVals;
}