Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit 5797eca

Browse files
authored
Merge pull request #5777 from trufflesuite/make-easy
Add `encodeCreation()` method to Encoder
2 parents 28d00b8 + b115d52 commit 5797eca

File tree

2 files changed

+110
-46
lines changed

2 files changed

+110
-46
lines changed

packages/encoder/lib/encoders.ts

Lines changed: 93 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,40 @@ export class ContractEncoder {
12951295
);
12961296
}
12971297

1298+
/**
1299+
* **This method is asynchronous.**
1300+
*
1301+
* This method is similar to [[encodeTransaction]], except that instead of
1302+
* encoding a function transaction, it encodes a creation transaction.
1303+
*
1304+
* Because this method does not perform overload resolution, it only returns
1305+
* the resulting transaction options (including the encoded `data`), and does
1306+
* not bother returning the ABI used (as this was user-supplied.)
1307+
*
1308+
* If the `allowOptions` flag is set in the `options` argument, the input may
1309+
* contain an additional transaction options argument after the other
1310+
* arguments. Any non-`data` options not specified in such a transaction
1311+
* options argument will be simply omitted; it you want some options to have
1312+
* defaults, it is up to the you to set these options as appropriate
1313+
* afterwards.
1314+
*
1315+
* If the transaction options parameter has a `data` or a `to` option,
1316+
* these option will be recognized but ignored.
1317+
*
1318+
* See [[encodeTransaction]] for documentation of the inputs.
1319+
*/
1320+
public async encodeCreation(
1321+
inputs: unknown[],
1322+
options: Types.ResolveOptions = {}
1323+
): Promise<Codec.Options> {
1324+
const method = this.getConstructorMethod();
1325+
return await this.projectEncoder.encodeTxNoResolution(
1326+
method,
1327+
inputs,
1328+
options
1329+
);
1330+
}
1331+
12981332
/**
12991333
* **This method is asynchronous.**
13001334
*
@@ -1350,36 +1384,12 @@ export class ContractEncoder {
13501384
abi: Abi.FunctionEntry | Abi.ConstructorEntry
13511385
): Codec.Wrap.Method {
13521386
abi = <Abi.FunctionEntry | Abi.ConstructorEntry>Abi.normalizeEntry(abi); //just to be absolutely certain!
1353-
const allocations = this.projectEncoder.getAllocations();
13541387
debug("got allocations");
13551388
switch (abi.type) {
1356-
case "constructor": {
1357-
debug("constructor binary: %s", this.constructorBinary);
1358-
//first check that we have constructor binary, and that it's all linked
1359-
if (!this.constructorBinary || this.constructorBinary === "0x") {
1360-
throw new NoBytecodeError(this.contract.contractName);
1361-
} else if (!this.constructorBinary.match(/^0x([0-9a-fA-F]{2})+$/)) {
1362-
throw new UnlinkedContractError(
1363-
this.contract.contractName,
1364-
this.artifact ? this.artifact.bytecode : undefined
1365-
);
1366-
}
1367-
//otherwise, we're good to go!
1368-
const allocation =
1369-
//@ts-ignore: We set this up and checked this earlier
1370-
allocations.calldata.constructorAllocations[
1371-
<string>this.constructorContextHash
1372-
].input;
1373-
const inputs = allocation.arguments.map(
1374-
input => ({ type: input.type, name: input.name || undefined }) //convert "" to undefined
1375-
);
1376-
return {
1377-
selector: this.constructorBinary,
1378-
inputs,
1379-
abi
1380-
};
1381-
}
1382-
case "function": {
1389+
case "constructor":
1390+
return this.getConstructorMethod(abi);
1391+
case "function":
1392+
const allocations = this.projectEncoder.getAllocations();
13831393
const selector: string = Codec.AbiData.Utils.abiSelector(abi);
13841394
const allocation: Codec.AbiData.Allocate.CalldataAllocation = this
13851395
.deployedContextHash
@@ -1397,9 +1407,50 @@ export class ContractEncoder {
13971407
inputs,
13981408
abi
13991409
};
1400-
}
14011410
}
14021411
}
1412+
1413+
//if you already know the ABI, you can pass it in for convenience.
1414+
//if you don't, we'll find it for you.
1415+
private getConstructorMethod(abi?: Abi.ConstructorEntry): Codec.Wrap.Method {
1416+
if (!abi) {
1417+
abi = this.getConstructorAbi();
1418+
}
1419+
const allocations = this.projectEncoder.getAllocations();
1420+
debug("constructor binary: %s", this.constructorBinary);
1421+
//first check that we have constructor binary, and that it's all linked
1422+
if (!this.constructorBinary || this.constructorBinary === "0x") {
1423+
throw new NoBytecodeError(this.contract.contractName);
1424+
} else if (!this.constructorBinary.match(/^0x([0-9a-fA-F]{2})+$/)) {
1425+
throw new UnlinkedContractError(
1426+
this.contract.contractName,
1427+
this.artifact ? this.artifact.bytecode : undefined
1428+
);
1429+
}
1430+
//otherwise, we're good to go!
1431+
const allocation =
1432+
//@ts-ignore: We set this up and checked this earlier
1433+
allocations.calldata.constructorAllocations[
1434+
<string>this.constructorContextHash
1435+
].input;
1436+
const inputs = allocation.arguments.map(
1437+
input => ({ type: input.type, name: input.name || undefined }) //convert "" to undefined
1438+
);
1439+
return {
1440+
selector: this.constructorBinary,
1441+
inputs,
1442+
abi
1443+
};
1444+
}
1445+
1446+
private getConstructorAbi(): Abi.ConstructorEntry {
1447+
return (
1448+
this.abi.find(
1449+
(abi: Abi.Entry): abi is Abi.ConstructorEntry =>
1450+
abi.type === "constructor"
1451+
) || Codec.AbiData.Utils.DEFAULT_CONSTRUCTOR_ABI
1452+
);
1453+
}
14031454
}
14041455

14051456
/**
@@ -1546,4 +1597,17 @@ export class ContractInstanceEncoder {
15461597
encoded.tx.to = this.toAddress;
15471598
return encoded;
15481599
}
1600+
1601+
/**
1602+
* **This method is asynchronous.**
1603+
*
1604+
* This method functions identically to [[ContractEncoder.encodeCreation]].
1605+
* The particular contract instance is ignored, only its class is used.
1606+
*/
1607+
public async encodeCreation(
1608+
inputs: unknown[],
1609+
options: Types.ResolveOptions = {}
1610+
): Promise<Codec.Options> {
1611+
return await this.contractEncoder.encodeCreation(inputs, options);
1612+
}
15491613
}

