Skip to content

Commit

Permalink
merge dev
Browse files Browse the repository at this point in the history
  • Loading branch information
jrwbabylonlab committed Sep 19, 2024
2 parents 1e183d1 + 4ce4bca commit 08b058e
Show file tree
Hide file tree
Showing 83 changed files with 7,210 additions and 2,729 deletions.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
NEXT_PUBLIC_MEMPOOL_API=https://babylon.mempool.space
NEXT_PUBLIC_MEMPOOL_API=https://mempool.space
NEXT_PUBLIC_API_URL=https://staking-api.testnet.babylonchain.io
NEXT_PUBLIC_POINTS_API_URL=https://points.testnet.babylonchain.io
NEXT_PUBLIC_NETWORK=signet
NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES=true
1 change: 1 addition & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
build-args: |
NEXT_PUBLIC_MEMPOOL_API=${{ vars.NEXT_PUBLIC_MEMPOOL_API }}
NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL }}
NEXT_PUBLIC_POINTS_API_URL=${{ vars.NEXT_PUBLIC_POINTS_API_URL }}
NEXT_PUBLIC_NETWORK=${{ vars.NEXT_PUBLIC_NETWORK }}
NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES=${{ vars.NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES }}
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/sync_pr_dev_to_main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Create Sync PR from Main to Dev

on:
schedule:
- cron: "0 0 * * *"

permissions:
pull-requests: write

jobs:
call_sync_branch:
uses: babylonlabs-io/.github/.github/workflows/[email protected]
with:
base_branch: "main"
target_branch: "dev"
reviewers: "jrwbabylonlab,gbarkhatov,jeremy-babylonlabs"
secrets: inherit
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ dist
.svelte-kit

### VisualStudioCode ###
.vscode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
Expand Down Expand Up @@ -259,3 +260,13 @@ yarn-error.log*
next-env.d.ts

.env

# E2E Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/

# E2E Chrome Extensions
extensions

2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v22.6.0
v22.3.0
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ ENV NEXT_PUBLIC_MEMPOOL_API=${NEXT_PUBLIC_MEMPOOL_API}
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}

ARG NEXT_PUBLIC_POINTS_API_URL
ENV NEXT_PUBLIC_POINTS_API_URL=${NEXT_PUBLIC_POINTS_API_URL}

ARG NEXT_PUBLIC_NETWORK
ENV NEXT_PUBLIC_NETWORK=${NEXT_PUBLIC_NETWORK}

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ where,
node queries
- `NEXT_PUBLIC_API_URL` specifies the back-end API to use for the staking
system queries
- `NEXT_PUBLIC_POINTS_API_URL` specifies the Points API to use for the points
system
- `NEXT_PUBLIC_NETWORK` specifies the BTC network environment
- `NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES` boolean value to indicate whether display
testing network related message. Default to true
Expand Down
8 changes: 8 additions & 0 deletions e2e/app.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { expect, test } from "@playwright/test";

test.describe("App", () => {
test("should have a title", async ({ page }) => {
await page.goto("/");
await expect(page).toHaveTitle(/Staking Dashboard/);
});
});
20 changes: 20 additions & 0 deletions e2e/balanceAddress.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { expect, test } from "@playwright/test";

import { setupWalletConnection } from "./helper/connect";

test.describe("Balance and address checks after connection", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/");
await setupWalletConnection(page);
});

test("balance is correct", async ({ page }) => {
const balance = await page.getByTestId("balance").textContent();
expect(balance).toBe("0.12345678 BTC");
});

test("address is correct", async ({ page }) => {
const address = await page.getByTestId("address").textContent();
expect(address).toBe("bc1p...97sd");
});
});
6 changes: 6 additions & 0 deletions e2e/constants/staking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { satoshiToBtc } from "@/utils/btcConversions";

export const STAKING_AMOUNT_SAT = 50000;
export const STAKING_AMOUNT_BTC = satoshiToBtc(STAKING_AMOUNT_SAT);
export const STAKING_TX_HASH =
"47af61d63bcc6c513561d9a1198d082052cc07a81f50c6f130653f0a6ecc0fc1";
54 changes: 54 additions & 0 deletions e2e/helper/connect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Page, expect } from "@playwright/test";

