@ethersproject/abi#FunctionFragment TypeScript Examples

The following examples show how to use @ethersproject/abi#FunctionFragment. 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: hooks.ts    From interface-v2 with GNU General Public License v3.0 6 votes vote down vote up
function toCallState(
  callResult: CallResult | undefined,
  contractInterface: Interface | undefined,
  fragment: FunctionFragment | undefined,
  latestBlockNumber: number | undefined,
): CallState {
  if (!callResult) return INVALID_CALL_STATE;
  const { valid, data, blockNumber } = callResult;
  if (!valid) return INVALID_CALL_STATE;
  if (valid && !blockNumber) return LOADING_CALL_STATE;
  if (!contractInterface || !fragment || !latestBlockNumber)
    return LOADING_CALL_STATE;
  const success = data && data.length > 2;
  const syncing = (blockNumber ?? 0) < latestBlockNumber;
  let result: Result | undefined = undefined;
  if (success && data) {
    try {
      result = contractInterface.decodeFunctionResult(fragment, data);
    } catch (error) {
      console.debug('Result data parsing failed', fragment, data);
      return {
        valid: true,
        loading: false,
        error: true,
        syncing,
        result,
      };
    }
  }
  return {
    valid: true,
    loading: false,
    syncing,
    result: result,
    error: !success,
  };
}
Example #2
Source File: utils.ts    From hardhat-deploy with MIT License 6 votes vote down vote up
export function mergeABIs(
  abis: any[][],
  options: {check: boolean; skipSupportsInterface: boolean}
): any[] {
  if (abis.length === 0) {
    return [];
  }
  const result: any[] = JSON.parse(JSON.stringify(abis[0]));

  for (let i = 1; i < abis.length; i++) {
    const abi = abis[i];
    for (const fragment of abi) {
      const newEthersFragment = Fragment.from(fragment);
      // TODO constructor special handling ?
      const foundSameSig = result.find((v) => {
        const existingEthersFragment = Fragment.from(v);
        if (v.type !== fragment.type) {
          return false;
        }
        if (!existingEthersFragment) {
          return v.name === fragment.name; // TODO fallback and receive hanlding
        }

        if (
          existingEthersFragment.type === 'constructor' ||
          newEthersFragment.type === 'constructor'
        ) {
          return existingEthersFragment.name === newEthersFragment.name;
        }

        if (newEthersFragment.type === 'function') {
          return (
            Interface.getSighash(existingEthersFragment as FunctionFragment) ===
            Interface.getSighash(newEthersFragment as FunctionFragment)
          );
        } else if (newEthersFragment.type === 'event') {
          return existingEthersFragment.format() === newEthersFragment.format();
        } else {
          return v.name === fragment.name; // TODO fallback and receive hanlding
        }
      });
      if (foundSameSig) {
        if (
          options.check &&
          !(
            options.skipSupportsInterface &&
            fragment.name === 'supportsInterface'
          )
        ) {
          if (fragment.type === 'function') {
            throw new Error(
              `function "${fragment.name}" will shadow "${foundSameSig.name}". Please update code to avoid conflict.`
            );
          }
        }
      } else {
        result.push(fragment);
      }
    }
  }

  return result;
}
Example #3
Source File: hooks.ts    From vvs-ui with GNU General Public License v3.0 6 votes vote down vote up
function toCallState(
  callResult: CallResult | undefined,
  contractInterface: Interface | undefined,
  fragment: FunctionFragment | undefined,
  latestBlockNumber: number | undefined,
): CallState {
  if (!callResult) return INVALID_CALL_STATE
  const { valid, data, blockNumber } = callResult
  if (!valid) return INVALID_CALL_STATE
  if (valid && !blockNumber) return LOADING_CALL_STATE
  if (!contractInterface || !fragment || !latestBlockNumber) return LOADING_CALL_STATE
  const success = data && data.length > 2
  const syncing = (blockNumber ?? 0) < latestBlockNumber
  let result: Result | undefined
  if (success && data) {
    try {
      result = contractInterface.decodeFunctionResult(fragment, data)
    } catch (error) {
      console.debug('Result data parsing failed', fragment, data)
      return {
        valid: true,
        loading: false,
        error: true,
        syncing,
        result,
      }
    }
  }
  return {
    valid: true,
    loading: false,
    syncing,
    result,
    error: !success,
  }
}
Example #4
Source File: hooks.ts    From luaswap-interface with GNU General Public License v3.0 6 votes vote down vote up
function toCallState(
  callResult: CallResult | undefined,
  contractInterface: Interface | undefined,
  fragment: FunctionFragment | undefined,
  latestBlockNumber: number | undefined
): CallState {
  if (!callResult) return INVALID_CALL_STATE
  const { valid, data, blockNumber } = callResult
  if (!valid) return INVALID_CALL_STATE
  if (valid && !blockNumber) return LOADING_CALL_STATE
  if (!contractInterface || !fragment || !latestBlockNumber) return LOADING_CALL_STATE
  const success = data && data.length > 2
  const syncing = (blockNumber ?? 0) < latestBlockNumber
  let result: Result | undefined = undefined
  if (success && data) {
    try {
      result = contractInterface.decodeFunctionResult(fragment, data)
    } catch (error) {
      console.debug('Result data parsing failed', fragment, data)
      return {
        valid: true,
        loading: false,
        error: true,
        syncing,
        result
      }
    }
  }
  return {
    valid: true,
    loading: false,
    syncing,
    result: result,
    error: !success
  }
}
Example #5
Source File: contract.ts    From solana-solidity.js with Apache License 2.0 6 votes vote down vote up
/** @internal */
    protected buildCall(fragment: FunctionFragment, returnResult: boolean): ContractFunction {
        return (...args: any[]) => {
            const options = args[args.length - 1];
            if (args.length > fragment.inputs.length && typeof options === 'object') {
                return this.call(fragment, returnResult, args.slice(0, fragment.inputs.length), options);
            } else {
                return this.call(fragment, returnResult, args);
            }
        };
    }