packages/encoder/test/constructor.test.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import * as Encoder from "..";
99
import * as Codec from "@truffle/codec";
1010
import { Shims } from "@truffle/compile-common";
1111
import type { ContractObject as Artifact } from "@truffle/contract-schema/spec";
12-
import * as Abi from "@truffle/abi-utils";
1312
import Ganache from "ganache";
1413
import type { Provider } from "web3/providers";
1514

@@ -60,29 +59,30 @@ beforeAll(async () => {
6059

6160
describe("Encoding", () => {
6261
describe("Constructors", () => {
63-
let encoder: Encoder.ContractEncoder;
64-
let abi: Abi.ConstructorEntry;
65-
let bytecode: string;
66-
67-
beforeAll(async () => {
68-
encoder = await Encoder.forArtifact(artifacts.TestContract, {
62+
it("Encodes constructors", async () => {
63+
const artifact = artifacts.TestContract;
64+
const encoder = await Encoder.forArtifact(artifact, {
6965
projectInfo: { compilations }
7066
});
71-
abi = <Abi.ConstructorEntry>(
72-
Abi.normalize(artifacts.TestContract.abi).find(
73-
entry => entry.type === "constructor"
74-
)
75-
);
76-
bytecode = Shims.NewToLegacy.forBytecode(artifacts.TestContract.bytecode);
77-
});
78-
79-
it("Encodes constructors", async () => {
80-
const { data } = await encoder.encodeTxNoResolution(abi, [1]);
67+
const bytecode = Shims.NewToLegacy.forBytecode(artifact.bytecode);
68+
const { data } = await encoder.encodeCreation([1]);
8169
assert.strictEqual(
8270
data,
8371
bytecode +
8472
"0000000000000000000000000000000000000000000000000000000000000001"
8573
);
8674
});
75+
76+
it("Encodes implicit default constructors", async () => {
77+
const artifact = artifacts.AuxContract;
78+
//check that it really is implicit, that it's not in the ABI
79+
assert(!artifact.abi.some(abi => abi.type === "constructor"));
80+
const encoder = await Encoder.forArtifact(artifact, {
81+
projectInfo: { compilations }
82+
});
83+
const bytecode = Shims.NewToLegacy.forBytecode(artifact.bytecode);
84+
const { data } = await encoder.encodeCreation([]);
85+
assert.strictEqual(data, bytecode);
86+
});
8787
});
8888
});

0 commit comments

Comments
 (0)