import { injectBTCWallet } from "./injectBTCWallet";

export const clickConnectButton = async (page: Page) => {
const connectButton = page.getByRole("button", {
name: "Connect to BTC",
});
await connectButton.click();
};

export const acceptTermsAndConditions = async (page: Page) => {
const termsCheckbox = page
.locator("label")
.filter({ hasText: "I certify that I have read" });

const inscriptionsCheckbox = page
.locator("label")
.filter({ hasText: "I certify that there are no" });

const hwCheckbox = page
.locator("label")
.filter({ hasText: "I acknowledge that Keystone via QR code" });

await termsCheckbox.click();
await inscriptionsCheckbox.click();
await hwCheckbox.click();

expect(await termsCheckbox.isChecked()).toBe(true);
expect(await inscriptionsCheckbox.isChecked()).toBe(true);
expect(await hwCheckbox.isChecked()).toBe(true);
};

export const clickInjectableWalletButton = async (page: Page) => {
const browserButton = page
.getByTestId("modal")
.getByRole("button", { name: "Browser" });
await browserButton.click();
};

export const clickConnectWalletButton = async (page: Page) => {
const connectWalletButton = page.getByTestId("modal").getByRole("button", {
name: "Connect to BTC network",
});
await connectWalletButton.click();
};

export const setupWalletConnection = async (page: Page) => {
await injectBTCWallet(page);
await clickConnectButton(page);
await acceptTermsAndConditions(page);
await clickInjectableWalletButton(page);
await clickConnectWalletButton(page);
};
47 changes: 47 additions & 0 deletions e2e/helper/injectBTCWallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Page } from "@playwright/test";

// Sample wallet implementation for E2E testing purposes
export const injectBTCWallet = async (page: Page) => {
// Inject the wallet methods into window.btcwallet
await page.evaluate(() => {
// wallet
const btcWallet = {
connectWallet: () => {
return btcWallet;
},
getWalletProviderName: () => "BTC Wallet",
getAddress: () =>
"bc1p8gjpy0vyfdq3tty8sy0v86dvl69rquc85n2gpuztll9wxh9cpars7r97sd",
getPublicKeyHex: () =>
"024c6e2954c75bcb53aa13b7cd5d8bcdb4c9a4dd0784d68b115bd4408813b45608",
on: () => {},
getNetwork: () => "mainnet",
getBTCTipHeight: () => 859568,
getNetworkFees: () => ({
fastestFee: 1,
halfHourFee: 1,
hourFee: 1,
economyFee: 1,
minimumFee: 1,
}),
getUtxos: () => [
{
txid: "fa4908ad8876655ccb5ffba6a9eab58e1b785af73703cd58b19526c099d67c05",
vout: 0,
value: 12345678,
scriptPubKey:
"51203a24123d844b4115ac87811ec3e9acfe8a307307a4d480f04bffcae35cb80f47",
},
],
getInscriptions: () => [],
signPsbt: (_psbtHex: string) => {
return "70736274ff0100fd040102000000028a12de07985b7d06d83d9683eb3c0a86284fa3cbb2df998aed61009d700748ba0200000000fdffffff4ca53ae433b535b660a2dca99724199b2219a617508eed2ccf88762683a622430200000000fdffffff0350c3000000000000225120cf7c40c6fb1395430816dbb5e1ba9f172ef25573a3b609efa1723559cd82d5590000000000000000496a4762626234004c6e2954c75bcb53aa13b7cd5d8bcdb4c9a4dd0784d68b115bd4408813b45608094f5861be4128861d69ea4b66a5f974943f100f55400bf26f5cce124b4c9af7009604450000000000002251203a24123d844b4115ac87811ec3e9acfe8a307307a4d480f04bffcae35cb80f47340e0d000001012b50ba0000000000002251203a24123d844b4115ac87811ec3e9acfe8a307307a4d480f04bffcae35cb80f470108420140f94b4114bf4c77c449fefb45d60a86831a73897e58b03ba8250e1bf877912cdcc48d106fa266e8aa4085a43e9ad348652fb7b1ad0d820b6455c06edd92cadfef0001012b79510000000000002251203a24123d844b4115ac87811ec3e9acfe8a307307a4d480f04bffcae35cb80f470108420140e7abc0544c68c94a154e9136397ad8ab7d4dce0545c7c0db89aeb9a455e9377fb1c116ca20cdcb1c1ef4c9335a85c34499f45918ee37b010b69220626c4a8d7100000000";
},
pushTx: (_txHex: string) => {
return "47af61d63bcc6c513561d9a1198d082052cc07a81f50c6f130653f0a6ecc0fc1";
},
};

window.btcwallet = btcWallet;
});
};
18 changes: 18 additions & 0 deletions e2e/helper/interceptRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Page } from "@playwright/test";

