github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/js/src/solts/lib/provider.ts (about) 1 import ts, { factory } from 'typescript'; 2 import { BoundsType, CallbackReturnType } from './events'; 3 import { 4 AddressType, 5 ColonToken, 6 ContractCodecType, 7 createCall, 8 createCallbackType, 9 createParameter, 10 createPromiseOf, 11 declareConstant, 12 ErrorType, 13 EventType, 14 ExportToken, 15 MaybeUint8ArrayType, 16 Method, 17 QuestionToken, 18 StringType, 19 Uint8ArrayType, 20 Undefined, 21 UnknownType, 22 } from './syntax'; 23 24 export const errName = factory.createIdentifier('err'); 25 export const contractCodecName = factory.createIdentifier('codec'); 26 export const eventName = factory.createIdentifier('event'); 27 28 export const EventErrParameter = createParameter(errName, ErrorType, undefined, true); 29 export const EventParameter = createParameter(eventName, EventType, undefined, true); 30 31 class Deploy extends Method { 32 private abiName = factory.createIdentifier('abi'); 33 private codeHashName = factory.createIdentifier('codeHash'); 34 35 params = [ 36 createParameter('data', factory.createUnionTypeNode([StringType, Uint8ArrayType])), 37 createParameter( 38 'contractMeta', 39 factory.createArrayTypeNode( 40 factory.createTypeLiteralNode([ 41 factory.createPropertySignature(undefined, this.abiName, undefined, StringType), 42 factory.createPropertySignature(undefined, this.codeHashName, undefined, Uint8ArrayType), 43 ]), 44 ), 45 undefined, 46 true, 47 ), 48 ]; 49 ret = createPromiseOf(AddressType); 50 51 constructor() { 52 super('deploy'); 53 } 54 55 call( 56 exp: ts.Expression, 57 data: ts.Expression, 58 withContractMeta: ts.Expression, 59 contractMeta: { abi: ts.Expression; codeHash: ts.Expression }[], 60 ): ts.CallExpression { 61 const contractMetaLiteral = factory.createArrayLiteralExpression( 62 contractMeta.map(({ abi, codeHash }) => 63 factory.createObjectLiteralExpression([ 64 factory.createPropertyAssignment(this.abiName, abi), 65 factory.createPropertyAssignment(this.codeHashName, codeHash), 66 ]), 67 ), 68 ); 69 return createCall(factory.createPropertyAccessExpression(exp, this.id), [ 70 data, 71 // TODO: Contracts that may create contracts need to be deployed with contract meta for all contracts they create 72 // unfortunately we have no good way to determine from solc output which contracts a contract may create, so 73 // short of pushing all contract meta to every contract in a family of contracts we cannot safely deploy with meta 74 // in the general case this Burrow throws on creating a new contract if a) the parent has meta, and b) the child 75 // meta cannot be found. The solution is to delocalise the contract storage from the parent contract and have 76 // a global registry of metadata to query against when creating a contract 77 factory.createConditionalExpression(withContractMeta, QuestionToken, contractMetaLiteral, ColonToken, Undefined), 78 ]); 79 } 80 } 81 82 class Call extends Method { 83 params = [ 84 createParameter('data', factory.createUnionTypeNode([StringType, Uint8ArrayType])), 85 createParameter('address', StringType), 86 ]; 87 ret = createPromiseOf(MaybeUint8ArrayType); 88 89 constructor() { 90 super('call'); 91 } 92 93 call(exp: ts.Expression, data: ts.Expression, address: ts.Expression) { 94 return createCall(factory.createPropertyAccessExpression(exp, this.id), [data, address]); 95 } 96 } 97 98 class CallSim extends Method { 99 params = [ 100 createParameter('data', factory.createUnionTypeNode([StringType, Uint8ArrayType])), 101 createParameter('address', StringType), 102 ]; 103 ret = createPromiseOf(MaybeUint8ArrayType); 104 105 constructor() { 106 super('callSim'); 107 } 108 109 call(exp: ts.Expression, data: ts.Expression, address: ts.Expression) { 110 return createCall(factory.createPropertyAccessExpression(exp, this.id), [data, address]); 111 } 112 } 113 114 class Listen extends Method { 115 params = [ 116 createParameter('signatures', factory.createArrayTypeNode(StringType)), 117 createParameter('address', StringType), 118 createParameter('callback', createCallbackType([EventErrParameter, EventParameter], CallbackReturnType)), 119 createParameter('start', BoundsType, undefined, true), 120 createParameter('end', BoundsType, undefined, true), 121 ]; 122 ret = UnknownType; 123 124 constructor() { 125 super('listen'); 126 } 127 128 call( 129 exp: ts.Expression, 130 sig: ts.Expression, 131 addr: ts.Expression, 132 callback: ts.Expression, 133 start: ts.Expression, 134 end: ts.Expression, 135 ) { 136 return createCall(factory.createPropertyAccessExpression(exp, this.id), [sig, addr, callback, start, end]); 137 } 138 } 139 140 class ContractCodec extends Method { 141 params = [createParameter('contractABI', StringType)]; 142 ret = ContractCodecType; 143 144 constructor() { 145 super('contractCodec'); 146 } 147 148 call(provider: ts.Expression, contractABI: ts.Expression) { 149 return createCall(factory.createPropertyAccessExpression(provider, this.id), [contractABI]); 150 } 151 } 152 153 export class Provider { 154 private name = factory.createIdentifier('Provider'); 155 156 methods = { 157 deploy: new Deploy(), 158 call: new Call(), 159 callSim: new CallSim(), 160 listen: new Listen(), 161 contractCodec: new ContractCodec(), 162 }; 163 164 createInterface(extern?: boolean): ts.InterfaceDeclaration { 165 return factory.createInterfaceDeclaration( 166 undefined, 167 extern ? [ExportToken] : undefined, 168 this.name, 169 undefined, 170 undefined, 171 [ 172 this.methods.deploy.signature(), 173 this.methods.call.signature(), 174 this.methods.callSim.signature(), 175 this.methods.listen.signature(), 176 this.methods.contractCodec.signature(), 177 ], 178 ); 179 } 180 181 declareContractCodec(client: ts.Identifier, abiName: ts.Identifier): ts.VariableStatement { 182 return declareConstant(contractCodecName, this.methods.contractCodec.call(client, abiName)); 183 } 184 185 type(): ts.TypeReferenceNode { 186 return factory.createTypeReferenceNode(this.name); 187 } 188 } 189 190 const encodeDeploy = factory.createIdentifier('encodeDeploy'); 191 const encodeFunctionData = factory.createIdentifier('encodeFunctionData'); 192 const decodeFunctionResult = factory.createIdentifier('decodeFunctionResult '); 193 const decodeEventLog = factory.createIdentifier('decodeEventLog '); 194 195 export function callEncodeDeploy(args: ts.Expression[]): ts.CallExpression { 196 return createCall(factory.createPropertyAccessExpression(contractCodecName, encodeDeploy), [...args]); 197 } 198 199 export function callEncodeFunctionData(signature: string, args: ts.Expression[]): ts.CallExpression { 200 return createCall(factory.createPropertyAccessExpression(contractCodecName, encodeFunctionData), [ 201 factory.createStringLiteral(signature), 202 ...args, 203 ]); 204 } 205 206 export function callDecodeFunctionResult(signature: string, data: ts.Expression): ts.CallExpression { 207 return createCall(factory.createPropertyAccessExpression(contractCodecName, decodeFunctionResult), [ 208 factory.createStringLiteral(signature), 209 data, 210 ]); 211 } 212 213 export function callDecodeEventLog(signature: string, data: ts.Expression, topics: ts.Expression): ts.CallExpression { 214 return createCall(factory.createPropertyAccessExpression(contractCodecName, decodeEventLog), [ 215 factory.createStringLiteral(signature), 216 data, 217 topics, 218 ]); 219 }