Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix encoding & hardhat test #18

Merged
merged 23 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
558f4a7
⚙️ Update .gitignore for hardhat
tommyrharper Nov 22, 2023
8f841af
⚙️ Integrate and install hardhat
tommyrharper Nov 22, 2023
5bdfbbc
🗑️ Delete Lock contract
tommyrharper Nov 22, 2023
1b36a92
✅ 🪖 Add hardhat Signature test
tommyrharper Nov 22, 2023
ec42d2f
✅ Add signature scaffold
tommyrharper Nov 22, 2023
e7fa90a
✅ Update to use signature
tommyrharper Nov 22, 2023
17d844c
✅ 🔧 Remove owner from test use signer
tommyrharper Nov 22, 2023
9145753
✅ Complete hardhat signer test
tommyrharper Nov 22, 2023
28099ca
👷🏻 🪲 Fix conditional order hash bug
tommyrharper Nov 22, 2023
760a9a0
✅ 🪲 Update getConditionalOrderSignatureRaw with encodePacked
tommyrharper Nov 22, 2023
9ec92ed
🚀 Add hardhat test to ci
tommyrharper Nov 22, 2023
df98ede
🚀 🪲 Remove hardhat compile
tommyrharper Nov 22, 2023
28d8ef1
🚀 🪲 Remove weird package.json thing
tommyrharper Nov 22, 2023
d2db657
🚀 🪲 Change node and npm versions in ci
tommyrharper Nov 22, 2023
ffc21c9
🚀 Update ci npm & node versions
tommyrharper Nov 22, 2023
1a0c4f1
🗑️ Delete package.json
tommyrharper Nov 22, 2023
20a23f0
🗑️ commented compile step to CI
tommyrharper Nov 22, 2023
8761f57
✅ test values in conditions hardhat
tommyrharper Nov 22, 2023
7928df5
👷🏻 🪲 Fix out-of-bounds error
tommyrharper Nov 22, 2023
38347dc
Merge pull request #19 from Kwenta/fix-encoding-hardhat-ci
tommyrharper Nov 22, 2023
6f97fbd
⚙️ Add package-lock.json to .gitignore
tommyrharper Nov 22, 2023
c142518
✅ 🧹 Add correct conditions type
tommyrharper Nov 22, 2023
e20490a
✅ 🧹 Add conditions.length to hashedConditions in test utils
tommyrharper Nov 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,31 @@ jobs:
run: |
forge test --fork-url ${{ secrets.OPTIMISM_GOERLI_RPC_URL }} --etherscan-api-key ${{ secrets.ETHERSCAN_API_KEY }} -vvv
id: test

hardhat_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- name: Check out repository code
uses: actions/checkout@v2

- name: Building on Node.js
uses: actions/setup-node@v2
with:
node-version: '18.12.0'

- name: Update NPM
run: npm install -g [email protected]
- uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/package-lock.json') }}

- name: Install dependencies
run: npm i --no-audit

- name: Execute contract tests
run: npx hardhat test
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,21 @@ out/
# Other
.vscode
.idea

# Hardhat
node_modules
.env
package-lock.json

# Hardhat files
/cache_hardhat
/cache
/artifacts

# TypeChain files
/typechain
/typechain-types

# solidity-coverage files
/coverage
/coverage.json
37 changes: 37 additions & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import "hardhat-preprocessor";
import fs from "fs";

function getRemappings() {
return fs
.readFileSync("remappings.txt", "utf8")
.split("\n")
.filter(Boolean) // remove empty lines
.map((line) => line.trim().split("="));
}

const config: HardhatUserConfig = {
solidity: "0.8.20",
preprocess: {
eachLine: (hre) => ({
transform: (line: string) => {
if (line.match(/^\s*import /i)) {
for (const [from, to] of getRemappings()) {
if (line.includes(from)) {
line = line.replace(from, to);
break;
}
}
}
return line;
},
}),
},
paths: {
sources: "./src",
cache: "./cache_hardhat",
},
};

export default config;
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
"bugs": {
"url": "https://github.com/Kwenta/smart-margin-v3/issues"
},
"devDependencies": {},
"dependencies": {}
}
"devDependencies": {
"@nomicfoundation/hardhat-toolbox": "^4.0.0",
"hardhat": "^2.19.1",
"hardhat-preprocessor": "^0.1.5"
}
}
7 changes: 7 additions & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@openzeppelin/contracts/=lib/trusted-multicall-forwarder/lib/openzeppelin-contracts/contracts/
ds-test/=lib/forge-std/lib/ds-test/src/
erc4626-tests/=lib/trusted-multicall-forwarder/lib/openzeppelin-contracts/lib/erc4626-tests/
forge-std/=lib/forge-std/src/
openzeppelin-contracts/=lib/trusted-multicall-forwarder/lib/openzeppelin-contracts/
synthetix-v3/=lib/synthetix-v3/
trusted-multicall-forwarder/=lib/trusted-multicall-forwarder/src/
4 changes: 2 additions & 2 deletions src/libraries/ConditionalOrderHashLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@

// array of dynamic length bytes must be hashed separately
// to create an array of fixed length bytes32 hashes
bytes32[] memory hashedConditions;
bytes32[] memory hashedConditions = new bytes32[](co.conditions.length);

Check warning on line 55 in src/libraries/ConditionalOrderHashLib.sol

View check run for this annotation

Codecov / codecov/patch

src/libraries/ConditionalOrderHashLib.sol#L55