// Utility function to intercept requests and fulfill them with mock data
export const interceptRequest = async (
page: Page,
urlPattern: string,
status: number,
body: Record<string, any> = {},
contentType: string = "application/json",
): Promise<void> => {
await page.route(urlPattern, async (route) => {
await route.fulfill({
status,
contentType,
body: JSON.stringify(body),
});
});
};
46 changes: 46 additions & 0 deletions e2e/mock/tx/unbonding.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { DelegationState } from "@/app/types/delegations";

export const activeTX = {
data: [
{
staking_tx_hash_hex:
"1547205e6e32aaeb4eba21788891f4f323ffee9fd824461300f71292fe33f67e",
staker_pk_hex:
"4c6e2954c75bcb53aa13b7cd5d8bcdb4c9a4dd0784d68b115bd4408813b45608",
finality_provider_pk_hex:
"094f5861be4128861d69ea4b66a5f974943f100f55400bf26f5cce124b4c9af7",
state: DelegationState.ACTIVE,
staking_value: 50000,
staking_tx: {
tx_hex:
"02000000000102b497f79965a97f792dc604791cb97d76567660fdcff8d519cf993175de2880c00000000000fdffffff092b154d5edd66be91057390140898468a48df393ea52e52f6fe82fc895141ec0000000000fdffffff0350c3000000000000225120cf7c40c6fb1395430816dbb5e1ba9f172ef25573a3b609efa1723559cd82d5590000000000000000496a4762626234004c6e2954c75bcb53aa13b7cd5d8bcdb4c9a4dd0784d68b115bd4408813b45608094f5861be4128861d69ea4b66a5f974943f100f55400bf26f5cce124b4c9af70096cdb80000000000002251203a24123d844b4115ac87811ec3e9acfe8a307307a4d480f04bffcae35cb80f470140aefb4107e1a224ec95f5ef3482e594371d575b869b6ea95f985fd39d02f821549acd28c7c4a80e4d2af66e6d24f06f3e4be4e8f1e6778559c25ed4eca145fa960140242411eccc7853685dd04e7b2eb0ad337e6e8c0039026114cb2500566aa1e6d4288121ccec9535aaee697d0b4f0fd2588838d4d3a0055165aeeb59883fdd1716340e0d00",
output_index: 0,
start_timestamp: "2024-09-12T16:09:01Z",
start_height: 861031,
timelock: 150,
},
is_overflow: false,
},
],
pagination: { next_key: "" },
};

export const unbondingPOST = {
staker_signed_signature_hex:
"c73ffb9088349cb94b4d5a5f293394627d190437f47dc2275a1c67afd8f1200d594f8d86f4dd6bf248bd2f71f337eac094feafebe78ea68279c3e22609cf5b58",
staking_tx_hash_hex:
"1547205e6e32aaeb4eba21788891f4f323ffee9fd824461300f71292fe33f67e",
unbonding_tx_hash_hex:
"6f62aaae98658e64c6ee91f408375feb06bbd33536b7a5ffc12cc88c43a82c93",
unbonding_tx_hex:
"020000000001017ef633fe9212f700134624d89feeff23f3f491887821ba4eebaa326e5e2047150000000000ffffffff019065000000000000225120f33fe22ce55a0d4f272d54d84ceb2d8b383784bd5bdad12cfc6e6ed38336148f0340c73ffb9088349cb94b4d5a5f293394627d190437f47dc2275a1c67afd8f1200d594f8d86f4dd6bf248bd2f71f337eac094feafebe78ea68279c3e22609cf5b588a204c6e2954c75bcb53aa13b7cd5d8bcdb4c9a4dd0784d68b115bd4408813b45608ad206f13a6d104446520d1757caec13eaf6fbcf29f488c31e0107e7351d4994cd068ac20a10a06bb3bae360db3aef0326413b55b9e46bf20b9a96fc8a806a99e644fe277ba20a5e21514682b87e37fb5d3c9862055041d1e6f4cc4f3034ceaf3d90f86b230a6ba529c61c050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac08cbd88238189c54c871cf32592ee6a4168ace71be7fa421fe0d115170c55fd872e3fc575e9845aca1bad807c7c409836824e21b47fcdc5ba259c787c17ff5fca00000000",
};

