Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/142 provide spendable reveal and reclaim paths #143

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 5 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"vitest-fetch-mock": "^0.2.1"
},
"dependencies": {
"@noble/curves": "^1.0.0",
"@noble/secp256k1": "^2.0.0",
"@scure/base": "^1.1.1",
"@scure/bip32": "^1.3.0",
Expand All @@ -71,7 +72,7 @@
"postcss-cli": "^10.0.0",
"process": "^0.11.10",
"readable-stream": "^4.3.0",
"sbtc-bridge-lib": "^1.0.11",
"sbtc-bridge-lib": "^1.0.12",
"svelte-bootstrap-icons": "^2.3.1",
"svelte-json-tree": "^1.0.0",
"svelte-local-storage-store": "^0.4.0",
Expand Down
57 changes: 54 additions & 3 deletions src/lib/bridge_api.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { CONFIG } from '$lib/config';
import type { PeginRequestI } from 'sbtc-bridge-lib'
import type { PeginRequestI, WrappedPSBT } from 'sbtc-bridge-lib'

function addNetSelector (path:string) {
if (CONFIG.VITE_NETWORK === 'testnet' || CONFIG.VITE_NETWORK === 'devnet') {
return path.replace('bridge-api', 'bridge-api/testnet');
}
else {
} else {
return path.replace('bridge-api', 'bridge-api/mainnet');
}
}
Expand Down Expand Up @@ -59,6 +58,58 @@ export async function sendRawTransaction(tx: { hex: string; }) {
return await extractResponse(response);
}

export async function fetchKeys() {
const path = addNetSelector(CONFIG.VITE_BRIDGE_API + '/btc/tx/keys');
const response = await fetch(path);
if (response.status !== 200) {
throw new Error('Bitcoin address not known - is the network correct?');
}
const res = await extractResponse(response);
return res;
}

export async function signAndBroadcast(wrappedPsbt:WrappedPSBT) {
const path = addNetSelector(CONFIG.VITE_BRIDGE_API + '/btc/tx/signAndBroadcast');
const response = await fetch(path, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(wrappedPsbt)
});
let res:any;
try {
res = await response.json();
} catch (err) {
try {
console.log(err)
res = await response.text();
} catch (err1) {
console.log(err1)
}
}
return res;
}

export async function sign(wrappedPsbt:WrappedPSBT) {
const path = addNetSelector(CONFIG.VITE_BRIDGE_API + '/btc/tx/sign');
const response = await fetch(path, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(wrappedPsbt)
});
let res:any;
try {
res = await response.json();
} catch (err) {
try {
console.log(err)
res = await response.text();
} catch (err1) {
console.log(err1)
}
}
return res;
}

