-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
83 changed files
with
7,210 additions
and
2,729 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
v22.6.0 | ||
v22.3.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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), | ||
}); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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: "" }, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}); | ||
}); |
Oops, something went wrong.