diff --git a/.env.regtest b/.env.regtest new file mode 100644 index 000000000..07ac3a384 --- /dev/null +++ b/.env.regtest @@ -0,0 +1,18 @@ +# wallet arkade-regtest overrides +ARKD_IMAGE=ghcr.io/arkade-os/arkd:v0.9.1 +ARKD_WALLET_IMAGE=ghcr.io/arkade-os/arkd-wallet:v0.9.1 + +# nbxplorer guard in start-env.sh handles missing container gracefully +BITCOIN_LOW_FEE=true + +# Match wallet's existing arkd config +ARKD_SCHEDULER_TYPE=gocron +ARKD_BOARDING_EXIT_DELAY=1024 +ARKD_SESSION_DURATION=10 +ARKD_LOG_LEVEL=6 + +# Zero fees — faucetOffchain uses wallet.settle() without fee budget +ARK_OFFCHAIN_INPUT_FEE="0.0" +ARK_ONCHAIN_INPUT_FEE="0.0" +ARK_OFFCHAIN_OUTPUT_FEE="0.0" +ARK_ONCHAIN_OUTPUT_FEE="0.0" diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 697a8c307..def8dc8a2 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -7,10 +7,19 @@ on: branches: [master, next] jobs: test: - timeout-minutes: 30 + timeout-minutes: 45 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + submodules: true + - uses: actions/setup-go@v5 + with: + go-version: '1.23' + - uses: actions/cache@v4 + with: + path: regtest/_build + key: nigiri-${{ hashFiles('regtest/.env.defaults', '.env.regtest') }} - uses: actions/setup-node@v4 with: node-version: lts/* @@ -20,14 +29,41 @@ jobs: run: pnpm install - name: Install Playwright Browsers run: pnpm exec playwright install --with-deps - - name: Run Nigiri - uses: vulpemventures/nigiri-github-action@v1 - with: - use_liquid: false - use_ln: true - - name: Setup regtest environment - run: pnpm regtest + - name: Start regtest environment + run: chmod +x regtest/*.sh regtest/helpers/*.sh && ./regtest/start-env.sh + - name: Add nigiri to PATH + run: echo "${{ github.workspace }}/regtest/_build/nigiri/build" >> $GITHUB_PATH + - name: Start nostr relay + run: docker compose -f docker-compose.nak.yml up -d --build + - name: Verify environment + run: pnpm regtest:setup + - name: Diagnostic - dump regtest env state + run: | + echo "=== .env.regtest ===" + cat .env.regtest || echo "no .env.regtest" + echo "=== arkd container env ===" + docker exec ark env 2>/dev/null | grep -E "ARKD_|ARK_|SCHEDULER|CSV|VTXO|ROUND" || true + echo "=== arkd info ===" + curl -s http://localhost:7070/v1/info 2>/dev/null | head -50 || true + echo "=== arkd admin fees ===" + curl -s http://localhost:7070/v1/admin/intentFees 2>/dev/null || true + echo "=== docker ps ===" + docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" || true - name: Run Playwright tests run: sleep 5 && pnpm run test:e2e env: CI: true + - name: Capture logs on failure + if: failure() + run: | + docker logs ark 2>&1 || true + docker logs ark-wallet 2>&1 || true + docker logs boltz 2>&1 || true + docker logs boltz-lnd 2>&1 || true + docker logs boltz-fulmine 2>&1 || true + docker logs nak 2>&1 || true + - name: Cleanup + if: always() + run: | + docker compose -f docker-compose.nak.yml down -v 2>/dev/null || true + chmod +x regtest/*.sh regtest/helpers/*.sh 2>/dev/null; ./regtest/clean-env.sh diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..4320baa95 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "regtest"] + path = regtest + url = https://github.com/ArkLabsHQ/arkade-regtest.git + branch = master diff --git a/arkd.Dockerfile b/arkd.Dockerfile deleted file mode 100644 index 3ef417b63..000000000 --- a/arkd.Dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -# First image used to build the sources -FROM golang:1.25.5 AS builder - -ARG TARGETOS -ARG TARGETARCH -ARG VERSION - -ARG BRANCH=master - -WORKDIR /app - -RUN git clone https://github.com/arkade-os/arkd.git && cd arkd && git checkout ${BRANCH} - -RUN mkdir -p bin && cd arkd && \ - CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \ - go build -ldflags="-X 'main.Version=${VERSION}'" -o /app/bin/arkd ./cmd/arkd - -RUN cd arkd/pkg/ark-cli && \ - CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \ - go build -ldflags="-X 'main.Version=${VERSION}'" -o /app/bin/ark main.go - -# Second image, running the arkd executable -FROM alpine:3.22 - -RUN apk update && apk upgrade - -WORKDIR /app - -COPY --from=builder /app/bin/* /app/ - -ENV PATH="/app:${PATH}" -ENV ARK_DATADIR=/app/data -ENV ARK_WALLET_DATADIR=/app/wallet-data - -# Expose volume containing all 'arkd' data -VOLUME /app/data -VOLUME /app/wallet-data - -ENTRYPOINT [ "arkd" ] \ No newline at end of file diff --git a/arkdwallet.Dockerfile b/arkdwallet.Dockerfile deleted file mode 100644 index 0de9400c9..000000000 --- a/arkdwallet.Dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -# First stage: build the ark-wallet-daemon binary -FROM golang:1.25.5 AS builder - -ARG VERSION -ARG TARGETOS -ARG TARGETARCH - -ARG BRANCH=master - -WORKDIR /app - -RUN git clone https://github.com/arkade-os/arkd.git && cd arkd && git checkout ${BRANCH} - -RUN mkdir -p bin && cd arkd && \ - CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \ - go build -ldflags="-X 'main.Version=${VERSION}'" -o /app/bin/arkd-wallet ./cmd/arkd-wallet/main.go - -# Second stage: minimal runtime image -FROM alpine:3.22 - -RUN apk update && apk upgrade - -WORKDIR /app - -COPY --from=builder /app/bin/arkd-wallet /app/ - -ENV PATH="/app:${PATH}" -ENV ARK_WALLET_DATADIR=/app/wallet-data - -VOLUME /app/wallet-data - -ENTRYPOINT [ "arkd-wallet" ] \ No newline at end of file diff --git a/cors.Dockerfile b/cors.Dockerfile deleted file mode 100644 index 28b3e718b..000000000 --- a/cors.Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM nginx:alpine - -WORKDIR /etc/nginx -COPY ./cors.nginx.conf ./conf.d/default.conf -EXPOSE 9069 -ENTRYPOINT [ "nginx" ] -CMD [ "-g", "daemon off;" ] \ No newline at end of file diff --git a/cors.nginx.conf b/cors.nginx.conf deleted file mode 100644 index 8981dc08b..000000000 --- a/cors.nginx.conf +++ /dev/null @@ -1,48 +0,0 @@ -upstream api { - server boltz:9001; -} - -upstream api2 { - server boltz:9005; -} - -server { - listen 9069; - server_name localhost; - - location /v2/swap/restore { - - if ($request_method = 'OPTIONS') { - add_header 'Access-Control-Max-Age' 1728000; - add_header 'Access-Control-Allow-Origin' '*'; - add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent, - X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; - add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH'; - add_header 'Content-Type' 'application/json'; - add_header 'Content-Length' 0; - return 204; - } - - add_header 'Access-Control-Allow-Origin' '*'; - - proxy_pass http://api2; - } - - location / { - - if ($request_method = 'OPTIONS') { - add_header 'Access-Control-Max-Age' 1728000; - add_header 'Access-Control-Allow-Origin' '*'; - add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent, - X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; - add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH'; - add_header 'Content-Type' 'application/json'; - add_header 'Content-Length' 0; - return 204; - } - - add_header 'Access-Control-Allow-Origin' '*'; - - proxy_pass http://api/; - } -} \ No newline at end of file diff --git a/docker-compose.nak.yml b/docker-compose.nak.yml new file mode 100644 index 000000000..69f1ad940 --- /dev/null +++ b/docker-compose.nak.yml @@ -0,0 +1,15 @@ +name: nigiri +services: + nak: + build: + context: . + dockerfile: nak.Dockerfile + container_name: nak + ports: + - '10547:10547' + command: ['nak', 'serve', '--hostname', '0.0.0.0', '--port', '10547'] + +networks: + default: + name: nigiri + external: true diff --git a/package.json b/package.json index c30dc6697..d4ac4a225 100644 --- a/package.json +++ b/package.json @@ -47,10 +47,9 @@ "format": "prettier --write src", "format:check": "prettier --check src", "git-info": "node scripts/git-commit-info.js", - "regtest": "pnpm regtest:down && pnpm regtest:build && pnpm regtest:up && pnpm regtest:setup", - "regtest:build": "docker compose -f test.docker-compose.yml build", - "regtest:up": "docker compose -f test.docker-compose.yml up arkd arkd-wallet nbxplorer pgnbxplorer -d", - "regtest:down": "docker compose -f test.docker-compose.yml down -v", + "regtest:start": "./regtest/start-env.sh && docker compose -f docker-compose.nak.yml up -d", + "regtest:stop": "./regtest/stop-env.sh && docker compose -f docker-compose.nak.yml down", + "regtest:clean": "./regtest/clean-env.sh && docker compose -f docker-compose.nak.yml down -v", "regtest:setup": "node src/test/setup.mjs" }, "eslintConfig": { diff --git a/regtest b/regtest new file mode 160000 index 000000000..6c5a5408a --- /dev/null +++ b/regtest @@ -0,0 +1 @@ +Subproject commit 6c5a5408a50b049fd7b0dff739bbf28f5848f0dc diff --git a/src/test/e2e/delegate.test.ts b/src/test/e2e/delegate.test.ts index 8726e6ef7..eba159b2f 100644 --- a/src/test/e2e/delegate.test.ts +++ b/src/test/e2e/delegate.test.ts @@ -2,6 +2,7 @@ import { test, expect } from '@playwright/test' import { createWallet, waitForWalletPage } from './utils' test('should toggle delegates', async ({ page }) => { + test.setTimeout(60000) // create wallet await createWallet(page) diff --git a/src/test/e2e/fundedWallet.ts b/src/test/e2e/fundedWallet.ts index 5376b26b0..11e9dcd48 100644 --- a/src/test/e2e/fundedWallet.ts +++ b/src/test/e2e/fundedWallet.ts @@ -33,7 +33,7 @@ const waitForBalance = async ( } const createNote = async (amount: number): Promise => { - const { stdout } = await execAsync(`docker exec -t arkd arkd note --amount ${amount}`) + const { stdout } = await execAsync(`docker exec -t ark arkd note --amount ${amount}`) return stdout.trim() } diff --git a/src/test/e2e/nostr.test.ts b/src/test/e2e/nostr.test.ts index 618c57079..43836f411 100644 --- a/src/test/e2e/nostr.test.ts +++ b/src/test/e2e/nostr.test.ts @@ -25,6 +25,7 @@ const execAsync = promisify(exec) // 9. Restore wallet with nsec key // 10. Verify setting is euro (proving it was restored from nostr) test('should save config to nostr', async ({ page }) => { + test.setTimeout(60000) // create wallet await createWallet(page) diff --git a/src/test/e2e/send.test.ts b/src/test/e2e/send.test.ts index 1b108df32..c8dd83562 100644 --- a/src/test/e2e/send.test.ts +++ b/src/test/e2e/send.test.ts @@ -335,7 +335,7 @@ test('should send to onchain address with collaborative exit', async ({ page, is // since 1000 sats is below the minimum for chain swap, wallet will use collaborative exit to send onchain test('should send MAX to onchain address with collaborative exit', async ({ page }) => { // set fees - execSync('docker exec -t arkd arkd fees intent --onchain-output "200.0"') + execSync('docker exec -t ark arkd fees intent --onchain-output "200.0"') // create wallet await createWallet(page) @@ -386,5 +386,5 @@ test('should send MAX to onchain address with collaborative exit', async ({ page await expect(page.getByText('Sent')).toBeVisible() // clear fees - execSync('docker exec -t arkd arkd fees clear') + execSync('docker exec -t ark arkd fees clear') }) diff --git a/src/test/e2e/swap.test.ts b/src/test/e2e/swap.test.ts index 9542aa14c..89659e313 100644 --- a/src/test/e2e/swap.test.ts +++ b/src/test/e2e/swap.test.ts @@ -170,7 +170,7 @@ test('should receive bitcoin funds from swap', async ({ page, isMobile }) => { test('should send funds to onchain address via swap', async ({ page, isMobile }) => { test.setTimeout(120000) // set fees - execSync('docker exec -t arkd arkd fees intent --onchain-output "200.0"') + execSync('docker exec -t ark arkd fees intent --onchain-output "200.0"') // create wallet await createWallet(page) @@ -202,5 +202,5 @@ test('should send funds to onchain address via swap', async ({ page, isMobile }) await expect(page.getByText('Sent')).toBeVisible() // clear fees - execSync('docker exec -t arkd arkd fees clear') + execSync('docker exec -t ark arkd fees clear') }) diff --git a/src/test/setup.mjs b/src/test/setup.mjs index f962199c7..29125d5bb 100644 --- a/src/test/setup.mjs +++ b/src/test/setup.mjs @@ -2,35 +2,27 @@ import { promisify } from 'util' import { setTimeout } from 'timers' import { execSync } from 'child_process' -const arkdExec = 'docker exec -t arkd' -const lncli = 'docker exec -i boltz-lnd lncli --network=regtest' - const sleep = promisify(setTimeout) -async function execCommand(command, silent = false) { - return new Promise((resolve, reject) => { - try { - const options = silent ? { stdio: 'pipe', encoding: 'utf8' } : { encoding: 'utf8' } - const result = execSync(command, options).toString().trim() - resolve(result) - } catch (error) { - // If the error indicates the wallet is already initialized, we can continue - if (error.stderr && error.stderr.toString().includes('wallet already initialized')) { - console.log('Wallet already initialized, continuing...') - resolve('') - } else { - reject(error) - } +function execCommand(command, silent = false) { + try { + const options = silent ? { stdio: 'pipe', encoding: 'utf8' } : { encoding: 'utf8' } + return execSync(command, options).toString().trim() + } catch (error) { + if (error.stderr && error.stderr.toString().includes('wallet already initialized')) { + console.log('Wallet already initialized, continuing...') + return '' } - }) + throw error + } } -async function waitForArkServer(maxRetries = 30, retryDelay = 2000) { - console.log('Waiting for ark server to be ready...') +async function waitForService(name, checkCmd, maxRetries = 30, retryDelay = 2000) { + console.log(`Waiting for ${name} to be ready...`) for (let i = 0; i < maxRetries; i++) { try { - execSync('curl -s http://localhost:7070/v1/info', { stdio: 'pipe' }) - console.log(' ✔ Server ready') + execSync(checkCmd, { stdio: 'pipe' }) + console.log(` ✔ ${name} ready`) return true } catch { if (i < maxRetries - 1) { @@ -39,291 +31,32 @@ async function waitForArkServer(maxRetries = 30, retryDelay = 2000) { await sleep(retryDelay) } } - throw new Error('ark server failed to be ready after maximum retries') -} - -async function checkWalletStatus(maxRetries = 30, retryDelay = 2000) { - const cmd = `${arkdExec} arkd wallet status` - for (let i = 0; i < maxRetries; i++) { - try { - const statusOutput = execSync(cmd, { stdio: 'pipe' }).toString() - const initialized = statusOutput.includes('initialized: true') - const unlocked = statusOutput.includes('unlocked: true') - const synced = statusOutput.includes('synced: true') - return { initialized, unlocked, synced } - } catch { - await sleep(retryDelay) - } - } -} - -async function waitForWalletReady(maxRetries = 30, retryDelay = 2000) { - console.log('Waiting for wallet to be ready and synced...') - for (let i = 0; i < maxRetries; i++) { - const status = await checkWalletStatus() - if (status && status.initialized && status.unlocked && status.synced) { - console.log(' ✔ Wallet ready and synced') - return true - } - if (i < maxRetries - 1) { - console.log(` Waiting... (${i + 1}/${maxRetries})`) - } - await sleep(retryDelay) - } - throw new Error('Wallet failed to be ready after maximum retries') -} - -async function waitForCmd(command, maxRetries = 10, retryDelay = 1000) { - for (let i = 1; i <= maxRetries; i++) { - try { - execSync(command, { stdio: 'pipe' }) - console.log(' ✔ Ready') - return true - } catch { - if (i < maxRetries) { - console.log(` Waiting... (${i}/${maxRetries})`) - } - await sleep(retryDelay) - } - } - throw new Error(`Timed out waiting for command after ${(maxRetries * retryDelay) / 1000} seconds.`) + throw new Error(`${name} failed to be ready after maximum retries`) } -async function faucet(address, amount, maxRetries = 10, retryDelay = 1000) { - const initialCountResponse = execSync(`curl -s http://localhost:3000/address/${address}`, { encoding: 'utf8' }) - const initialCount = JSON.parse(initialCountResponse).chain_stats.tx_count - - const txid = execSync(`nigiri faucet ${address} ${amount}`, { encoding: 'utf8', stdio: 'pipe' }).trim() - console.log(` Transaction ID: ${txid}`) - - for (let i = 1; i <= maxRetries; i++) { - await sleep(retryDelay) - try { - const newCountResponse = execSync(`curl -s http://localhost:3000/address/${address}`, { encoding: 'utf8' }) - const newCount = JSON.parse(newCountResponse).chain_stats.tx_count - if (newCount > initialCount) { - console.log(' ✔ Confirmed') - return txid - } - } catch { - // Continue retrying - } - if (i < maxRetries) { - console.log(` Waiting for confirmation (${i}/${maxRetries})...`) - } - } - throw new Error(`Timed out waiting for faucet transaction to confirm.`) -} - -async function waitForArkReady(maxRetries = 10, retryDelay = 1000) { - const cmd = 'docker exec arkd arkd wallet status' - return waitForCmd(cmd, maxRetries, retryDelay) -} - -async function setupArkServer() { +async function setup() { try { console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━') - console.log(' Setting up ark server') + console.log(' Verifying regtest environment') console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n') - // Wait for ark server to be ready first - await waitForArkServer() + // Verify arkd is serving + await waitForService('arkd', 'curl -sf http://localhost:7070/v1/info') - // nigiri already initializes arkd - // Create and unlock arkd wallet - console.log('Creating ark wallet...') - await execCommand(`${arkdExec} arkd wallet create --password secret`, true) - console.log(' ✔ Wallet created') - - console.log('Unlocking ark wallet...') - await execCommand(`${arkdExec} arkd wallet unlock --password secret`, true) - console.log(' ✔ Wallet unlocked') - - // Wait for wallet to be ready and synced - await waitForWalletReady() - - // Get and log the server info const serverInfo = JSON.parse(execSync('curl -s http://localhost:7070/v1/info').toString()) - console.log(`\nark Server Public Key: ${serverInfo.signerPubkey}`) - - // Get arkd address and fund it with nigiri faucet - console.log('\nFunding ark wallet...') - const arkdAddress = await execCommand(`${arkdExec} arkd wallet address`) - console.log(` Address: ${arkdAddress}`) - - for (let i = 0; i < 10; i++) { - await execCommand(`nigiri faucet ${arkdAddress}`, true) - } - console.log(' ✔ Funded with 10 BTC') + console.log(`\narkd Public Key: ${serverInfo.signerPubkey}`) - // Wait for transaction to be confirmed - await sleep(5000) + // Verify boltz pairs are loaded + await waitForService('boltz', 'curl -sf http://localhost:9069/v2/swap/submarine') - // Initialize ark client - console.log('\nInitializing ark client...') - await execCommand( - `${arkdExec} ark init --server-url http://localhost:7070 --explorer http://chopsticks:3000 --password secret`, - true, - ) - console.log(' ✔ Client initialized') + // Verify nostr relay (nak is a WebSocket server, check container is running) + await waitForService('nak', 'docker exec nak nak --version', 10, 1000) - // fund the ark-cli with 1 vtxo worth of 2000000 - console.log('\nCreating and redeeming notes...') - const note = await execCommand(`${arkdExec} arkd note --amount 2000000`) - const cmd = `${arkdExec} ark redeem-notes -n ${note} --password secret` - await execCommand(cmd, true) - console.log(' ✔ Notes redeemed') - - console.log('\n✔ ark server and client setup completed') - } catch (error) { - console.error('\n✗ Error setting up ark server:', error) - throw error - } -} - -async function setupBoltz() { - try { - console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━') - console.log(' Setting up Boltz') - console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n') - - console.log('Waiting for LND to be ready...') - await waitForCmd('docker exec lnd lncli --network=regtest getinfo') - - await sleep(2000) - - console.log('\nFunding LND...') - await execCommand('nigiri faucet lnd 1', true) - console.log(' ✔ Funded') - - console.log('\nStarting Boltz LND container...') - await execCommand('docker compose -f test.docker-compose.yml up -d boltz-lnd', true) - console.log(' ✔ Container started') - - console.log('\nWaiting for Boltz LND to be ready...') - await waitForCmd('docker exec boltz-lnd lncli --network=regtest getinfo') - - console.log('\nFunding Boltz LND...') - const addressResponse = execSync(`${lncli} newaddress p2wkh`, { encoding: 'utf8' }) - const address = JSON.parse(addressResponse).address - console.log(` Address: ${address}`) - await faucet(address, 1) - - console.log('\nConnecting LND instances...') - const nigiriInfoResponse = execSync('docker exec lnd lncli --network=regtest getinfo', { encoding: 'utf8' }) - const nigiriPubkey = JSON.parse(nigiriInfoResponse).identity_pubkey - await execCommand(`${lncli} connect ${nigiriPubkey}@lnd:9735`, true) - - // Check if peers are connected - const boltzPeersResponse = execSync(`${lncli} listpeers`, { encoding: 'utf8' }) - const nigiriPeersResponse = execSync('docker exec lnd lncli --network=regtest listpeers', { encoding: 'utf8' }) - const boltzPeersCount = JSON.parse(boltzPeersResponse).peers?.length || 0 - const nigiriPeersCount = JSON.parse(nigiriPeersResponse).peers?.length || 0 - - if (boltzPeersCount === 1 && nigiriPeersCount === 1) { - console.log(' ✔ Instances connected') - } else { - console.error(' ✗ Error connecting instances') - process.exit(1) - } - - console.log('\nOpening channel between LND instances...') - await execCommand(`${lncli} openchannel --node_key="${nigiriPubkey}" --local_amt=1000000`, true) - console.log(' ✔ Channel opened (1M sats)') - - console.log('\nMining blocks to mature channel...') - await execCommand('nigiri rpc --generate 10', true) - console.log(' ✔ 10 blocks mined') - await sleep(5000) - - console.log('\nBalancing channel...') - const invoiceResponse = execSync('docker exec lnd lncli --network=regtest addinvoice --amt 500000', { - encoding: 'utf8', - }) - const invoice = JSON.parse(invoiceResponse).payment_request - await execCommand(`${lncli} payinvoice --force ${invoice}`, true) - console.log(' ✔ Channel balanced (500k sats each side)') - - console.log('\nWaiting for ark to be ready...') - await waitForArkReady() - - console.log('\nStarting Fulmine container...') - await execCommand('docker compose -f test.docker-compose.yml up -d boltz-fulmine', true) - console.log(' ✔ Container started') - await sleep(5000) - - console.log('\nCreating Fulmine wallet...') - await execCommand( - `curl -s -X POST http://localhost:7001/api/v1/wallet/create -H "Content-Type: application/json" -d '{"private_key": "5b9902c1098cc0f4c7e91066ef3227e292d994a50ebc33961ac6daa656fd242e", "password": "password", "server_url": "http://arkd:7070"}'`, - true, - ) - console.log(' ✔ Wallet created') - - await sleep(5000) - - console.log('\nUnlocking Fulmine wallet...') - await execCommand( - `curl -s -X POST http://localhost:7001/api/v1/wallet/unlock -H "Content-Type: application/json" -d '{"password": "password"}'`, - true, - ) - console.log(' ✔ Wallet unlocked') - - await sleep(2000) - - console.log('\nGetting Fulmine address...') - const fulmineAddressResponse = execSync('curl -s -X GET http://localhost:7001/api/v1/address', { encoding: 'utf8' }) - const fulmineAddress = JSON.parse(fulmineAddressResponse).address.split('?')[0].split(':')[1] - console.log(` Address: ${fulmineAddress}`) - - console.log('\nFunding Fulmine address...') - await faucet(fulmineAddress, 1) - - await sleep(2000) - - console.log('\nSettling funds in Fulmine...') - await execCommand('curl -s -X GET http://localhost:7001/api/v1/settle', true) - console.log(' ✔ Funds settled') - - console.log('\nStarting Boltz backend and PostgreSQL...') - await execCommand('docker compose -f test.docker-compose.yml up -d boltz-postgres boltz', true) - console.log(' ✔ Containers started') - - console.log('\nStarting CORS proxy...') - await execCommand('docker compose -f test.docker-compose.yml up -d cors', true) - console.log(' ✔ Container started') - - console.log('\n✔ Boltz setup completed') - } catch (error) { - console.error('\n✗ Error setting up Boltz:', error) - throw error - } -} - -async function setupNostr() { - try { - console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━') - console.log(' Setting up Nostr') - console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n') - console.log('Starting nostr relay on ws://localhost:10547...') - await execCommand('docker compose -f test.docker-compose.yml up -d nak', true) - console.log(' ✔ Container started') - } catch (error) { - console.error('\n✗ Error setting up Nostr:', error) - throw error - } -} - -// Run setup -async function setup() { - try { - await setupArkServer() - await setupBoltz() - await setupNostr() console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━') - console.log(' ✓ regtest setup completed successfully') + console.log(' ✓ regtest environment verified') console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n') } catch (error) { - console.error('\n✗ Setup failed:', error) + console.error('\n✗ Setup verification failed:', error) process.exit(1) } } diff --git a/test.docker-compose.yml b/test.docker-compose.yml deleted file mode 100644 index 43f0dffbd..000000000 --- a/test.docker-compose.yml +++ /dev/null @@ -1,286 +0,0 @@ -services: - pgnbxplorer: - restart: unless-stopped - image: postgres:16 - container_name: pgnbxplorer - ports: - - 5432:5432 - environment: - - POSTGRES_HOST_AUTH_METHOD=trust - volumes: - - type: tmpfs - target: /var/lib/postgresql/data - healthcheck: - test: ['CMD-SHELL', 'pg_isready -U postgres -d nbxplorer -h 127.0.0.1 -p 5432'] - interval: 2s - timeout: 2s - retries: 30 - nbxplorer: - restart: unless-stopped - container_name: nbxplorer - ports: - - 32838:32838 - image: nicolasdorier/nbxplorer:2.5.30 - environment: - - NBXPLORER_NETWORK=regtest - - NBXPLORER_CHAINS=btc - - NBXPLORER_BTCRPCURL=http://bitcoin:18443 - - NBXPLORER_BTCNODEENDPOINT=bitcoin:18444 - - NBXPLORER_BTCRPCUSER=admin1 - - NBXPLORER_BTCRPCPASSWORD=123 - - NBXPLORER_VERBOSE=1 - - NBXPLORER_BIND=0.0.0.0:32838 - - NBXPLORER_TRIMEVENTS=10000 - - NBXPLORER_SIGNALFILESDIR=/datadir - - NBXPLORER_POSTGRES=User ID=postgres;Host=pgnbxplorer;Port=5432;Application Name=nbxplorer;MaxPoolSize=20;Database=nbxplorer - - NBXPLORER_EXPOSERPC=1 - - NBXPLORER_NOAUTH=1 - volumes: - - type: tmpfs - target: /datadir - depends_on: - pgnbxplorer: - condition: service_healthy - arkd-wallet: - restart: unless-stopped - image: ghcr.io/arkade-os/arkd-wallet:v0.9.1 - container_name: arkd-wallet - depends_on: - - nbxplorer - ports: - - '6060:6060' - environment: - - ARKD_WALLET_LOG_LEVEL=5 - - ARKD_WALLET_NBXPLORER_URL=http://nbxplorer:32838 - - ARKD_WALLET_DATADIR=./data/regtest - - ARKD_WALLET_NETWORK=regtest - - ARKD_WALLET_SIGNER_KEY=afcd3fa10f82a05fddc9574fdb13b3991b568e89cc39a72ba4401df8abef35f0 - volumes: - - type: tmpfs - target: /app/data - arkd: - image: ghcr.io/arkade-os/arkd:v0.9.1 - container_name: arkd - restart: unless-stopped - depends_on: - - arkd-wallet - ports: - - '7070:7070' - environment: - - ARKD_LOG_LEVEL=6 - - ARKD_NO_MACAROONS=true - - ARKD_UNILATERAL_EXIT_DELAY=512 - - ARKD_BOARDING_EXIT_DELAY=1024 - - ARKD_DATADIR=./data/regtest - - ARKD_WALLET_ADDR=arkd-wallet:6060 - - ARKD_ESPLORA_URL=http://chopsticks:3000 - - ARKD_VTXO_MIN_AMOUNT=1 - - ARKD_LIVE_STORE_TYPE=inmemory - - ARKD_EVENT_DB_TYPE=badger - - ARKD_DB_TYPE=sqlite - - ARKD_SESSION_DURATION=10 - volumes: - - type: tmpfs - target: /app/data - - boltz-lnd: - image: lightninglabs/lnd:v0.19.1-beta - restart: unless-stopped - container_name: boltz-lnd - command: - - '--bitcoin.regtest' - - '--bitcoin.node=bitcoind' - - '--maxpendingchannels=10' - - '--rpclisten=0.0.0.0:10009' - - '--bitcoind.rpchost=bitcoin:18443' - - '--bitcoind.rpcuser=admin1' - - '--bitcoind.rpcpass=123' - - '--bitcoind.zmqpubrawblock=tcp://bitcoin:28332' - - '--bitcoind.zmqpubrawtx=tcp://bitcoin:28333' - - '--db.bolt.auto-compact' - - '--db.prune-revocation' - - '--alias=Ark Labs' - - '--tlsextradomain=boltz-lnd' - - '--protocol.option-scid-alias' - - '--protocol.wumbo-channels' - - '--accept-keysend' - - '--minchansize=25000' - - '--noseedbackup' - - '--gc-canceled-invoices-on-startup' - - '--coin-selection-strategy=random' - - '--protocol.custom-message=513' - - '--protocol.custom-nodeann=39' - - '--protocol.custom-init=39' - - '--no-rest-tls' - - '--restcors=*' - volumes: - - lnd_datadir:/root/.lnd - ports: - - '9736:9735' - - '10010:10009' - boltz: - container_name: boltz - restart: unless-stopped - image: boltz/boltz:latest - pull_policy: always - ports: - - '9000:9000' - - '9001:9001' - - '9004:9004' - - '9005:9005' - expose: - - '9001' - environment: - BOLTZ_CONFIG: | - loglevel = "debug" - network = "regtest" - [ark] - host = "boltz-fulmine" - port = 7000 - useLocktimeSeconds = true - - [ark.unilateralDelays] - claim = 444 # 3d.2h in blocks - refund = 444 # 3d.2h in blocks - refundWithoutReceiver = 720 # 5d in blocks - - [api] - host = "0.0.0.0" - port = 9001 - cors = "*" - - [grpc] - host = "0.0.0.0" - port = 9000 - - [sidecar] - [sidecar.grpc] - host = "0.0.0.0" - port = 9003 - - [sidecar.ws] - host = "0.0.0.0" - port = 9004 - - [sidecar.api] - host = "0.0.0.0" - port = 9005 - - [postgres] - host = "boltz-postgres" - port = 5432 - database = "boltz" - username = "postgres" - password = "postgres" - - [swap] - deferredClaimSymbols = [ "BTC" ] - - [[pairs]] - base = "ARK" - quote = "BTC" - rate = 1 - fee = 0.4 - swapInFee = 0.01 - invoiceExpiry = 361 - maxSwapAmount = 4294967 - minSwapAmount = 1000 - - [pairs.timeoutDelta] - reverse = 1440 - chain=1440 - swapMinimal = 1440 - swapMaximal = 2880 - swapTaproot = 10080 - - [[currencies]] - symbol = "BTC" - network = "bitcoinRegtest" - minWalletBalance = 10000000 - minLocalBalance = 10000000 - minRemoteBalance = 10000000 - maxSwapAmount = 4294967 - minSwapAmount = 50000 - maxZeroConfAmount = 100000 - preferredWallet = "core" - - [currencies.chain] - host = "bitcoin" - port = 18443 - user = "admin1" - password = "123" - zmqpubrawtx = "tcp://bitcoin:28333" - zmqpubrawblock = "tcp://bitcoin:28332" - - [[currencies.lnds]] - host = "boltz-lnd" - port = 10009 - certpath = "/home/boltz/.lnd/tls.cert" - macaroonpath = "/home/boltz/.lnd/data/chain/bitcoin/regtest/admin.macaroon" - volumes: - - boltz_datadir:/home/boltz/.boltz - - lnd_datadir:/home/boltz/.lnd - entrypoint: sh -c 'echo "$$BOLTZ_CONFIG" > /home/boltz/.boltz/boltz.config && boltzd --datadir /home/boltz/.boltz --configpath /home/boltz/.boltz/boltz.config' - boltz-postgres: - image: postgres:15.4 - restart: unless-stopped - environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: boltz - POSTGRES_HOST_AUTH_METHOD: trust - expose: - - '5432' - volumes: - - postgres_datadir:/var/lib/postgresql/data - boltz-fulmine: - image: ghcr.io/arklabshq/fulmine:v0.3.15 - container_name: boltz-fulmine - environment: - - FULMINE_LOG_LEVEL=5 - - FULMINE_NO_MACAROONS=true - - FULMINE_DELEGATOR_FEE=350 - - FULMINE_DELEGATOR_ENABLED=true - - FULMINE_DELEGATOR_ENABLED=true - - FULMINE_DISABLE_TELEMETRY=true - - FULMINE_ARK_SERVER=http://arkd:7070 - - FULMINE_ESPLORA_URL=http://chopsticks:3000 - ports: - - '7000:7000' - - '7001:7001' - - '7002:7002' - volumes: - - bitcoin_fulmine_data:/app/data - restart: unless-stopped - cors: - build: - context: . - dockerfile: cors.Dockerfile - container_name: cors - depends_on: - - boltz - ports: - - '9069:9069' - nak: - build: - context: . - dockerfile: nak.Dockerfile - container_name: nak - ports: - - '10547:10547' - command: ['nak', 'serve', '--hostname', '0.0.0.0', '--port', '10547'] - -volumes: - postgres_datadir: - name: postgres_datadir - boltz_datadir: - name: boltz_datadir - bitcoin_fulmine_data: - name: bitcoin_fulmine_data - lnd_datadir: - name: lnd_datadir - -networks: - default: - name: nigiri - external: true