Skip to content

Commit

Permalink
test: migrate integration tests to hardhat
Browse files Browse the repository at this point in the history
  • Loading branch information
Luisfc68 committed Jan 3, 2025
1 parent c8fe0e3 commit 4707a36
Show file tree
Hide file tree
Showing 12 changed files with 602 additions and 485 deletions.
1 change: 0 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ errorCodes.json

truffle*
migrations
integration-test
testHashQuote.js
testRefundPegout.js
testRegisterPegout.js
Expand Down
2 changes: 0 additions & 2 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ export default [
"node_modules/*",
"artifacts/*",
"cache/*",
"node_modules/*",
// should be removed after completing the hardhat migration
"migrations/*",
"truffle*",
"integration-test/*",
"testHashQuote.js",
"testRefundPegout.js",
"testRegisterPegout.js",
Expand Down
7 changes: 6 additions & 1 deletion integration-test/Readme.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# Integration test

The purpose of this test is to validate that the basic flow of the pegin and pegout works in a particular network

## Configuration

To run the test you need to have a file named `test.config.json` with the same format as `test.config.example.json`. The fields are the following:

- **pollingIntervalInSeconds**: number of seconds that the test is going to wait to check again during long lasting operations. E. g. waiting for bitcoin transaction confirmations
- **lbcAddress**: the address of the `LiquidityBridgeContract` in the network where the test is running
- **btcUtilsAddress**: the address of the `BtcUtils` library in the network where the test is running
Expand All @@ -13,12 +16,14 @@ To run the test you need to have a file named `test.config.json` with the same f
- **btc**: url, user and password of the bitcoin rpc server that is going to be used to perform the bitcoin transactions

## How to run

1. Register the liquidity provider address in the `LiquidityBridgeContract`
2. Complete the config file fields
3. Add the network to `truffe-config.js` file
4. Run `npm run test:integration <network>`

## Constraints

- The LP address that is set on config file must be registered as LP in the contract
- The ABI files in `build` folder need to correspond with the contract that is being tested
- Timeout must be disabled
- Timeout must be disabled
107 changes: 0 additions & 107 deletions integration-test/common.js

This file was deleted.

123 changes: 123 additions & 0 deletions integration-test/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { BytesLike } from "ethers";
import { readFile } from "fs/promises";

export interface IntegrationTestConfig {
pollingIntervalInSeconds: number;
lbcAddress: string;
btcUtilsAddress: string;
lpPrivateKey: string;
lpBtcAddress: string;
userPrivateKey: string;
userBtcAddress: string;
btc: {
url: string;
user: string;
pass: string;
walletName: string;
walletPassphrase: string;
txFee: number;
};
}

export const INTEGRATION_TEST_TIMEOUT = 1000 * 60 * 60 * 3; // 3 hours
export type BtcCaller = <T>(method: string, ...args: unknown[]) => Promise<T>;

export const sleep: (ms: number) => Promise<void> = (ms) =>
new Promise((resolve) => setTimeout(resolve, ms));
export const formatHex = (hex: string) =>
hex.startsWith("0x") ? hex : "0x" + hex;

export async function loadConfig(): Promise<IntegrationTestConfig> {
const buffer = await readFile("integration-test/test.config.json");
return JSON.parse(buffer.toString()) as IntegrationTestConfig;
}

export function getBitcoinRpcCaller(
args: IntegrationTestConfig["btc"],
debug = false
): BtcCaller {
const { url, user, pass, walletName } = args;
const headers = new Headers();
headers.append("content-type", "application/json");
const token = Buffer.from(`${user}:${pass}`).toString("base64");
headers.append("Authorization", "Basic " + token);

return async function <T>(method: string, ...args: unknown[]): Promise<T> {
const body = JSON.stringify({
jsonrpc: "1.0",
method: method.toLowerCase(),
params: typeof args[0] === "object" ? args[0] : args,
});
const requestOptions = { method: "POST", headers, body };
if (debug) {
console.debug(body);
}
const parsedUrl = new URL(url);
parsedUrl.pathname = "/wallet/" + walletName;
return fetch(parsedUrl.toString(), requestOptions)
.then((response) => {
if (!response.ok) {
throw new Error(response.statusText);
}
return response.json();
})
.then((response: { result: T; error?: Error }) => {
if (response.error) {
throw response.error;
}
return response.result satisfies T;
});
};
}

export async function sendBtc(args: {
toAddress: string;
amountInBtc: number | string;
rpc: BtcCaller;
data?: string;
}) {
const { toAddress, amountInBtc, rpc, data } = args;
const outputs = [{ [toAddress]: amountInBtc.toString() }];
const fundOptions: { fee_rate: number; changePosition?: number } = {
fee_rate: 25,
};
if (data) {
outputs.push({ data });
fundOptions.changePosition = 2;
}
const rawSendTx = await rpc("createrawtransaction", {
inputs: [],
outputs,
});
const fundedSendTx = await rpc<{ hex: string }>(
"fundrawtransaction",
rawSendTx,
fundOptions
);
const signedSendTx = await rpc<{ hex: string }>(
"signrawtransactionwithwallet",
fundedSendTx.hex
);
return rpc<string>("sendrawtransaction", signedSendTx.hex);
}

export async function waitForBtcTransaction(args: {
rpc: BtcCaller;
hash: BytesLike;
confirmations: number;
interval: number;
}) {
const { rpc, hash, confirmations, interval } = args;
let tx: { confirmations: number; blockhash: string; hex: string } | undefined;
while (!tx?.confirmations || confirmations > tx.confirmations) {
tx = await rpc("gettransaction", hash);
if (tx && confirmations > tx.confirmations) {
console.info(
`Waiting for transaction ${hash.toString()} (${tx.confirmations.toString()} confirmations)`
);
await sleep(interval);
}
}
console.info("Transaction confirmed");
return tx;
}
Loading

0 comments on commit 4707a36

Please sign in to comment.