Skip to content
This repository has been archived by the owner on Feb 23, 2023. It is now read-only.

Commit

Permalink
Merge pull request #83 from nervosnetwork/fix-process
Browse files Browse the repository at this point in the history
fix(base, web3): bug in buildDeployProcess when using metamask
  • Loading branch information
RetricSu authored Dec 28, 2021
2 parents ac3e105 + cd3ff1b commit bb853a1
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 22 deletions.
26 changes: 13 additions & 13 deletions packages/base/src/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,19 @@ export async function buildDeployProcess(
);
}

const result = splitByteCodeAndConstructorArgs(tx.data, deploymentRecords);
if (result == null) {
// let's build a standard send transaction
// since we can't find matched deploymentRecords
return buildSendTransaction(
abi,
godwoker,
tx,
signingMethod,
signingMessageType_
);
}

const t = normalizeEthTransaction({
from: tx.from,
to: tx.to,
Expand Down Expand Up @@ -154,19 +167,6 @@ export async function buildDeployProcess(
const signature = godwoker.packSignature(_signature);
const l2Tx = { raw: rawL2Tx, signature: signature };

const result = splitByteCodeAndConstructorArgs(tx.data, deploymentRecords);
if (result == null) {
// let's build a standard send transaction
// since we can't find matched deploymentRecords
return buildSendTransaction(
abi,
godwoker,
tx,
signingMethod,
signingMessageType_
);
}

const abiItem = deploymentRecords[result.signature];
const _abiItem = _.cloneDeep(abiItem); // do not change the original abi object
let serializedAbiItem = serializeAbiItem(_abiItem);
Expand Down
10 changes: 7 additions & 3 deletions packages/web3/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
"/lib"
],
"ava": {
"files": [
"!tests/helper.ts"
],
"extensions": [
"ts"
],
Expand All @@ -40,6 +43,7 @@
]
},
"devDependencies": {
"@metamask/eth-sig-util": "^4.0.0",
"@types/node": "^14.14.37",
"ava": "^3.15.0",
"babel-plugin-transform-runtime": "^6.23.0",
Expand All @@ -55,19 +59,19 @@
"stream-browserify": "^3.0.0",
"ts-loader": "^8.0.12",
"ts-node": "^10.0.0",
"web3": "^1.6.1",
"webpack": "^5.28.0",
"webpack-cli": "^4.5.0",
"webpack-node-externals": "^3.0.0",
"web3": "^1.6.1"
"webpack-node-externals": "^3.0.0"
},
"dependencies": {
"@polyjuice-provider/base": "0.1.2",
"buffer": "^6.0.3",
"encoding": "^0.1.13",
"web3-core": "^1.6.1",
"web3-core-helpers": "1.6.1",
"web3-eth-accounts": "^1.6.1",
"web3-providers-ws": "^1.6.1",
"web3-core-helpers": "1.6.1",
"xhr2-cookies": "^1.1.0"
}
}
3 changes: 2 additions & 1 deletion packages/web3/src/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ export class PolyjuiceHttpProvider {
this.abi,
this.godwoker,
t,
signingMethod.bind(this)
signingMethod.bind(this),
SigningMessageType.noPrefix
)
: await buildSendTransaction(
this.abi,
Expand Down
3 changes: 2 additions & 1 deletion packages/web3/src/ws-providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ export class PolyjuiceWebsocketProvider extends Web3WsProvider {
this.abi,
this.godwoker,
t,
signingMethod.bind(this)
signingMethod.bind(this),
SigningMessageType.noPrefix
)
: await buildSendTransaction(
this.abi,
Expand Down
43 changes: 43 additions & 0 deletions packages/web3/tests/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { personalSign } from "@metamask/eth-sig-util";
import crypto from "crypto";
import keccak256 from "keccak256";
import Web3 from "web3";

export function privateKeyToEthAddress(privateKey) {
const ecdh = crypto.createECDH(`secp256k1`);
ecdh.generateKeys();
ecdh.setPrivateKey(Buffer.from(privateKey.slice(2), "hex"));
const publicKey = "0x" + ecdh.getPublicKey("hex", "uncompressed");
const _ethAddress =
"0x" +
keccak256(Buffer.from(publicKey.slice(4), "hex"))
.slice(12)
.toString("hex");
const ethAddress = Web3.utils.toChecksumAddress(_ethAddress);
return ethAddress;
}

export async function initMockWindowsEthereum(privateKey: string) {
let window = {
ethereum: {
request: async function ({ method, params }) {
if (method !== "personal_sign") {
throw new Error(
"mock window.ethereum only impl personal_sign method."
);
}
const [message_without_prefix, address] = params;
const ethAddress = privateKeyToEthAddress(privateKey);
if (address === ethAddress.toLocaleLowerCase()) {
return personalSign({
privateKey: Buffer.from(privateKey.slice(2), "hex"),
data: message_without_prefix,
});
}

throw new Error("invalid test data");
},
},
};
return window;
}
157 changes: 157 additions & 0 deletions packages/web3/tests/metamask.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import test from "ava";
import Web3 from "web3";
import { PolyjuiceHttpProvider } from "../lib/index";
import { AbiItems, PolyjuiceConfig } from "@polyjuice-provider/base";
import anotherContract from "../../../contract-testcase/ErrorReceipt.json";
import deployArgsTestContract from "../../../contract-testcase/DeployArgs.json";
import { genNewEthAddress } from "../../../contract-testcase/helper";
import { initMockWindowsEthereum } from "./helper";
const Contract = require("web3-eth-contract");

const root = require("path").join.bind(this, __dirname, "..");
require("dotenv").config({ path: root(".test.env") });

const ABI = deployArgsTestContract.abi as AbiItems;
const BYTECODE = deployArgsTestContract.bytecode;

const PRIVATE_KEY = process.env.PRIVATE_KEY;
let ethAddressFromPrivateKey = process.env.ETH_ADDRESS;

let testAddressArray = [
genNewEthAddress(),
"0x0000000000000000000000000000000000000000",
ethAddressFromPrivateKey,
];

let contractAddressFromBadDeployment: string;
let contractAddressFromGoodDeployment: string;
let contractDeployArgs: any[];

let provider: PolyjuiceHttpProvider;
let web3: Web3;

test.before(async (t) => {
// init provider and web3
const web3Rpc = process.env.WEB3_JSON_RPC;
const polyjuiceConfig: PolyjuiceConfig = {
abiItems: [...ABI, ...anotherContract.abi] as AbiItems,
web3Url: web3Rpc,
};

provider = new PolyjuiceHttpProvider(web3Rpc, polyjuiceConfig);
web3 = new Web3(provider);
(global as any).window = await initMockWindowsEthereum(PRIVATE_KEY);
Contract.setProvider(provider);
});

test.serial("prepare one contract address by deploying", async (t) => {
const deployTx = new Contract(anotherContract.abi as AbiItems)
.deploy({
data: anotherContract.bytecode,
arguments: [],
})
.send({
from: ethAddressFromPrivateKey,
gasPrice: "0x00",
});
const contract = await deployTx;

t.is(contract.options.address.slice(0, 2), "0x");
contractAddressFromBadDeployment = contract.options.address;
testAddressArray.push(contractAddressFromBadDeployment);
});

test.serial("deploy example contract without converting address", async (t) => {
const constructorArgs = [1, testAddressArray];
contractDeployArgs = constructorArgs;
const deployTx = new Contract(ABI)
.deploy({
data: BYTECODE,
arguments: constructorArgs,
})
.send({
from: ethAddressFromPrivateKey,
gasPrice: "0x00",
});
const contract = await deployTx;

t.is(contract.options.address.slice(0, 2), "0x");
contractAddressFromBadDeployment = contract.options.address;
});

test.serial(
"call example contract to show deploy arguments is not supporting automatically address-converting",
async (t) => {
const contract = new web3.eth.Contract(
ABI as AbiItems,
contractAddressFromBadDeployment
);
const value: string = await contract.methods.getValue().call();
t.is(value, contractDeployArgs[0].toString());

// the return addressList should be the same with the contract constructor arguments
// since the address converting for deployment arguments
// are not supported in providers for now.
// therefor, when you call contract method to return addressList,
// the address-type converting from polyjuiceAddress to ethAddress will go wrong,
// thus throw error is expected
const callRevert = async () => {
try {
await contract.methods.getAddressList().call();
} catch (error) {
throw new Error(error.message);
}
};
const callRevertRunResult = await t.throwsAsync(callRevert);
t.true(
callRevertRunResult.message.includes(
"result from jsonRPC poly_getEthAddressByGodwokenShortAddress is null or undefined. unable to fetch eth address from"
)
);
const errorAddress = callRevertRunResult.message.slice(-42);
t.true(testAddressArray.includes(errorAddress));
}
);

test.serial("deploy example contract in the right way", async (t) => {
const constructorArgs = [1, testAddressArray];
contractDeployArgs = constructorArgs;

// you need this extra steps to convert your constructor arguments
// for deploying contract otherwise the address type will go wrong
const newConstructorArgs = await provider.convertDeployArgs(
constructorArgs,
ABI as AbiItems,
BYTECODE
);
t.not(constructorArgs, newConstructorArgs);
// pass the new args with address converting to deploy contract
const deployTx = new Contract(ABI)
.deploy({
data: BYTECODE,
arguments: newConstructorArgs,
})
.send({
from: ethAddressFromPrivateKey,
gasPrice: "0x00",
});
const contract = await deployTx;
t.is(contract.options.address.slice(0, 2), "0x");
contractAddressFromGoodDeployment = contract.options.address;
});

test.serial(
"call example contract with good deployment to show deploy arguments supporting automatically address-converting",
async (t) => {
const contract = new web3.eth.Contract(
ABI as AbiItems,
contractAddressFromGoodDeployment
);
const value: string = await contract.methods.getValue().call();
t.is(value, contractDeployArgs[0].toString());

// the return addressList should be the same with the contract constructor arguments
const addressList = await contract.methods.getAddressList().call();
t.deepEqual(addressList, contractDeployArgs[1]);
}
);
22 changes: 21 additions & 1 deletion packages/web3/tests/web3.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import {
} from "../lib/index";
import {
AbiItems,
DEFAULT_EMPTY_ETH_ADDRESS,
PolyjuiceConfig,
RpcFailedError,
} from "@polyjuice-provider/base";
import { initMockWindowsEthereum } from "./helper";
import errorReceiptContract from "../../../contract-testcase/ErrorReceipt.json";

const Contract = require("web3-eth-contract");
Expand Down Expand Up @@ -358,6 +358,26 @@ test.serial("ws: test-ws-provider-with-account", async (t) => {
t.is(txRes.status, true);
});

test.serial("ws: test-ws-provider-with-metamask", async (t) => {
(global as any).window = await initMockWindowsEthereum(PRIVATE_KEY);

const simpleStorageV2 = new wsWeb3.eth.Contract(
EXAMPLE_CONTRACT.abi as AbiItems,
contract_address!
);

const id = await wsWeb3.eth.net.getId();
const txRes = await simpleStorageV2.methods
.set(ETH_ADDRESS)
.send({ from: ETH_ADDRESS, gas: "0x30d40", gasPrice: "0x00" });

t.is(id, 1024777);
t.is(txRes.transactionHash.slice(0, 2), "0x");
t.is(txRes.transactionHash.length, 66);
t.is(typeof txRes.gasUsed, "number");
t.is(txRes.status, true);
});

// test.serial("make a lot of call at short time", async (t) => {
// polyjuiceAccounts.wallet.add(PRIVATE_KEY);
// Contract.setProvider(provider, polyjuiceAccounts);
Expand Down
17 changes: 14 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,17 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==

"@metamask/eth-sig-util@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.0.tgz#11553ba06de0d1352332c1bde28c8edd00e0dcf6"
integrity sha512-LczOjjxY4A7XYloxzyxJIHONELmUxVZncpOLoClpEcTiebiVdM46KRPYXGuULro9oNNR2xdVx3yoKiQjdfWmoA==
dependencies:
ethereumjs-abi "^0.6.8"
ethereumjs-util "^6.2.1"
ethjs-util "^0.1.6"
tweetnacl "^1.0.3"
tweetnacl-util "^0.15.1"

"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
Expand Down Expand Up @@ -3284,7 +3295,7 @@ ethereumjs-util@^5.0.0, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2, ethereum
rlp "^2.0.0"
safe-buffer "^5.1.1"

ethereumjs-util@^6.0.0, ethereumjs-util@^6.1.0:
ethereumjs-util@^6.0.0, ethereumjs-util@^6.1.0, ethereumjs-util@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69"
integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==
Expand Down Expand Up @@ -3395,7 +3406,7 @@ ethjs-unit@0.1.6:
bn.js "4.11.6"
number-to-bn "1.7.0"

ethjs-util@0.1.6, ethjs-util@^0.1.3:
ethjs-util@0.1.6, ethjs-util@^0.1.3, ethjs-util@^0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536"
integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==
Expand Down Expand Up @@ -6847,7 +6858,7 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"

tweetnacl-util@^0.15.0:
tweetnacl-util@^0.15.0, tweetnacl-util@^0.15.1:
version "0.15.1"
resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b"
integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==
Expand Down

0 comments on commit bb853a1

Please # to comment.