Skip to content

Commit

Permalink
Add Code Coverage (#52)
Browse files Browse the repository at this point in the history
Co-authored-by: kosmotrade <[email protected]>
  • Loading branch information
ppsimatikas and kosmotrade authored May 27, 2024
1 parent ab0750d commit a1d3c55
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 9 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ jobs:
- name: Install & Build
run: yarn && yarn build

- name: Lint & Unit Test
- name: Lint & Unit Test & Coverage
run: |
yarn lint
yarn test unit
yarn verify
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v20.13.1
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ Intended to be used on server-side applications only.

## Local Testing

This project requires the Node.js version 20.0.0+.
If you are using nvm, you can run `nvm use` and use the node version in `.nvmrc`.

```sh
# Install
yarn
Expand Down
12 changes: 10 additions & 2 deletions jest.config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
{
"preset": "ts-jest",
"testEnvironment": "node"
}
"testEnvironment": "node",
"coverageThreshold": {
"global": {
"branches": 60,
"functions": 60,
"lines": 60,
"statements": 60
}
}
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
"build": "rm -rf ./dist && tsc",
"lint": "eslint . --ignore-pattern dist/",
"test": "jest --testTimeout 30000",
"coverage": "yarn test --coverage",
"verify": "yarn lint && yarn coverage unit",
"fmt": "prettier --write '{src,examples,tests}/**/*.{js,jsx,ts,tsx}'"
},
"devDependencies": {
Expand Down
2 changes: 2 additions & 0 deletions src/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
arbitrum,
optimism,
optimismSepolia,
localhost,
} from "viem/chains";

// All supported networks
Expand All @@ -18,6 +19,7 @@ const SUPPORTED_NETWORKS = createNetworkMap([
arbitrum,
optimism,
optimismSepolia,
localhost,
]);

interface NetworkFields {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/kdf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function najPublicKeyStrToUncompressedHexPoint(
export async function deriveChildPublicKey(
parentUncompressedPublicKeyHex: string,
signerId: string,
path = ""
path: string = ""
): Promise<string> {
const ec = new EC("secp256k1");
const scalar = await sha256Hash(
Expand Down
10 changes: 10 additions & 0 deletions tests/unit/utils.kdf.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const DECOMPRESSED_HEX =
"04a410e78ef8a4f81ffc7e1f2e60c6fd6ccd5ed1689ea83b980215a58ded51871d16b2c99f3772e6b017b35a2367883552ea6b545f82552e3b05bae56975d40241";
const CHILD_PK =
"04445b302250c5ba69e6a45d39b73a4cefc99a7e6e75ac164080c8bc68aa8c16fc332cf9b485f0f8ed0d815affdf3f9ad7e450c2658351fb09de2ad54e0f60795d";
const CHILD_PK_NO_PATH =
"043e6054b729c98e7b5fd46d4c182e7e243c1b035290cf3e5db1cb0e032382dd5065675c05934a1f7cfdf524aa8af2ede5251f03ba7ea5f154cdbadd65d0e9c36a";

describe("Crypto Functions", () => {
it("converts NEAR public key string to uncompressed hex point", () => {
Expand All @@ -27,6 +29,14 @@ describe("Crypto Functions", () => {
expect(result).toEqual(CHILD_PK);
});

it("derives child public key without path", async () => {
const parentHex = DECOMPRESSED_HEX;
const signerId = "ethdenver2024.testnet";
const result = await deriveChildPublicKey(parentHex, signerId);
expect(result).toMatch(/^04[0-9a-f]+$/);
expect(result).toEqual(CHILD_PK_NO_PATH);
});

it("converts uncompressed hex point to EVM address", () => {
const uncompressedHex = CHILD_PK;
const result = uncompressedHexPointToEvmAddress(uncompressedHex);
Expand Down
30 changes: 29 additions & 1 deletion tests/unit/utils.signature.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { signatureFromTxHash } from "../../src/utils/signature";
import {
signatureFromTxHash,
pickValidSignature,
} from "../../src/utils/signature";

describe("utility: get Signature", () => {
const url: string = "https://archival-rpc.testnet.near.org";
Expand Down Expand Up @@ -33,3 +36,28 @@ describe("utility: get Signature", () => {
);
});
});

describe("utility: pickValidSignature", () => {
const sig0 = "0x88LS5pkj99pd6B6noZU6sagQ1QDwHHoSy3qpHr5xLNsR";
const sig1 = "0xHaG9L4HnP69v6wSnAmKfzsCUhDaVMRZWNGhGqnepsMTD";

it("No signature is valid, should throw error", async () => {
expect(() => pickValidSignature([false, false], [sig0, sig1]))
.toThrow("Invalid signature");
});

it("both sig0 and sig1 are valid, should return sig0", async () => {
const sig = pickValidSignature([true, true], [sig0, sig1]);
expect(sig).toEqual(sig0);
});

it("sig0 is valid, should return sig0", async () => {
const sig = pickValidSignature([true, false], [sig0, sig1]);
expect(sig).toEqual(sig0);
});

it("sig1 is valid, should return sig1", async () => {
const sig = pickValidSignature([false, true], [sig0, sig1]);
expect(sig).toEqual(sig1);
});
});
26 changes: 25 additions & 1 deletion tests/unit/utils.transaction.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TransactionWithSignature } from "../../src";
import { buildTxPayload, addSignature } from "../../src/utils/transaction";
import { buildTxPayload, addSignature, toPayload } from "../../src/utils/transaction";

describe("Transaction Builder Functions", () => {
it("buildTxPayload", async () => {
Expand All @@ -11,6 +11,15 @@ describe("Transaction Builder Functions", () => {
36, 9, 101, 199, 230, 132, 140, 98, 211, 7, 68, 130, 233, 88, 145, 179,
]);
});

it("fails: toPayload", async () => {
const txHash =
"0x02e783aa36a7808309e8bb84773f7cbb8094deadbeef0000000000000000000000000b00b1e50180c00";
expect(() => toPayload(txHash)).toThrow(
`Payload Hex must have 32 bytes: ${txHash}`
);
});

it("addSignature", async () => {
const testTx: TransactionWithSignature = {
transaction:
Expand All @@ -27,4 +36,19 @@ describe("Transaction Builder Functions", () => {
"0x02f86b83aa36a780845974e6f084d0aa7af08094deadbeef0000000000000000000000000b00b1e50180c001a0ef532579e267c932b959a1adb9e455ac3c5397d0473471c4c3dd5d62fd4d7edea07c195e658c713d601d245311a259115bb91ec87c86acb07c03bd9c1936a6a9e8"
);
});

it("fails: addSignature", async () => {
const testTx: TransactionWithSignature = {
transaction:
"0x02e883aa36a780845974e6f084d0aa7af08094deadbeef0000000000000000000000000b00b1e50180c0",
signature: {
big_r: "02EF532579E267C932B959A1ADB9E455AC3C5397D0473471C4C3DD5D62FD4D7EDE",
big_s: "7C195E658C713D601D245311A259115BB91EC87C86ACB07C03BD9C1936A6A9E8",
},
};
const sender = "0xInvalidSenderAddress";
expect(() => addSignature(testTx, sender)).toThrow(
"Signature is not valid"
);
});
});
91 changes: 90 additions & 1 deletion tests/unit/wc.handlers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
offChainRecovery,
wcRouter,
} from "../../src/wallet-connect/handlers";
import { MessageData } from "../../src/types/types";
import { MessageData, TypedMessageData } from "../../src/types/types";

describe("Wallet Connect", () => {
const chainId = "eip155:11155111";
Expand Down Expand Up @@ -33,6 +33,20 @@ describe("Wallet Connect", () => {
]);
});

it("fail with wrong method", async () => {
const messageString = "Hello!";
const request = {
method: "eth_fail",
params: [from, toHex(messageString)],
};

await expect(wcRouter(
request.method,
chainId,
request.params as PersonalSignParams
)).rejects.toThrow("Unhandled session_request method: eth_fail");
});

it("opensea login", async () => {
const request = {
method: "personal_sign",
Expand Down Expand Up @@ -277,5 +291,80 @@ Challenge: 4113fc3ab2cc60f5d595b2e55349f1eec56fd0c70d4287081fe7156848263626`
"0x491e245db3914b85807f3807f2125b9ed9722d0e9f3fa0fe325b31893fa5e693387178ae4a51f304556c1b2e9dd24f1120d073f93017af006ad801a639214ea61b"
);
});