export const unbondingTX = {
tx_hex:
"020000000001017ef633fe9212f700134624d89feeff23f3f491887821ba4eebaa326e5e2047150000000000ffffffff019065000000000000225120f33fe22ce55a0d4f272d54d84ceb2d8b383784bd5bdad12cfc6e6ed38336148f0600406e6c2d481d4c77bf841c98e32b2dfcc86bb3267564752e03a34e67fdf70a9c2a7eddc15943f938b915518405dc6c80807971883f5206026ca609254ae401310040f53aa9e92f4d93ec92da58c6c7a379f18435f7ac877eda33105300115e942a403ae384ccfade0b690acd3bc4b6f2d946f1ef8a370f0d74fca346915dd2090caf40c73ffb9088349cb94b4d5a5f293394627d190437f47dc2275a1c67afd8f1200d594f8d86f4dd6bf248bd2f71f337eac094feafebe78ea68279c3e22609cf5b588a204c6e2954c75bcb53aa13b7cd5d8bcdb4c9a4dd0784d68b115bd4408813b45608ad206f13a6d104446520d1757caec13eaf6fbcf29f488c31e0107e7351d4994cd068ac20a10a06bb3bae360db3aef0326413b55b9e46bf20b9a96fc8a806a99e644fe277ba20a5e21514682b87e37fb5d3c9862055041d1e6f4cc4f3034ceaf3d90f86b230a6ba529c61c050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac08cbd88238189c54c871cf32592ee6a4168ace71be7fa421fe0d115170c55fd872e3fc575e9845aca1bad807c7c409836824e21b47fcdc5ba259c787c17ff5fca00000000",
output_index: 0,
start_timestamp: "2024-09-12T16:32:26Z",
start_height: 861033,
timelock: 5,
};
34 changes: 34 additions & 0 deletions e2e/mock/tx/withdrawing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { DelegationState } from "@/app/types/delegations";