Added line #L55 was not covered by tests
for (uint256 i = 0; i < co.conditions.length; i++) {
hashedConditions[i] = keccak256(co.conditions[i]);
}
Expand All @@ -66,7 +66,7 @@
co.requireVerified,
co.trustedExecutor,
co.maxExecutorFee,
keccak256(abi.encode(hashedConditions))
keccak256(abi.encodePacked(hashedConditions))
)
);
}
Expand Down
138 changes: 138 additions & 0 deletions test/Signature.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
import { expect } from "chai";
import { ethers } from "hardhat";

const ONE_ADDRESS = "0x0000000000000000000000000000000000000001";

// example data
const signerPrivateKey =
"0xe690d00bd51f5343c6999d8e88328e3dfa0111b65f2a8790d48f89fe43ad07c0";
const marketId = "200";
const accountId = "170141183460469231731687303715884105756";
const sizeDelta = "1000000000000000000";
const settlementStrategyId = "0";
const acceptablePrice =
"115792089237316195423570985008687907853269984665640564039457584007913129639935";
const isReduceOnly = false;
const trackingCode =
"0x4b57454e54410000000000000000000000000000000000000000000000000000";
const referrer = "0xF510a2Ff7e9DD7e18629137adA4eb56B9c13E885";
const nonce = "0";
const requireVerified = false;
const trustedExecutor = "0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496";
const maxExecutorFee =
"115792089237316195423570985008687907853269984665640564039457584007913129639935";
// 0x6162630000000000000000000000000000000000000000000000000000000000 = abc
// 0x6465660000000000000000000000000000000000000000000000000000000000 = def
// 0x6768690000000000000000000000000000000000000000000000000000000000 = ghi
const conditions: string[] = [
"0x6162630000000000000000000000000000000000000000000000000000000000",
"0x6465660000000000000000000000000000000000000000000000000000000000",
"0x6768690000000000000000000000000000000000000000000000000000000000",
];

describe("Signature", function () {
// We define a fixture to reuse the same setup in every test.
// We use loadFixture to run this setup once, snapshot that state,
// and reset Hardhat Network to that snapshot in every test.
async function bootstrapSystem() {
// Contracts are deployed using the first signer/account by default
const [owner, otherAccount] = await ethers.getSigners();

const Engine = await ethers.getContractFactory("Engine");
const engine = await Engine.deploy(
ONE_ADDRESS,
ONE_ADDRESS,
ONE_ADDRESS,
ONE_ADDRESS,
ONE_ADDRESS
);
await engine.waitForDeployment();

return { engine, owner, otherAccount };
}

describe("Signature checks", function () {
it("The engine deployed successfully", async function () {
const { engine } = await loadFixture(bootstrapSystem);

expect(await engine.getAddress()).to.exist;
});

it("Signature is verified", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very nicely done ☑️

const { engine } = await loadFixture(bootstrapSystem);
const wallet = new ethers.Wallet(signerPrivateKey);
const signer = wallet.address;
const engineAddress = await engine.getAddress();

const domain = {
name: "SMv3: OrderBook",
version: "1",
chainId: 31337,
verifyingContract: engineAddress,
};

const types = {
OrderDetails: [
{ name: "marketId", type: "uint128" },
{ name: "accountId", type: "uint128" },
{ name: "sizeDelta", type: "int128" },
{ name: "settlementStrategyId", type: "uint128" },
{ name: "acceptablePrice", type: "uint256" },
{ name: "isReduceOnly", type: "bool" },
{ name: "trackingCode", type: "bytes32" },
{ name: "referrer", type: "address" },
],
ConditionalOrder: [
{ name: "orderDetails", type: "OrderDetails" },
{ name: "signer", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "requireVerified", type: "bool" },
{ name: "trustedExecutor", type: "address" },
{ name: "maxExecutorFee", type: "uint256" },
{ name: "conditions", type: "bytes[]" },
],
};

let orderDetails = {
marketId: BigInt(marketId),
accountId: BigInt(accountId),
sizeDelta: BigInt(sizeDelta),
settlementStrategyId: BigInt(settlementStrategyId),
acceptablePrice: BigInt(acceptablePrice),
isReduceOnly: isReduceOnly,
trackingCode: trackingCode,
referrer: referrer,
};

// define the conditional order struct
let conditionalOrder = {
orderDetails: orderDetails,
signer: signer,
nonce: BigInt(nonce),
requireVerified: requireVerified,
trustedExecutor: trustedExecutor,
maxExecutorFee: BigInt(maxExecutorFee),
conditions: conditions,
};

const signature = await wallet.signTypedData(
domain,
types,
conditionalOrder
);

const recoveredAddress = ethers.verifyTypedData(
domain,
types,
conditionalOrder,
signature
);

expect(recoveredAddress).to.equal(signer);

const res = await engine.verifySignature(conditionalOrder, signature);
expect(res).to.be.true;
});
});
});
4 changes: 2 additions & 2 deletions test/utils/ConditionalOrderSignature.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ contract ConditionalOrderSignature {

// array of dynamic length bytes must be hashed separately
// to create an array of fixed length bytes32 hashes
bytes32[] memory hashedConditions;
bytes32[] memory hashedConditions = new bytes32[](co.conditions.length);
for (uint256 i = 0; i < co.conditions.length; i++) {
hashedConditions[i] = keccak256(co.conditions[i]);
}
Expand All @@ -53,7 +53,7 @@ contract ConditionalOrderSignature {
co.requireVerified,
co.trustedExecutor,
co.maxExecutorFee,
keccak256(abi.encode(hashedConditions))
keccak256(abi.encodePacked(hashedConditions))
)
);

Expand Down
11 changes: 11 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true
}
}
Loading