it("recovering eth_signTypedData", async () => {
// TODO: Find a real examples of Ethereum apps and simulate them on the test
const recoveryData = {
type: "eth_signTypedData",
data: {
address: "0xf11c22d61ecd7b1adcb6b43542fe8a96b9328dc7",
message: {
from: {
name: "Cow",
wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
},
to: {
name: "Bob",
wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
},
contents: "Hello, Bob!",
},
types: {
Person: [
{ name: "name", type: "string" },
{ name: "wallet", type: "address" },
],
Mail: [
{ name: "from", type: "Person" },
{ name: "to", type: "Person" },
{ name: "contents", type: "string" },
],
},
primaryType: "Mail",
domain: {
name: "Ether Mail",
version: "1",
chainId: 1,
verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
}
} as TypedMessageData,
};
const r =
"0x491E245DB3914B85807F3807F2125B9ED9722D0E9F3FA0FE325B31893FA5E693";
const s =
"0x387178AE4A51F304556C1B2E9DD24F1120D073F93017AF006AD801A639214EA6";
const sigs: [Hex, Hex] = [
serializeSignature({ r, s, yParity: 0 }),
serializeSignature({ r, s, yParity: 1 }),
];

await expect(offChainRecovery(recoveryData, sigs)).rejects.toThrow(
"Invalid signature"
);
});

it("fail with wrong type", async () => {
const recoveryData = {
type: "wrong_type",
data: {
address: "0xf11c22d61ecd7b1adcb6b43542fe8a96b9328dc7",
message: {
raw: "0x57656c636f6d6520746f204f70656e536561210a0a436c69636b20746f207369676e20696e20616e642061636365707420746865204f70656e536561205465726d73206f662053657276696365202868747470733a2f2f6f70656e7365612e696f2f746f732920616e64205072697661637920506f6c696379202868747470733a2f2f6f70656e7365612e696f2f70726976616379292e0a0a5468697320726571756573742077696c6c206e6f742074726967676572206120626c6f636b636861696e207472616e73616374696f6e206f7220636f737420616e792067617320666565732e0a0a57616c6c657420616464726573733a0a3078663131633232643631656364376231616463623662343335343266653861393662393332386463370a0a4e6f6e63653a0a63336432623238622d623964652d346239662d383935362d316336663739373133613431",
},
} as MessageData,
};
const r =
"0x491E245DB3914B85807F3807F2125B9ED9722D0E9F3FA0FE325B31893FA5E693";
const s =
"0x387178AE4A51F304556C1B2E9DD24F1120D073F93017AF006AD801A639214EA6";
const sigs: [Hex, Hex] = [
serializeSignature({ r, s, yParity: 0 }),
serializeSignature({ r, s, yParity: 1 }),
];

await expect(offChainRecovery(recoveryData, sigs)).rejects.toThrow(
"Invalid Path"
);
});
});
});

0 comments on commit a1d3c55

Please sign in to comment.