export const unbondedTX = {
data: [
{
staking_tx_hash_hex:
"1547205e6e32aaeb4eba21788891f4f323ffee9fd824461300f71292fe33f67e",
staker_pk_hex:
"4c6e2954c75bcb53aa13b7cd5d8bcdb4c9a4dd0784d68b115bd4408813b45608",
finality_provider_pk_hex:
"094f5861be4128861d69ea4b66a5f974943f100f55400bf26f5cce124b4c9af7",
state: DelegationState.UNBONDED,
staking_value: 50000,
staking_tx: {
tx_hex:
"02000000000102b497f79965a97f792dc604791cb97d76567660fdcff8d519cf993175de2880c00000000000fdffffff092b154d5edd66be91057390140898468a48df393ea52e52f6fe82fc895141ec0000000000fdffffff0350c3000000000000225120cf7c40c6fb1395430816dbb5e1ba9f172ef25573a3b609efa1723559cd82d5590000000000000000496a4762626234004c6e2954c75bcb53aa13b7cd5d8bcdb4c9a4dd0784d68b115bd4408813b45608094f5861be4128861d69ea4b66a5f974943f100f55400bf26f5cce124b4c9af70096cdb80000000000002251203a24123d844b4115ac87811ec3e9acfe8a307307a4d480f04bffcae35cb80f470140aefb4107e1a224ec95f5ef3482e594371d575b869b6ea95f985fd39d02f821549acd28c7c4a80e4d2af66e6d24f06f3e4be4e8f1e6778559c25ed4eca145fa960140242411eccc7853685dd04e7b2eb0ad337e6e8c0039026114cb2500566aa1e6d4288121ccec9535aaee697d0b4f0fd2588838d4d3a0055165aeeb59883fdd1716340e0d00",
output_index: 0,
start_timestamp: "2024-09-12T16:09:01Z",
start_height: 861031,
timelock: 150,
},
is_overflow: false,
unbonding_tx: {
tx_hex:
"020000000001017ef633fe9212f700134624d89feeff23f3f491887821ba4eebaa326e5e2047150000000000ffffffff019065000000000000225120f33fe22ce55a0d4f272d54d84ceb2d8b383784bd5bdad12cfc6e6ed38336148f0600406e6c2d481d4c77bf841c98e32b2dfcc86bb3267564752e03a34e67fdf70a9c2a7eddc15943f938b915518405dc6c80807971883f5206026ca609254ae401310040f53aa9e92f4d93ec92da58c6c7a379f18435f7ac877eda33105300115e942a403ae384ccfade0b690acd3bc4b6f2d946f1ef8a370f0d74fca346915dd2090caf40c73ffb9088349cb94b4d5a5f293394627d190437f47dc2275a1c67afd8f1200d594f8d86f4dd6bf248bd2f71f337eac094feafebe78ea68279c3e22609cf5b588a204c6e2954c75bcb53aa13b7cd5d8bcdb4c9a4dd0784d68b115bd4408813b45608ad206f13a6d104446520d1757caec13eaf6fbcf29f488c31e0107e7351d4994cd068ac20a10a06bb3bae360db3aef0326413b55b9e46bf20b9a96fc8a806a99e644fe277ba20a5e21514682b87e37fb5d3c9862055041d1e6f4cc4f3034ceaf3d90f86b230a6ba529c61c050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac08cbd88238189c54c871cf32592ee6a4168ace71be7fa421fe0d115170c55fd872e3fc575e9845aca1bad807c7c409836824e21b47fcdc5ba259c787c17ff5fca00000000",
output_index: 0,
start_timestamp: "2024-09-12T16:32:26Z",
start_height: 861033,
timelock: 5,
},
},
],
pagination: { next_key: "" },
};
54 changes: 54 additions & 0 deletions e2e/staking.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { expect, test } from "@playwright/test";

import {
STAKING_AMOUNT_BTC,
STAKING_AMOUNT_SAT,
STAKING_TX_HASH,
} from "./constants/staking";
import { setupWalletConnection } from "./helper/connect";

test.describe("Create staking transaction", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/");
await setupWalletConnection(page);
});

test("prepare the staking", async ({ page }) => {
const previewButton = page.locator("button").filter({ hasText: "Preview" });

// Selects the first finality provider in the list
await page.locator("#finality-providers>div>div").first().click();
expect(previewButton).toBeDisabled();

// Preview available after filling the amount
await page.getByPlaceholder("BTC").fill(`${STAKING_AMOUNT_BTC}`);
expect(previewButton).toBeEnabled();

await previewButton.click();
const stakeButton = page.locator("button").filter({ hasText: "Stake" });
await stakeButton.click();

// Success modal
const success = page
.getByTestId("modal")
.locator("div")
.filter({ hasText: "Congratulations!" });
expect(success).toBeVisible();

// Check for local storage
const item = await page.evaluate(() =>
localStorage.getItem(
"bbn-staking-delegations-4c6e2954c75bcb53aa13b7cd5d8bcdb4c9a4dd0784d68b115bd4408813b45608",
),
);
expect(item).not.toBeNull();

const parsed = JSON.parse(item as string);
expect(parsed).toHaveLength(1);

// Check the staking delegation tx hash and staking value
const [delegation] = parsed;
expect(delegation.stakingValueSat).toBe(STAKING_AMOUNT_SAT);
expect(delegation.stakingTxHashHex).toBe(STAKING_TX_HASH);
});
});
Loading

0 comments on commit 08b058e

Please sign in to comment.