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

     1  import ts, { factory, ObjectLiteralElementLike } from 'typescript';
     2  import { defaultCallName } from './caller';
     3  import { decodeName } from './decoder';
     4  import { encodeName } from './encoder';
     5  import {
     6    BoundsType,
     7    CallbackReturnType,
     8    createListener,
     9    createListenerForFunction,
    10    dataFromEvent,
    11    eventSigHash,
    12    topicsFromEvent,
    13  } from './events';
    14  import { errName, EventErrParameter, eventName, EventParameter, Provider } from './provider';
    15  import { ContractMethodsList, getRealType, inputOuputsToType, Signature } from './solidity';
    16  import {
    17    asConst,
    18    constObject,
    19    createCall,
    20    createCallbackType,
    21    createParameter,
    22    createPromiseOf,
    23    declareConstant,
    24    EqualsGreaterThanToken,
    25    ExportToken,
    26    MaybeUint8ArrayType,
    27    Method,
    28    prop,
    29    ReturnType,
    30    StringType,
    31    Undefined,
    32    UnknownType,
    33  } from './syntax';
    34  
    35  export const contractFunctionName = factory.createIdentifier('contract');
    36  export const contractTypeName = factory.createIdentifier('Contract');
    37  export const functionsGroupName = factory.createIdentifier('functions');
    38  export const listenersGroupName = factory.createIdentifier('listeners');
    39  const dataName = factory.createIdentifier('data');
    40  const clientName = factory.createIdentifier('client');
    41  const addressName = factory.createIdentifier('address');
    42  const listenerForName = factory.createIdentifier('listenerFor');
    43  const listenerName = factory.createIdentifier('listener');
    44  
    45  export function declareContractType(): ts.TypeAliasDeclaration {
    46    return factory.createTypeAliasDeclaration(
    47      undefined,
    48      [ExportToken],
    49      contractTypeName,
    50      undefined,
    51      factory.createTypeReferenceNode(ReturnType, [factory.createTypeQueryNode(contractFunctionName)]),
    52    );
    53  }
    54  
    55  export function generateContractObject(
    56    contractName: string,
    57    abi: ContractMethodsList,
    58    provider: Provider,
    59  ): ts.VariableStatement {
    60    const functions = abi.filter((a) => a.type === 'function');
    61    const events = abi.filter((a) => a.type === 'event');
    62  
    63    const functionObjectProperties = functions.length
    64      ? [
    65          createGroup(
    66            functionsGroupName,
    67            functions.flatMap((a) =>
    68              a.signatures.map((signature, index) => solidityFunction(a.name, a.signatures, index)),
    69            ),
    70          ),
    71        ]
    72      : [];
    73  
    74    const eventObjectProperties = events.length
    75      ? [
    76          createGroup(
    77            listenersGroupName,
    78            events.map((a) => solidityEvent(a.name, a.signatures[0], provider)),
    79          ),
    80          factory.createPropertyAssignment(listenerForName, createListenerForFunction(clientName, addressName)),
    81          factory.createPropertyAssignment(listenerName, createListener(clientName, addressName)),
    82        ]
    83      : [];
    84  
    85    return declareConstant(
    86      contractFunctionName,
    87      factory.createArrowFunction(
    88        undefined,
    89        undefined,
    90        [createParameter(clientName, provider.type()), createParameter(addressName, StringType)],
    91        undefined,
    92        EqualsGreaterThanToken,
    93        asConst(
    94          factory.createObjectLiteralExpression([
    95            factory.createPropertyAssignment('name', factory.createStringLiteral(contractName)),
    96            factory.createShorthandPropertyAssignment(addressName),
    97            ...functionObjectProperties,
    98            ...eventObjectProperties,
    99          ]),
   100        ),
   101      ),
   102      true,
   103    );
   104  }
   105  
   106  function solidityFunction(name: string, signatures: Signature[], index: number): ts.MethodDeclaration {
   107    const signature = signatures[index];
   108    const args = signature.inputs.map((input) => factory.createIdentifier(input.name));
   109    const encodeFunctionOrOverloadsArray = prop(createCall(encodeName, [clientName]), name);
   110    const callName = factory.createIdentifier('call');
   111  
   112    // Special case for overloads
   113    const hasOverloads = signatures.length > 1;
   114  
   115    const encoderFunction = hasOverloads
   116      ? factory.createElementAccessExpression(encodeFunctionOrOverloadsArray, index)
   117      : encodeFunctionOrOverloadsArray;
   118  
   119    const decoderFunctionOrOverloadsArray = prop(createCall(decodeName, [clientName, dataName]), name);
   120  
   121    const decoderFunction = hasOverloads
   122      ? factory.createElementAccessExpression(decoderFunctionOrOverloadsArray, index)
   123      : decoderFunctionOrOverloadsArray;
   124  
   125    const encode = declareConstant(dataName, createCall(encoderFunction, args));
   126  
   127    const returnType = inputOuputsToType(signature.outputs);
   128  
   129    const call = factory.createCallExpression(
   130      callName,
   131      [returnType],
   132      [
   133        clientName,
   134        addressName,
   135        dataName,
   136        signature.constant ? factory.createTrue() : factory.createFalse(),
   137        factory.createArrowFunction(
   138          undefined,
   139          undefined,
   140          [createParameter(dataName, MaybeUint8ArrayType)],
   141          undefined,
   142          undefined,
   143          factory.createBlock([factory.createReturnStatement(createCall(decoderFunction, []))], true),
   144        ),
   145      ],
   146    );
   147  
   148    const callParameter = createParameter(callName, undefined, defaultCallName);
   149  
   150    const params = signature.inputs.map((input) => createParameter(input.name, getRealType(input.type)));
   151    // Suffix overloads
   152    return new Method(index > 0 ? `${name}_${index}` : name)
   153      .parameters(params)
   154      .parameters(callParameter)
   155      .returns(createPromiseOf(returnType))
   156      .declaration([encode, factory.createReturnStatement(call)], true);
   157  }
   158  
   159  function solidityEvent(name: string, signature: Signature, provider: Provider): ts.MethodDeclaration {
   160    const callback = factory.createIdentifier('callback');
   161    const start = factory.createIdentifier('start');
   162    const end = factory.createIdentifier('end');
   163    // Receivers of LogEventParameter
   164    const data = dataFromEvent(eventName);
   165    const topics = topicsFromEvent(eventName);
   166    const decoderFunction = prop(createCall(decodeName, [clientName, data, topics]), name);
   167    return (
   168      new Method(name)
   169        .parameter(
   170          callback,
   171          createCallbackType(
   172            [EventErrParameter, createParameter(eventName, inputOuputsToType(signature.inputs), undefined, true)],
   173            CallbackReturnType,
   174          ),
   175        )
   176        .parameter(start, BoundsType, true)
   177        .parameter(end, BoundsType, true)
   178        // type may be EventStream, allow type assertion without polluting inteface
   179        .returns(UnknownType)
   180        .declaration([
   181          factory.createReturnStatement(
   182            provider.methods.listen.call(
   183              clientName,
   184              factory.createArrayLiteralExpression([factory.createStringLiteral(eventSigHash(name, signature.inputs))]),
   185              addressName,
   186  
   187              factory.createArrowFunction(
   188                undefined,
   189                undefined,
   190                [EventErrParameter, EventParameter],
   191                undefined,
   192                undefined,
   193                factory.createBlock([
   194                  factory.createIfStatement(errName, factory.createReturnStatement(createCall(callback, [errName]))),
   195                  factory.createReturnStatement(createCall(callback, [Undefined, createCall(decoderFunction)])),
   196                ]),
   197              ),
   198              start,
   199              end,
   200            ),
   201          ),
   202        ])
   203    );
   204  }
   205  
   206  function createGroup(name: ts.Identifier, elements: ObjectLiteralElementLike[]): ts.PropertyAssignment {
   207    return factory.createPropertyAssignment(name, constObject(elements));
   208  }