github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/js/src/solts/lib/solidity.ts (about)

     1  import { camelCase } from 'camel-case';
     2  import { Keccak } from 'sha3';
     3  import ts, { factory, TypeNode } from 'typescript';
     4  import { ABI } from '../../contracts/abi';
     5  import { asArray, asRefNode, asTuple, BooleanType, BufferType, NumberType, StringType, VoidType } from './syntax';
     6  
     7  export function sha3(str: string): string {
     8    const hash = new Keccak(256).update(str);
     9    return hash.digest('hex').toUpperCase();
    10  }
    11  
    12  export function nameFromABI(abi: ABI.Func | ABI.Event): string {
    13    if (abi.name.indexOf('(') !== -1) {
    14      return abi.name;
    15    }
    16    const typeName = (abi.inputs as (ABI.EventInput | ABI.FunctionIO)[]).map((i) => i.type).join(',');
    17    return abi.name + '(' + typeName + ')';
    18  }
    19  
    20  export function getSize(type: string): number {
    21    return parseInt(type.replace(/.*\[|\].*/gi, ''), 10);
    22  }
    23  
    24  export function getRealType(type: string): ts.TypeNode {
    25    if (/\[\]/i.test(type)) {
    26      return asArray(getRealType(type.replace(/\[\]/, '')));
    27    }
    28    if (/\[.*\]/i.test(type)) {
    29      return asTuple(getRealType(type.replace(/\[.*\]/, '')), getSize(type));
    30    } else if (/int/i.test(type)) {
    31      return NumberType;
    32    } else if (/bool/i.test(type)) {
    33      return BooleanType;
    34    } else if (/bytes/i.test(type)) {
    35      return asRefNode(BufferType);
    36    } else {
    37      return StringType;
    38    } // address, bytes
    39  }
    40  
    41  export function inputOuputsToType(ios?: InputOutput[]): TypeNode {
    42    if (!ios?.length) {
    43      return VoidType;
    44    }
    45    const named = ios.filter((out) => out !== undefined && out.name !== '');
    46    if (ios.length === named.length) {
    47      return factory.createTypeLiteralNode(
    48        ios.map(({ name, type }) => factory.createPropertySignature(undefined, name, undefined, getRealType(type))),
    49      );
    50    } else {
    51      return factory.createTupleTypeNode(ios.map(({ type }) => getRealType(type)));
    52    }
    53  }
    54  
    55  export type InputOutput = {
    56    name: string;
    57    type: string;
    58  };
    59  export type MethodType = 'function' | 'event';
    60  export type Signature = {
    61    hash: string;
    62    constant: boolean;
    63    inputs: Array<InputOutput>;
    64    outputs?: Array<InputOutput>;
    65  };
    66  export type Method = {
    67    name: string;
    68    type: MethodType;
    69    signatures: Array<Signature>;
    70  };
    71  export type ContractMethods = Map<string, Method>;
    72  export type ContractMethodsList = Array<{ name: string } & Method>;
    73  
    74  export function getContractMethods(abi: ABI.FunctionOrEvent[]): Method[] {
    75    // solidity allows duplicate function names
    76    const contractMethods = abi.reduce<ContractMethods>((signatures, abi) => {
    77      if (abi.name === '') {
    78        return signatures;
    79      }
    80      if (abi.type === 'function') {
    81        const method = signatures.get(abi.name) || {
    82          name: abi.name,
    83          type: 'function',
    84          signatures: [],
    85        };
    86  
    87        const signature = {
    88          hash: getFunctionSelector(abi),
    89          constant: abi.constant || false,
    90          inputs: getInputs(abi),
    91          outputs: abi.outputs?.map((abi) => {
    92            return { name: abi.name, type: abi.type };
    93          }),
    94        };
    95        method.signatures.push(signature);
    96        signatures.set(method.name, method);
    97      } else if (abi.type === 'event') {
    98        signatures.set(abi.name, {
    99          name: abi.name,
   100          type: 'event',
   101          signatures: [
   102            {
   103              hash: getEventSignature(abi),
   104              constant: false,
   105              inputs: getInputs(abi),
   106            },
   107          ],
   108        });
   109      }
   110      return signatures;
   111    }, new Map<string, Method>());
   112    return Array.from(contractMethods, ([name, method]) => {
   113      return { name: name, type: method.type, signatures: method.signatures };
   114    });
   115  }
   116  
   117  export function libraryName(link: string): string {
   118    return link.split(':').slice(-1)[0];
   119  }
   120  
   121  function getFunctionSelector(abi: ABI.Func): string {
   122    return sha3(nameFromABI(abi)).slice(0, 8);
   123  }
   124  
   125  function getEventSignature(abi: ABI.Event): string {
   126    return sha3(nameFromABI(abi));
   127  }
   128  
   129  function getInputs(abi: ABI.FunctionOrEvent): InputOutput[] {
   130    return (
   131      abi.inputs
   132        ?.filter((abi) => abi.name !== '')
   133        .map((abi) => {
   134          return { name: abi.name, type: abi.type };
   135        }) ?? []
   136    );
   137  }