Example #6
Source File: transactions.ts    From snapshot-plugins with MIT License 6 votes vote down vote up
export async function decodeContractTransaction(
  network: string,
  transaction: ModuleTransaction,
  multiSendAddress: string
): Promise<ContractInteractionModuleTransaction> {
  const decode = (abi: string | FunctionFragment[]) => {
    const contractInterface = new InterfaceDecoder(abi);
    const method = contractInterface.getMethodFragment(transaction.data);
    contractInterface.decodeFunction(transaction.data, method); // Validate data can be decode by method.
    return contractInteractionToModuleTransaction(
      {
        data: transaction.data,
        nonce: 0,
        to: transaction.to,
        value: transaction.value,
        method
      },
      multiSendAddress
    );
  };

  const contractAbi = await getContractABI(network, transaction.to);
  if (contractAbi) return decode(contractAbi);

  const methodSignature = getMethodSignature(transaction.data);
  if (methodSignature) {
    const textSignatures = await fetchTextSignatures(methodSignature);
    for (const signature of textSignatures) {
      try {
        return decode([FunctionFragment.fromString(signature)]);
      } catch (e) {
        console.warn('invalid abi for transaction');
      }
    }
  }

  throw new Error(`we were not able to decode this transaction`);
}
Example #7
Source File: decoder.ts    From snapshot-plugins with MIT License 6 votes vote down vote up
public decodeFunction(
    data: string,
    fragmentOrName?: string | Fragment | JsonFragment
  ) {
    const fragment = this.getMethodFragment(data, fragmentOrName);
    if (!FunctionFragment.isFunctionFragment(fragment)) {
      throw new Error(
        `could not resolved to a function fragment fragmentOrName: ${fragmentOrName}`
      );
    }
    const functionFragment = FunctionFragment.fromObject(fragment);
    const decodedValues = this.decodeFunctionData(functionFragment.name, data);

    return functionFragment.inputs.reduce((acc, parameter, index) => {
      const value = decodedValues[index];
      const formattedValue = this.formatParameter(parameter, value);
      acc.push(formattedValue);
      if (parameter.name) {
        acc[parameter.name] = formattedValue;
      }
      return acc;
    }, [] as string[]);
  }