export async function fetchBurnBlockCount() {
const path = addNetSelector(CONFIG.VITE_BRIDGE_API + '/btc/blocks/count');
const response = await fetch(path);
Expand Down
8 changes: 4 additions & 4 deletions src/lib/components/common/UTXOSelection.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ let showUtxos:boolean;
let showDebugInfo = $sbtcConfig.userSettings.debugMode;

const useWebWallet = async () => {
bitcoinAddress = addresses().ordinal;
bitcoinAddress = addresses().cardinal;
configureUTXOs(true);
}

const isWebWallet = async () => {
return (bitcoinAddress === addresses().ordinal);
return (bitcoinAddress === addresses().cardinal);
}

const configureUTXOs = async (force:boolean) => {
Expand All @@ -38,7 +38,7 @@ const configureUTXOs = async (force:boolean) => {
try {
isSupported(bitcoinAddress);
} catch (err:any) {
//bitcoinAddress = addresses().ordinal;
//bitcoinAddress = addresses().cardinal;
errorReason = 'Unsupported bitcoin address - the reclaim feature currently requires a taproot (segwit v1) bitcoin addresses.';
return;
}
Expand Down Expand Up @@ -86,7 +86,7 @@ onMount(async () => {
{#if bitcoinAddress && errorReason}
<div>
<div class="text-warning">{errorReason}
<a href="/" class="text-underline text-warning" style="text-transform: uppercase" on:click|preventDefault={() => useWebWallet()}>reset address to your web wallet ordinal (taproot) address</a>
<a href="/" class="text-underline text-warning" style="text-transform: uppercase" on:click|preventDefault={() => useWebWallet()}>reset address to your web wallet cardinal (taproot) address</a>
</div>
</div>
{/if}
Expand Down
84 changes: 4 additions & 80 deletions src/lib/components/reclaim/TrCommit.svelte
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
<script lang="ts">
import { onMount } from 'svelte';
import { tsToDate, truncate, explorerBtcTxUrl, explorerBtcAddressUrl } from '$lib/utils'
import { tsToDate, explorerBtcTxUrl, explorerBtcAddressUrl } from '$lib/utils'
import * as btc from '@scure/btc-signer';
import type { PeginRequestI } from 'sbtc-bridge-lib'
import { CONFIG } from '$lib/config';
import { addressFromPubkey, parseDepositPayload } from 'sbtc-bridge-lib'
import TxExport from './TxExport.svelte';
import { sbtcConfig } from '$stores/stores'
import { parseDepositPayload } from 'sbtc-bridge-lib'

export let peginRequest:PeginRequestI;
export let reclaimBtcTx:btc.Transaction;
export let revealBtcTx:btc.Transaction;
let stacksData:any;
let intid = false;
let showCommitDetails = false;
Expand All @@ -22,38 +17,20 @@ onMount(() => {
const revealScript = btc.Script.decode(peginRequest.commitTxScript?.leaves[0].script);
const reclaimScript = btc.Script.decode(peginRequest.commitTxScript?.leaves[1].script);
for (let part of reclaimScript) {
if (typeof part === 'object') {
reclaimString += addressFromPubkey(CONFIG.VITE_NETWORK, part) + ' ';
} else {
reclaimString += part + ' ';
}
reclaimString += part + ' ';
}

let count = 0;
for (let part of revealScript) {
if (count === 0) {
revealString += '<stacks_data> ';
} else {
if (typeof part === 'object') {
revealString += addressFromPubkey(CONFIG.VITE_NETWORK, part) + ' ';
} else {
revealString += part + ' ';
}
revealString += part + ' ';
}
count++;
}
const amt = (peginRequest.vout && peginRequest.vout.value) ? peginRequest.vout.value : peginRequest.amount;
stacksData = parseDepositPayload(revealScript[0].valueOf() as Uint8Array, amt);
/**
const d1U = stacksData;
d3 = hex.encode(stacksData);
const index = 0;
const addr0 = parseInt(hex.encode(d1U.subarray(index + 1, index + 2)), 16);
const addr1 = hex.encode(d1U.subarray(index + 2, index + 22));
stacksAddress = c32address(addr0, addr1);
cnameBuf = new TextDecoder().decode(d1U.subarray(index + 22, index + 56));
revealFee = parseInt(hex.encode(d1U.subarray(index + 56, index + 84)), 16);
*/
} catch(err) {
console.log(err)
}
Expand All @@ -65,12 +42,6 @@ onMount(() => {
{#if intid}
<div class="row ">
<div class="col-12 mt-0 mb-2">Commitment Transaction: {tsToDate(peginRequest.updated)}</div>
<!--
{#each scriptElements as element}
<div class="col-md-2 col-sm-12 text-info">{element.key}</div>
<div class="col-md-10 col-sm-12">{element.value}</div>
{/each}
-->
{#if peginRequest.btcTxid}
<div class="col-md-2 col-sm-12 text-info">Sent To</div><div class="col-md-10 col-sm-12">
<a href={explorerBtcTxUrl(peginRequest.btcTxid)} target="_blank" rel="noreferrer">{(peginRequest.commitTxScript?.address)}</a>
Expand All @@ -86,58 +57,11 @@ onMount(() => {
<a href={explorerBtcTxUrl(peginRequest.reveal?.btcTxid)} target="_blank" rel="noreferrer">{(peginRequest.reveal?.btcTxid)}</a>
</div>
{/if}
<div class="col-12 text-start"><span class="pointer" on:keypress on:click={() => showCommitDetails = !showCommitDetails}>show details</span></div>
{:else}
<div class="col-md-2 col-sm-12 text-info">Sends To</div><div class="col-md-10 col-sm-12">
<a href={explorerBtcAddressUrl(peginRequest.commitTxScript?.address || '')} target="_blank" rel="noreferrer">{(peginRequest.commitTxScript?.address)}</a>
</div>
{/if}

{#if showCommitDetails}
<div class="mt-4 col-12">Reclaim Data</div>
<div class="col-md-2 col-sm-12 text-info">Reclaim Address</div><div class="col-md-10 col-sm-12">{peginRequest.fromBtcAddress}</div>
{#if stacksData && $sbtcConfig.userSettings.debugMode}
<div class="col-md-2 col-sm-12 text-info">Reclaim Pub Key</div><div class="col-md-10 col-sm-12">{peginRequest.reclaimPub}</div>
<div class="col-md-2 col-sm-12 text-info">Reclaim Script</div><div class="col-md-10 col-sm-12">{reclaimString}</div>
{/if}
{#if peginRequest.status < 3}
<TxExport btcTx={reclaimBtcTx} txtype={'reclaim'} amount={peginRequest.vout?.value || 0}/>
{/if}
<div class="mt-4 col-12">Reveal Data</div>
<div class="col-md-2 col-sm-12 text-info">Sbtc Address</div><div class="col-md-10 col-sm-12">{peginRequest.sbtcWalletAddress}</div>
{#if stacksData && $sbtcConfig.userSettings.debugMode}
<div class="col-md-2 col-sm-12 text-info">Reveal Pub Key</div><div class="col-md-10 col-sm-12">{peginRequest.revealPub}</div>
<div class="col-md-2 col-sm-12 text-info">Reveal Script</div><div class="col-md-10 col-sm-12">{revealString}</div>
{/if}
<div class="mt-4 col-12 text-info"></div>
{#if peginRequest.status < 3}
<TxExport btcTx={revealBtcTx} txtype={'reveal'} amount={peginRequest.vout?.value || 0}/>
{/if}
{#if stacksData && $sbtcConfig.userSettings.debugMode}
<div class="mt-4 col-12">Stacks Data</div>
<div class="col-md-2 col-sm-12 text-info">Op Code</div><div class="col-md-10 col-sm-12">{stacksData.opcode}</div>
<div class="col-md-2 col-sm-12 text-info">Address</div><div class="col-md-10 col-sm-12">{stacksData.stacksAddress}</div>
<div class="col-md-2 col-sm-12 text-info">Contract Name</div><div class="col-md-10 col-sm-12">{stacksData.cname || 'n/a'}</div>
<div class="col-md-2 col-sm-12 text-info">Memo</div><div class="col-md-10 col-sm-12">{stacksData.memo || 'n/a'}</div>
<div class="col-md-2 col-sm-12 text-info">Reveal Fee</div><div class="col-md-10 col-sm-12">{stacksData.revealFee}</div>
{/if}
{/if}
<!--
<div class="col-md-2 col-sm-12 text-info">Stacks addr</div><div class="col-md-10 col-sm-12">{stacksAddress}</div>
<div class="col-md-2 col-sm-12 text-info">Stacks contract</div><div class="col-md-10 col-sm-12">{cnameBuf}</div>
<div class="col-md-2 col-sm-12 text-info">Reveal Fee</div><div class="col-md-10 col-sm-12">{revealFee}</div>
<div class="col-md-2 col-sm-12 text-info">For</div><div class="col-md-10 col-sm-12">{peginRequest.amount} Sats</div>
<div class="col-md-2 col-sm-12 text-info">SBTC Wallet</div><div class="col-md-10 col-sm-12">{peginRequest.sbtcWalletAddress}</div>
<div class="col-12 mt-4 mb-2">Witness Data</div>
<div class="col-md-2 col-sm-12 text-info">Full Script</div><div class="col-md-10 col-sm-12">{peginRequest.commitTxScript?.witnessScript}</div>
<div class="col-md-2 col-sm-12 text-info">Witness Script</div><div class="col-md-10 col-sm-12">{d1}<br/>{d2}<br/>{d3}</div>
<div class="col-12 mt-4 mb-2">Commit Transaction</div>
<div class="col-md-2 col-sm-12 text-info">scriptpubkey_type</div><div class="col-md-10 col-sm-12">{peginRequest.vout?.scriptpubkey_type}</div>
<div class="col-md-2 col-sm-12 text-info">scriptpubkey</div><div class="col-md-10 col-sm-12">{peginRequest.vout?.scriptpubkey}</div>
<div class="col-md-2 col-sm-12 text-info">scriptpubkey_asm</div><div class="col-md-10 col-sm-12">{peginRequest.vout?.scriptpubkey_asm}</div>
<div class="col-md-2 col-sm-12 text-info">scriptpubkey_address</div><div class="col-md-10 col-sm-12">{peginRequest.vout?.scriptpubkey_address}</div>
<div class="col-md-2 col-sm-12 text-info">value</div><div class="col-md-10 col-sm-12">{peginRequest.vout?.value}</div>
-->
</div>
{/if}

Expand Down
86 changes: 86 additions & 0 deletions src/lib/components/reclaim/TrRevealReclaim.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<script lang="ts">
import { onMount } from 'svelte';
import { tsToDate } from '$lib/utils'
import * as btc from '@scure/btc-signer';
import type { PeginRequestI } from 'sbtc-bridge-lib'
import { parseDepositPayload } from 'sbtc-bridge-lib'
import TxExport from './TxExport.svelte';
import { sbtcConfig } from '$stores/stores'

export let peginRequest:PeginRequestI;
export let reclaimBtcTx:btc.Transaction;
export let revealBtcTx:btc.Transaction;
let stacksData:any;
let intid = false;
let showCommitDetails = false;

let reclaimString = '';
let revealString = '';
onMount(() => {
try {
const revealScript = btc.Script.decode(peginRequest.commitTxScript?.leaves[0].script);
const reclaimScript = btc.Script.decode(peginRequest.commitTxScript?.leaves[1].script);
for (let part of reclaimScript) {
reclaimString += part + ' ';
}

let count = 0;
for (let part of revealScript) {
if (count === 0) {
revealString += '<stacks_data> ';
} else {
revealString += part + ' ';
}
count++;
}
const amt = (peginRequest.vout && peginRequest.vout.value) ? peginRequest.vout.value : peginRequest.amount;
stacksData = parseDepositPayload(revealScript[0].valueOf() as Uint8Array, amt);
} catch(err) {
console.log(err)
}
intid = true;
})

</script>

{#if intid}
<div class="row ">
<!--
{#each scriptElements as element}
<div class="col-md-2 col-sm-12 text-info">{element.key}</div>
<div class="col-md-10 col-sm-12">{element.value}</div>
{/each}
-->
<div class="col-12 text-start"><span class="pointer" on:keypress on:click={() => showCommitDetails = !showCommitDetails}>show details</span></div>
{#if showCommitDetails}
<div class="mt-4 col-12">Reclaim Data</div>
<div class="col-md-2 col-sm-12 text-info">Refunds to</div><div class="col-md-10 col-sm-12">{peginRequest.senderAddress}</div>
{#if stacksData && $sbtcConfig.userSettings.debugMode}
<div class="col-md-2 col-sm-12 text-info">Reclaim Pub Key</div><div class="col-md-10 col-sm-12">{peginRequest.reclaimPub}</div>
{/if}
{#if peginRequest.status < 3}
<TxExport btcTx={reclaimBtcTx} txtype={'reclaim'} amount={peginRequest.vout?.value || 0}/>
{/if}
<div class="mt-4 col-12">Reveal Data</div>
<div class="col-md-2 col-sm-12 text-info">Sbtc Address</div><div class="col-md-10 col-sm-12">{peginRequest.sbtcWalletAddress}</div>
{#if stacksData && $sbtcConfig.userSettings.debugMode}
<div class="col-md-2 col-sm-12 text-info">Reveal Pub Key</div><div class="col-md-10 col-sm-12">{peginRequest.revealPub}</div>
{/if}
<div class="mt-4 col-12 text-info"></div>
{#if peginRequest.status < 3}
<TxExport btcTx={revealBtcTx} txtype={'reveal'} amount={peginRequest.vout?.value || 0}/>
{/if}
{#if stacksData && $sbtcConfig.userSettings.debugMode}
<div class="mt-4 col-12">Stacks Data</div>
<div class="col-md-2 col-sm-12 text-info">Op Code</div><div class="col-md-10 col-sm-12">{stacksData.opcode}</div>
<div class="col-md-2 col-sm-12 text-info">Address</div><div class="col-md-10 col-sm-12">{stacksData.stacksAddress}</div>
<div class="col-md-2 col-sm-12 text-info">Contract Name</div><div class="col-md-10 col-sm-12">{stacksData.cname || 'n/a'}</div>
<div class="col-md-2 col-sm-12 text-info">Memo</div><div class="col-md-10 col-sm-12">{stacksData.memo || 'n/a'}</div>
<div class="col-md-2 col-sm-12 text-info">Reveal Fee</div><div class="col-md-10 col-sm-12">{stacksData.revealFee}</div>
{/if}
{/if}
</div>
{/if}

<style>
</style>