* Instantiate a contract from a compiled CashScript artifact. * * @param artifact - The compiled contract artifact produced by `cashc`. * @param constructorArgs - Constructor arguments in the order defined in the contract source. * @param options - Contract options including the network
(
public artifact: TArtifact,
constructorArgs: TResolved['constructorInputs'],
private options: ContractOptions<TContractType>,
)
| 119 | * compiler version, or if the number or types of constructor arguments does not match the artifact. |
| 120 | */ |
| 121 | constructor( |
| 122 | public artifact: TArtifact, |
| 123 | constructorArgs: TResolved['constructorInputs'], |
| 124 | private options: ContractOptions<TContractType>, |
| 125 | ) { |
| 126 | super(); |
| 127 | this.provider = this.options.provider; |
| 128 | |
| 129 | // Note: technically, it is possible to instantiate a Contract like this, which breaks the type safety, |
| 130 | // but it seems unreasonable for anyone to do this |
| 131 | // new Contract<any, any, 'p2s'>(artifact), [], { provider }) |
| 132 | this.contractType = this.options.contractType ?? 'p2sh32' as TContractType; |
| 133 | |
| 134 | const expectedProperties = ['abi', 'bytecode', 'constructorInputs', 'contractName', 'compiler']; |
| 135 | if (!expectedProperties.every((property) => property in artifact)) { |
| 136 | throw new Error('Invalid or incomplete artifact provided'); |
| 137 | } |
| 138 | |
| 139 | if (!semver.satisfies(artifact.compiler.version, '>=0.7.0', { includePrerelease: true })) { |
| 140 | throw new Error(`Artifact compiled with unsupported compiler version: ${artifact.compiler.version}, required >=0.7.0`); |
| 141 | } |
| 142 | |
| 143 | if (artifact.constructorInputs.length !== constructorArgs.length) { |
| 144 | throw new Error(`Incorrect number of arguments passed to ${artifact.contractName} constructor. Expected ${artifact.constructorInputs.length} arguments (${artifact.constructorInputs.map((input) => input.type)}) but got ${constructorArgs.length}`); |
| 145 | } |
| 146 | |
| 147 | // Encode arguments (this also performs type checking) |
| 148 | this.encodedConstructorArgs = encodeConstructorArguments(artifact, constructorArgs); |
| 149 | |
| 150 | // Populate the 'unlock' object with the contract's functions |
| 151 | // (with a special case for single function, which has no "function selector") |
| 152 | this.unlock = {}; |
| 153 | if (artifact.abi.length === 1) { |
| 154 | const f = artifact.abi[0]; |
| 155 | // @ts-ignore TODO: see if we can use generics to make TypeScript happy |
| 156 | this.unlock[f.name] = this.createUnlocker(f); |
| 157 | } else { |
| 158 | artifact.abi.forEach((f, i) => { |
| 159 | // @ts-ignore TODO: see if we can use generics to make TypeScript happy |
| 160 | this.unlock[f.name] = this.createUnlocker(f, i); |
| 161 | }); |
| 162 | } |
| 163 | |
| 164 | const contractBytecodeScript = generateContractBytecodeScript( |
| 165 | asmToScript(this.artifact.bytecode), this.encodedConstructorArgs, |
| 166 | ); |
| 167 | |
| 168 | if (this.contractType !== 'p2s') { |
| 169 | this.address = scriptToAddress(contractBytecodeScript, this.provider.network, this.contractType, false); |
| 170 | this.tokenAddress = scriptToAddress(contractBytecodeScript, this.provider.network, this.contractType, true); |
| 171 | } |
| 172 | |
| 173 | this.name = artifact.contractName; |
| 174 | this.bytecode = binToHex(scriptToBytecode(contractBytecodeScript)); |
| 175 | this.lockingBytecode = this.contractType === 'p2s' ? this.bytecode : binToHex(addressToLockScript(this.address)); |
| 176 | this.bytesize = calculateBytesize(contractBytecodeScript); |
| 177 | this.opcount = countOpcodes(contractBytecodeScript); |
| 178 | } |
nothing calls this directly
no test coverage detected