Example #8
Source File: abi.ts    From snapshot-plugins with MIT License 6 votes vote down vote up
export function getContractTransactionData(
  abi: string,
  method: FunctionFragment,
  values: string[]
) {
  const contractInterface = new Interface(abi);
  const parameterValues = method.inputs.map(extractMethodArgs(values));
  return contractInterface.encodeFunctionData(method, parameterValues);
}
Example #9
Source File: abi.ts    From snapshot-plugins with MIT License 6 votes vote down vote up
export function getABIWriteFunctions(abi: Fragment[]) {
  const abiInterface = new Interface(abi);
  return (
    abiInterface.fragments
      // Return only contract's functions
      .filter(FunctionFragment.isFunctionFragment)
      .map(FunctionFragment.fromObject)
      // Return only write functions
      .filter(isWriteFunction)
      // Sort by name
      .sort((a, b) => (a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1))
  );
}
Example #10
Source File: hooks.ts    From goose-frontend-amm with GNU General Public License v3.0 6 votes vote down vote up
function toCallState(
  callResult: CallResult | undefined,
  contractInterface: Interface | undefined,
  fragment: FunctionFragment | undefined,
  latestBlockNumber: number | undefined
): CallState {
  if (!callResult) return INVALID_CALL_STATE
  const { valid, data, blockNumber } = callResult
  if (!valid) return INVALID_CALL_STATE
  if (valid && !blockNumber) return LOADING_CALL_STATE
  if (!contractInterface || !fragment || !latestBlockNumber) return LOADING_CALL_STATE
  const success = data && data.length > 2
  const syncing = (blockNumber ?? 0) < latestBlockNumber
  let result: Result | undefined
  if (success && data) {
    try {
      result = contractInterface.decodeFunctionResult(fragment, data)
    } catch (error) {
      console.error('Result data parsing failed', fragment, data)
      return {
        valid: true,
        loading: false,
        error: true,
        syncing,
        result,
      }
    }
  }
  return {
    valid: true,
    loading: false,
    syncing,
    result,
    error: !success,
  }
}
Example #11
Source File: hooks.ts    From glide-frontend with GNU General Public License v3.0 6 votes vote down vote up
function toCallState(
  callResult: CallResult | undefined,
  contractInterface: Interface | undefined,
  fragment: FunctionFragment | undefined,
  latestBlockNumber: number | undefined,
): CallState {
  if (!callResult) return INVALID_CALL_STATE
  const { valid, data, blockNumber } = callResult
  if (!valid) return INVALID_CALL_STATE
  if (valid && !blockNumber) return LOADING_CALL_STATE
  if (!contractInterface || !fragment || !latestBlockNumber) return LOADING_CALL_STATE
  const success = data && data.length > 2
  const syncing = (blockNumber ?? 0) < latestBlockNumber
  let result: Result | undefined
  if (success && data) {
    try {
      result = contractInterface.decodeFunctionResult(fragment, data)
    } catch (error) {
      console.debug('Result data parsing failed', fragment, data)
      return {
        valid: true,
        loading: false,
        error: true,
        syncing,
        result,
      }
    }
  }
  return {
    valid: true,
    loading: false,
    syncing,
    result,
    error: !success,
  }
}
Example #12
Source File: hooks.ts    From limit-orders-lib with GNU General Public License v3.0 6 votes vote down vote up
function toCallState(
  callResult: CallResult | undefined,
  contractInterface: Interface | undefined,
  fragment: FunctionFragment | undefined,
  latestBlockNumber: number | undefined
): CallState {
  if (!callResult) return INVALID_CALL_STATE;
  const { valid, data, blockNumber } = callResult;
  if (!valid) return INVALID_CALL_STATE;
  if (valid && !blockNumber) return LOADING_CALL_STATE;
  if (!contractInterface || !fragment || !latestBlockNumber)
    return LOADING_CALL_STATE;
  const success = data && data.length > 2;
  const syncing = (blockNumber ?? 0) < latestBlockNumber;
  let result: Result | undefined = undefined;
  if (success && data) {
    try {
      result = contractInterface.decodeFunctionResult(fragment, data);
    } catch (error) {
      console.debug("Result data parsing failed", fragment, data);
      return {
        valid: true,
        loading: false,
        error: true,
        syncing,
        result,
      };
    }
  }
  return {
    valid: true,
    loading: false,
    syncing,
    result: result,
    error: !success,
  };
}
Example #13
Source File: hooks.ts    From cheeseswap-interface with GNU General Public License v3.0 6 votes vote down vote up
function toCallState(
  callResult: CallResult | undefined,
  contractInterface: Interface | undefined,
  fragment: FunctionFragment | undefined,
  latestBlockNumber: number | undefined
): CallState {
  if (!callResult) return INVALID_CALL_STATE
  const { valid, data, blockNumber } = callResult
  if (!valid) return INVALID_CALL_STATE
  if (valid && !blockNumber) return LOADING_CALL_STATE
  if (!contractInterface || !fragment || !latestBlockNumber) return LOADING_CALL_STATE
  const success = data && data.length > 2
  const syncing = (blockNumber ?? 0) < latestBlockNumber
  let result: Result | undefined = undefined
  if (success && data) {
    try {
      result = contractInterface.decodeFunctionResult(fragment, data)
    } catch (error) {
      console.debug('Result data parsing failed', fragment, data)
      return {
        valid: true,
        loading: false,
        error: true,
        syncing,
        result
      }
    }
  }
  return {
    valid: true,
    loading: false,
    syncing,
    result: result,
    error: !success
  }
}
Example #14
Source File: contract.ts    From ethers-multicall with MIT License 6 votes vote down vote up
constructor(address: string, abi: JsonFragment[] | string[] | Fragment[]) {
    this._address = address;

    this._abi = toFragment(abi);

    this._functions = this._abi.filter(x => x.type === 'function').map(x => FunctionFragment.from(x));
    const callFunctions = this._functions.filter(x => x.stateMutability === 'pure' || x.stateMutability === 'view');

    for (const callFunction of callFunctions) {
      const { name } = callFunction;
      const getCall = makeCallFunction(this, name);
      if (!this[name]) {
        defineReadOnly(this, name, getCall);
      }
    }
  }
Example #15
Source File: hooks.ts    From sybil-interface with GNU General Public License v3.0 6 votes vote down vote up
function toCallState(
  callResult: CallResult | undefined,
  contractInterface: Interface | undefined,
  fragment: FunctionFragment | undefined,
  latestBlockNumber: number | undefined
): CallState {
  if (!callResult) return INVALID_CALL_STATE
  const { valid, data, blockNumber } = callResult
  if (!valid) return INVALID_CALL_STATE
  if (valid && !blockNumber) return LOADING_CALL_STATE
  if (!contractInterface || !fragment || !latestBlockNumber) return LOADING_CALL_STATE
  const success = data && data.length > 2
  const syncing = (blockNumber ?? 0) < latestBlockNumber
  let result: Result | undefined = undefined
  if (success && data) {
    try {
      result = contractInterface.decodeFunctionResult(fragment, data)
    } catch (error) {
      console.debug('Result data parsing failed', fragment, data)
      return {
        valid: true,
        loading: false,
        error: true,
        syncing,
        result,
      }
    }
  }
  return {
    valid: true,
    loading: false,
    syncing,
    result: result,
    error: !success,
  }
}
Example #16
Source File: AbiParser.ts    From useDApp with MIT License 6 votes vote down vote up
function makeCallParser(coder: Interface, fragment: FunctionFragment): CallParser {
  return {
    name: fragment.name,
    parseCallData(data: string) {
      try {
        const decoded = coder.decodeFunctionData(fragment, data)
        return fragment.inputs.map((input, i) => parseDecoded(input, decoded[i], i))
      } catch {
        return parseUnknownCallData(data)
      }
    },
    parseCallResult(data: string) {
      try {
        if (fragment.outputs) {
          const decoded = coder.decodeFunctionResult(fragment, data)
          const items = fragment.outputs.map((input, i) => parseDecoded(input, decoded[i], i))
          if (items.length === 1) {
            return items[0]
          } else {
            return { type: 'tuple', name: '#0', value: items }
          }
        } else {
          return parseUnknownCallResult(data)
        }
      } catch {
        return parseUnknownCallResult(data)
      }
    },
  }
}
Example #17
Source File: hooks.ts    From cuiswap with GNU General Public License v3.0 6 votes vote down vote up
function toCallState(
  callResult: CallResult | undefined,
  contractInterface: Interface | undefined,
  fragment: FunctionFragment | undefined,
  latestBlockNumber: number | undefined
): CallState {
  if (!callResult) return INVALID_CALL_STATE
  const { valid, data, blockNumber } = callResult
  if (!valid) return INVALID_CALL_STATE
  if (valid && !blockNumber) return LOADING_CALL_STATE
  if (!contractInterface || !fragment || !latestBlockNumber) return LOADING_CALL_STATE
  const success = data && data.length > 2
  const syncing = (blockNumber ?? 0) < latestBlockNumber
  let result: Result | undefined = undefined
  if (success && data) {
    try {
      result = contractInterface.decodeFunctionResult(fragment, data)
    } catch (error) {
      console.debug('Result data parsing failed', fragment, data)
      return {
        valid: true,
        loading: false,
        error: true,
        syncing,
        result
      }
    }
  }
  return {
    valid: true,
    loading: false,
    syncing,
    result: result,
    error: !success
  }
}
Example #18
Source File: abi.ts    From snapshot-plugins with MIT License 5 votes vote down vote up
export function parseMethodToABI(method: FunctionFragment) {
  return [method.format(FormatTypes.full)];
}
Example #19
Source File: abi.ts    From snapshot-plugins with MIT License 5 votes vote down vote up
export function isWriteFunction(method: FunctionFragment) {
  if (!method.stateMutability) return true;
  return !['view', 'pure'].includes(method.stateMutability);
}
Example #20
Source File: contract.ts    From ethers-multicall with MIT License 5 votes vote down vote up
private _functions: FunctionFragment[];
Example #21
Source File: contract.ts    From solana-solidity.js with Apache License 2.0 4 votes vote down vote up
/** @internal */
    protected async call<T extends boolean>(
        fragment: FunctionFragment,
        returnResult: T,
        args: readonly any[],
        options?: ContractCallOptions
    ): Promise<T extends true ? any : ContractFunctionResult> {
        const payer = options?.payer || this.payer;
        if (!payer) throw new MissingPayerAccountError();

        const {
            accounts = [],
            writableAccounts = [],
            programDerivedAddresses = [],
            signers = [],
            sender = payer.publicKey,
            value = 0,
            simulate = false,
            ed25519sigs = [],
            confirmOptions = {
                commitment: 'confirmed',
                skipPreflight: false,
                preflightCommitment: 'processed',
            },
        } = options ?? {};

        const seeds = programDerivedAddresses.map(({ seed }) => seed);
        const input = this.interface.encodeFunctionData(fragment, args);

        const data = Buffer.concat([
            // storage account where state for this contract will be stored
            this.storage.toBuffer(),
            // msg.sender for this transaction
            sender.toBuffer(),
            // lamports to send to payable constructor
            encodeU64(BigInt(value)),
            // hash of contract name, 0 for function calls
            Buffer.from('00000000', 'hex'),
            // PDA seeds
            encodeSeeds(seeds),
            // eth abi encoded constructor arguments
            Buffer.from(input.replace('0x', ''), 'hex'),
        ]);

        const keys = [
            ...programDerivedAddresses.map(({ address }) => ({
                pubkey: address,
                isSigner: false,
                isWritable: true,
            })),
            {
                pubkey: this.storage,
                isSigner: false,
                isWritable: true,
            },
            {
                pubkey: SYSVAR_CLOCK_PUBKEY,
                isSigner: false,
                isWritable: false,
            },
            {
                pubkey: PublicKey.default,
                isSigner: false,
                isWritable: false,
            },
            ...accounts.map((pubkey) => ({
                pubkey,
                isSigner: false,
                isWritable: false,
            })),
            ...writableAccounts.map((pubkey) => ({
                pubkey,
                isSigner: false,
                isWritable: true,
            })),
            ...signers.map((signer) => ({
                pubkey: signer.publicKey,
                isSigner: true,
                isWritable: true,
            })),
        ];

        const transaction = new Transaction();

        if (ed25519sigs.length > 0) {
            keys.push({ pubkey: SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });

            ed25519sigs.forEach(({ publicKey, message, signature }, index) => {
                transaction.add(Ed25519Program.createInstructionWithPublicKey({
                    instructionIndex: index,
                    publicKey: publicKey.toBuffer(),
                    message,
                    signature,
                }));
            });
        }

        transaction.add(
            new TransactionInstruction({
                keys,
                programId: this.program,
                data,
            })
        );

        // If the function is read-only, simulate the transaction to get the result
        const { logs, encoded, computeUnitsUsed } =
            simulate || fragment.stateMutability === 'view' || fragment.stateMutability === 'pure'
                ? await simulateTransactionWithLogs(this.connection, transaction, [payer, ...signers])
                : await sendAndConfirmTransactionWithLogs(
                    this.connection,
                    transaction,
                    [payer, ...signers],
                    confirmOptions
                );

        const events = this.parseLogsEvents(logs);

        const length = fragment.outputs?.length;
        let result: Result | null = null;

        if (length) {
            if (!encoded) throw new MissingReturnDataError();

            if (length == 1) {
                [result] = this.interface.decodeFunctionResult(fragment, encoded);
            } else {
                result = this.interface.decodeFunctionResult(fragment, encoded);
            }
        }

        if (returnResult === true)
            return result as any;
        return { result, logs, events, computeUnitsUsed };
    }