-
Notifications
You must be signed in to change notification settings - Fork 4
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: add Xverse to Connect Wallet component #8
base: main
Are you sure you want to change the base?
Conversation
WalkthroughWalkthroughThe recent changes introduce enhancements to the wallet integration in the application, particularly adding support for the "Xverse" wallet and streamlining wallet interaction methods. Several components have been updated to incorporate new hooks for blockchain functionalities, improving functionality and user experience. The updates also include modifications to existing wallet providers, simplifying method signatures and improving data retrieval processes, thereby enhancing the maintainability and readability of the codebase. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ConnectButton
participant XverseWallet
participant BitcoinWalletProvider
User->>ConnectButton: Click to connect wallet
ConnectButton->>XverseWallet: Initiate connection
XverseWallet->>BitcoinWalletProvider: Request user accounts
BitcoinWalletProvider-->>XverseWallet: Return account information
XverseWallet-->>ConnectButton: Connection successful
ConnectButton-->>User: Display connected wallet
sequenceDiagram
participant User
participant SendTransactionButton
participant BitcoinWalletProvider
participant TransactionUtils
User->>SendTransactionButton: Click to send transaction
SendTransactionButton->>BitcoinWalletProvider: Prepare transaction
BitcoinWalletProvider->>TransactionUtils: Create transaction
TransactionUtils-->>BitcoinWalletProvider: Return PSBT
BitcoinWalletProvider->>User: Transaction sent confirmation
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (invoked as PR comments)
Additionally, you can add CodeRabbit Configuration File (
|
@coderabbitai review |
Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Outside diff range, codebase verification and nitpick comments (2)
src/providers/BitcoinWalletProvider/okx.ts (1)
4-7
: Add a check for the existence ofwindow.okxwallet
in thegetAddress
function.The
getAddress
function inokx.ts
directly accesseswindow.okxwallet
without verifying its existence. To prevent potential runtime errors, add a check to handle cases wherewindow.okxwallet
might be undefined.
- File:
src/providers/BitcoinWalletProvider/okx.ts
- Lines: 4-7
getAddress: async () => { + const wallet = (window as any)?.okxwallet; + if (!wallet) { + throw new Error("OKX wallet not found"); + } const address = (await wallet.bitcoinTestnet.connect()).address; return { address, publicKey: null }; },Analysis chain
Verify the function usage and handle potential issues with accessing the global
window
object.The function now directly accesses the
okxwallet
from the globalwindow
object. Ensure that all function calls togetAddress
match the new signature and handle cases wherewindow.okxwallet
might be undefined.+ const wallet = (window as any)?.okxwallet; + if (!wallet) { + throw new Error("OKX wallet not found"); + }Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify all function calls to `getAddress` match the new signature. # Test: Search for the function usage. Expect: Only occurrences of the new signature. rg --type python -A 5 $'getAddress' # Handle potential issues with accessing the global `window` object. # Suggest adding a check for `window.okxwallet`.Length of output: 65
Script:
#!/bin/bash # Description: Verify all function calls to `getAddress` match the new signature. # Test: Search for the function usage within TypeScript files. Expect: Only occurrences of the new signature. rg --type ts -A 5 'getAddress'Length of output: 5288
src/providers/BitcoinWalletProvider/xdefi.ts (1)
4-8
: Ensure handling of potential issues with accessing the globalwindow
object ingetAddress
functionThe
getAddress
function directly accesses thexfi
wallet from the globalwindow
object. To ensure robustness, you should handle cases wherewindow.xfi
might be undefined. Additionally, the search results indicate that the function is used insrc/providers/BitcoinWalletProvider/index.tsx
.Suggested code modification:
getAddress: async () => { + const wallet = (window as any)?.xfi; + if (!wallet) { + throw new Error("XDEFI wallet not found"); + } wallet.bitcoin.changeNetwork("testnet"); const address = (await wallet?.bitcoin?.getAccounts())[0]; return { address, publicKey: null }; }Files to update:
src/providers/BitcoinWalletProvider/xdefi.ts
Please ensure that all function calls to
getAddress
handle the new error scenario appropriately.Analysis chain
Verify the function usage and handle potential issues with accessing the global
window
object.The function now directly accesses the
xfi
wallet from the globalwindow
object. Ensure that all function calls togetAddress
match the new signature and handle cases wherewindow.xfi
might be undefined.+ const wallet = (window as any)?.xfi; + if (!wallet) { + throw new Error("XDEFI wallet not found"); + }
+ const wallet = (window as any)?.xfi; + if (!wallet) { + throw new Error("XDEFI wallet not found"); + }Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify all function calls to `getAddress` match the new signature. # Test: Search for the function usage. Expect: Only occurrences of the new signature. rg --type python -A 5 $'getAddress' # Handle potential issues with accessing the global `window` object. # Suggest adding a check for `window.xfi`.Length of output: 65
Script:
#!/bin/bash # Description: Verify all function calls to `getAddress` match the new signature. # Test: Search for the function usage. Expect: Only occurrences of the new signature. rg --type js -A 5 'getAddress' # Handle potential issues with accessing the global `window` object. # Suggest adding a check for `window.xfi`.Length of output: 30
Script:
#!/bin/bash # Description: Verify all function calls to `getAddress` match the new signature. # Test: Search for the function usage in JavaScript and TypeScript files. Expect: Only occurrences of the new signature. rg --type js,ts -A 5 'getAddress' # Handle potential issues with accessing the global `window` object. # Suggest adding a check for `window.xfi`.Length of output: 63
Script:
#!/bin/bash # Description: Verify all function calls to `getAddress` match the new signature in JavaScript files. rg --type js -A 5 'getAddress'Length of output: 30
Script:
#!/bin/bash # Description: Verify all function calls to `getAddress` match the new signature in TypeScript files. rg --type ts -A 5 'getAddress'Length of output: 5288
Tools
Biome
[error] 7-7: Unsafe usage of optional chaining.
If it short-circuits with 'undefined' the evaluation will throw TypeError here:
(lint/correctness/noUnsafeOptionalChaining)
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files ignored due to path filters (1)
src/components/ConnectBitcoin/xverse.jpeg
is excluded by!**/*.jpeg
Files selected for processing (8)
- src/app/page.tsx (1 hunks)
- src/components/ConnectBitcoin/index.tsx (3 hunks)
- src/providers/BitcoinWalletProvider/index.tsx (4 hunks)
- src/providers/BitcoinWalletProvider/okx.ts (1 hunks)
- src/providers/BitcoinWalletProvider/unisat.ts (1 hunks)
- src/providers/BitcoinWalletProvider/xdefi.ts (1 hunks)
- src/providers/BitcoinWalletProvider/xverse/index.ts (1 hunks)
- src/providers/BitcoinWalletProvider/xverse/utils.ts (1 hunks)
Additional context used
Biome
src/providers/BitcoinWalletProvider/xdefi.ts
[error] 7-7: Unsafe usage of optional chaining.
If it short-circuits with 'undefined' the evaluation will throw TypeError here:
(lint/correctness/noUnsafeOptionalChaining)
Additional comments not posted (18)
src/providers/BitcoinWalletProvider/unisat.ts (2)
9-19
: Verify the function usage and handle potential issues with accessing the globalwindow
object.The function now directly accesses the
unisat
wallet from the globalwindow
object. Ensure that all function calls tosendTransaction
match the new signature and handle cases wherewindow.unisat
might be undefined. Also, consider improving error handling.+ const wallet = (window as any)?.unisat; + if (!wallet) { + throw new Error("Unisat wallet not found"); + } + try { + await wallet.requestAccounts(); + const memos = memo && [memo.toLowerCase()]; + const tx = await wallet.sendBitcoin(to, value * 1e8, { memos }); + return tx; + } catch (error) { + throw new Error("Transaction failed: " + error.message); + }
4-7
: Verify the function usage and handle potential issues with accessing the globalwindow
object.The function now directly accesses the
unisat
wallet from the globalwindow
object. Ensure that all function calls togetAddress
match the new signature and handle cases wherewindow.unisat
might be undefined.+ const wallet = (window as any)?.unisat; + if (!wallet) { + throw new Error("Unisat wallet not found"); + }src/providers/BitcoinWalletProvider/okx.ts (1)
Line range hint
9-29
:
Verify the function usage and handle potential issues with accessing the globalwindow
object.The function now directly accesses the
okxwallet
from the globalwindow
object. Ensure that all function calls tosendTransaction
match the new signature and handle cases wherewindow.okxwallet
might be undefined. Also, consider improving error handling.+ const wallet = (window as any)?.okxwallet; + if (!wallet) { + throw new Error("OKX wallet not found"); + } + try { + const account = await wallet?.bitcoinTestnet?.connect(); + if (!account) throw new Error("No account found"); + const txHash = await wallet.bitcoinTestnet.send({ + from: account.address, + to, + value: value * 1e8, + memo: `0x${memo}`, + memoPos: 1, + }); + return txHash; + } catch (error) { + throw new Error("Transaction failed: " + error.message); + }src/providers/BitcoinWalletProvider/xdefi.ts (1)
Line range hint
10-32
:
Verify the function usage and handle potential issues with accessing the globalwindow
object.The function now directly accesses the
unisat
wallet from the globalwindow
object. Ensure that all function calls tosendTransaction
match the new signature and handle cases wherewindow.unisat
might be undefined. Also, consider improving error handling and addressing the unsafe usage of optional chaining.+ const wallet = (window as any)?.unisat; + if (!wallet) { + throw new Error("Unisat wallet not found"); + } + try { + wallet.bitcoin.changeNetwork("testnet"); + const account = (await wallet?.bitcoin?.getAccounts())?.[0]; + if (!account) throw new Error("No account found"); + const tx = { + method: "transfer", + params: [ + { + feeRate: 10, + from: account, + recipient: to, + amount: { + amount: value * 1e8, + decimals: 8, + }, + memo: `hex::${memo}`, + }, + ], + }; + console.log(tx); + return new Promise((resolve, reject) => { + wallet.bitcoin.request(tx, (err: Error, res: Response) => { + if (err) { + reject(err); + } else { + resolve(res); + } + }); + }); + } catch (error) { + throw new Error("Transaction failed: " + error.message); + }Tools
Biome
[error] 7-7: Unsafe usage of optional chaining.
If it short-circuits with 'undefined' the evaluation will throw TypeError here:
(lint/correctness/noUnsafeOptionalChaining)
src/app/page.tsx (4)
13-13
: LGTM! Ensure the contract address is correct.The
contract
constant is defined correctly. Verify that the contract address is accurate and intended for use.
16-21
: LGTM! Verify hook functionality.The hooks (
useAccount
,useChainId
,useWalletClient
,useEthersSigner
,useZetaChainClient
,useBitcoinWallet
) are used correctly. Ensure that these hooks function as expected and provide the necessary data.
24-40
: LGTM! Verify the conditional rendering logic.The JSX structure is well-organized, and the
Swap
component is conditionally rendered based on theclient
availability. Ensure that the conditional rendering logic functions as intended.
4-10
: Ensure all imports are used.Verify that all imported modules (
Swap
,useEthersSigner
,useZetaChainClient
,ConnectBitcoin
,useBitcoinWallet
) are utilized within the component. Unused imports can lead to unnecessary bloat.Verification successful
All imports are used correctly.
The verification confirms that each imported module (
Swap
,useEthersSigner
,useZetaChainClient
,ConnectBitcoin
,useBitcoinWallet
) is utilized withinsrc/app/page.tsx
. No unnecessary imports were found.
Swap
is used in a JSX element.useEthersSigner
is used to get the signer.useZetaChainClient
is used to get the client.ConnectBitcoin
is used in a JSX element.useBitcoinWallet
is used to get the Bitcoin address.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify all imported modules are used within `src/app/page.tsx`. # Test: Search for the usage of each imported module. Expect: Each module should be used at least once. rg --type js --type ts --type tsx --type jsx -w 'Swap' src/app/page.tsx rg --type js --type ts --type tsx --type jsx -w 'useEthersSigner' src/app/page.tsx rg --type js --type ts --type tsx --type jsx -w 'useZetaChainClient' src/app/page.tsx rg --type js --type ts --type tsx --type jsx -w 'ConnectBitcoin' src/app/page.tsx rg --type js --type ts --type tsx --type jsx -w 'useBitcoinWallet' src/app/page.tsxLength of output: 546
Script:
#!/bin/bash # Description: Verify all imported modules are used within `src/app/page.tsx`. # Test: Search for the usage of each imported module. Expect: Each module should be used at least once. rg --type-add 'tsx:*.tsx' -w 'Swap' src/app/page.tsx rg --type-add 'tsx:*.tsx' -w 'useEthersSigner' src/app/page.tsx rg --type-add 'tsx:*.tsx' -w 'useZetaChainClient' src/app/page.tsx rg --type-add 'tsx:*.tsx' -w 'ConnectBitcoin' src/app/page.tsx rg --type-add 'tsx:*.tsx' -w 'useBitcoinWallet' src/app/page.tsxLength of output: 622
src/providers/BitcoinWalletProvider/xverse/index.ts (1)
1-2
: Ensure all imports are used.Verify that all imported modules (
AddressPurpose
,BaseAdapter
,createTransaction
,signPsbt
) are utilized within the file. Unused imports can lead to unnecessary bloat.Verification successful
All imports are used.
The verification confirms that all imported modules (
AddressPurpose
,BaseAdapter
,createTransaction
,signPsbt
) are utilized within the filesrc/providers/BitcoinWalletProvider/xverse/index.ts
.
AddressPurpose
is used in lines containingpurposes: [AddressPurpose.Payment, AddressPurpose.Payment]
.BaseAdapter
is instantiated withnew BaseAdapter("XverseProviders.BitcoinProvider")
.createTransaction
is called withcreateTransaction(publicKey, address, {...})
.signPsbt
is invoked withsignPsbt(result.psbtB64, result.utxoCnt, address)
.No unused imports were found.
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify all imported modules are used within `src/providers/BitcoinWalletProvider/xverse/index.ts`. # Test: Search for the usage of each imported module. Expect: Each module should be used at least once. rg --type js --type ts --type tsx --type jsx -w 'AddressPurpose' src/providers/BitcoinWalletProvider/xverse/index.ts rg --type js --type ts --type tsx --type jsx -w 'BaseAdapter' src/providers/BitcoinWalletProvider/xverse/index.ts rg --type js --type ts --type tsx --type jsx -w 'createTransaction' src/providers/BitcoinWalletProvider/xverse/index.ts rg --type js --type ts --type tsx --type jsx -w 'signPsbt' src/providers/BitcoinWalletProvider/xverse/index.tsLength of output: 573
Script:
#!/bin/bash # Description: Verify all imported modules are used within `src/providers/BitcoinWalletProvider/xverse/index.ts`. # Test: Search for the usage of each imported module. Expect: Each module should be used at least once. rg --type js --type ts --type jsx -w 'AddressPurpose' src/providers/BitcoinWalletProvider/xverse/index.ts rg --type js --type ts --type jsx -w 'BaseAdapter' src/providers/BitcoinWalletProvider/xverse/index.ts rg --type js --type ts --type jsx -w 'createTransaction' src/providers/BitcoinWalletProvider/xverse/index.ts rg --type js --type ts --type jsx -w 'signPsbt' src/providers/BitcoinWalletProvider/xverse/index.tsLength of output: 529
Script:
#!/bin/bash # Description: Verify all imported modules are used within `src/providers/BitcoinWalletProvider/xverse/index.ts`. # Test: Search for the usage of each imported module. Expect: Each module should be used at least once. rg --type js --type ts -w 'AddressPurpose' src/providers/BitcoinWalletProvider/xverse/index.ts rg --type js --type ts -w 'BaseAdapter' src/providers/BitcoinWalletProvider/xverse/index.ts rg --type js --type ts -w 'createTransaction' src/providers/BitcoinWalletProvider/xverse/index.ts rg --type js --type ts -w 'signPsbt' src/providers/BitcoinWalletProvider/xverse/index.tsLength of output: 1029
src/providers/BitcoinWalletProvider/index.tsx (5)
11-11
: LGTM! Ensure the new wallet type is integrated correctly.The
xverse
wallet type is added to thewalletTypes
object correctly. Verify that the new wallet type is used appropriately within the component.
18-18
: LGTM! Ensure the new property is integrated correctly.The
publicKey
property is added to theWalletContextProps
interface correctly. Verify that the new property is used appropriately within the component.
40-40
: LGTM! Ensure the new state is managed correctly.The
publicKey
state is initialized correctly. Verify that the new state is managed appropriately within the component.
51-63
: LGTM! Ensure error handling is sufficient.The
connectWallet
method is updated correctly to retrieve bothaddress
andpublicKey
. Ensure that the error handling is sufficient and covers all edge cases.
5-5
: Ensure the imported module is used.Verify that the imported
xverseWallet
module is utilized within the file. Unused imports can lead to unnecessary bloat.Verification successful
The imported
xverseWallet
module is used within the file.The
xverseWallet
module is correctly imported and utilized in thesrc/providers/BitcoinWalletProvider/index.tsx
file.
import xverseWallet from "./xverse";
xverse: xverseWallet,
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the imported `xverseWallet` module is used within `src/providers/BitcoinWalletProvider/index.tsx`. # Test: Search for the usage of `xverseWallet`. Expect: The module should be used at least once. rg --type js --type ts --type tsx --type jsx -w 'xverseWallet' src/providers/BitcoinWalletProvider/index.tsxLength of output: 136
Script:
#!/bin/bash # Description: Verify the imported `xverseWallet` module is used within `src/providers/BitcoinWalletProvider/index.tsx`. # Test: Search for the usage of `xverseWallet`. Expect: The module should be used at least once. rg -w 'xverseWallet' src/providers/BitcoinWalletProvider/index.tsxLength of output: 127
src/providers/BitcoinWalletProvider/xverse/utils.ts (1)
133-133
: LGTM!The export statement is correct.
src/components/ConnectBitcoin/index.tsx (3)
20-35
: LGTM!The import statements for
xverseIcon
and entities from@sats-connect/core
module are correct and necessary for the new functionality.
193-199
: LGTM!The JSX structure for the new
WalletButton
for the Xverse wallet is correct and consistent with existing buttons.
Line range hint
1-199
:
LGTM!The
ConnectBitcoin
component correctly integrates the newconnectXverse
function andWalletButton
for the Xverse wallet.
async function fetchUtxo(address: string): Promise<any[]> { | ||
try { | ||
const response = await fetch( | ||
`https://mempool.space/testnet/api/address/${address}/utxo` | ||
); | ||
if (!response.ok) { | ||
throw new Error("Failed to fetch UTXO"); | ||
} | ||
const utxos: any[] = await response.json(); | ||
|
||
if (utxos.length === 0) { | ||
throw new Error("0 Balance"); | ||
} | ||
return utxos; | ||
} catch (error) { | ||
console.error("Error fetching UTXO:", error); | ||
throw error; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enhance error handling and type definitions.
- Consider using more specific error handling to differentiate between network errors and application errors.
- Define a type for the UTXO response to improve type safety.
type Utxo = {
txid: string;
vout: number;
value: number;
// Add other relevant fields
};
async function fetchUtxo(address: string): Promise<Utxo[]> {
try {
const response = await fetch(
`https://mempool.space/testnet/api/address/${address}/utxo`
);
if (!response.ok) {
throw new Error(`Failed to fetch UTXO: ${response.statusText}`);
}
const utxos: Utxo[] = await response.json();
if (utxos.length === 0) {
throw new Error("0 Balance");
}
return utxos;
} catch (error) {
console.error("Error fetching UTXO:", error);
throw error;
}
}
async function createTransaction( | ||
publickkey: string, | ||
senderAddress: string, | ||
params: any | ||
): Promise<{ psbtB64: string; utxoCnt: number }> { | ||
const publicKey = hex.decode(publickkey); | ||
|
||
const p2wpkh = btc.p2wpkh(publicKey, bitcoinTestnet); | ||
const p2sh = btc.p2sh(p2wpkh, bitcoinTestnet); | ||
|
||
const recipientAddress = params.to; | ||
if (!senderAddress) { | ||
throw new Error("Error: no sender address"); | ||
} | ||
if (!recipientAddress) { | ||
throw new Error("Error: no recipient address in ENV"); | ||
} | ||
|
||
const output = await fetchUtxo(senderAddress); | ||
|
||
const tx = new btc.Transaction({ | ||
allowUnknowOutput: true, | ||
}); | ||
|
||
let utxoCnt = 0; | ||
|
||
output.forEach((utxo) => { | ||
tx.addInput({ | ||
txid: utxo.txid, | ||
index: utxo.vout, | ||
witnessUtxo: { | ||
script: p2sh.script, | ||
amount: BigInt(utxo.value), | ||
}, | ||
witnessScript: p2sh.witnessScript, | ||
redeemScript: p2sh.redeemScript, | ||
}); | ||
utxoCnt += 1; | ||
}); | ||
|
||
const changeAddress = senderAddress; | ||
|
||
const memo = params.memo.toLowerCase(); | ||
|
||
const opReturn = btc.Script.encode(["RETURN", Buffer.from(memo, "utf8")]); | ||
tx.addOutputAddress(recipientAddress, BigInt(params.amount), bitcoinTestnet); | ||
tx.addOutput({ | ||
script: opReturn, | ||
amount: BigInt(0), | ||
}); | ||
tx.addOutputAddress(changeAddress, BigInt(800), bitcoinTestnet); | ||
|
||
const psbt = tx.toPSBT(0); | ||
|
||
const psbtB64 = base64.encode(psbt); | ||
|
||
return { psbtB64, utxoCnt }; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enhance error handling, type definitions, and code comments.
- Consider using more specific error handling to differentiate between different types of errors.
- Define types for the function parameters and return values to improve type safety.
- Add comments to explain the purpose of each code block for better readability.
type TransactionParams = {
to: string;
amount: number;
memo: string;
};
async function createTransaction(
publickkey: string,
senderAddress: string,
params: TransactionParams
): Promise<{ psbtB64: string; utxoCnt: number }> {
const publicKey = hex.decode(publickkey);
const p2wpkh = btc.p2wpkh(publicKey, bitcoinTestnet);
const p2sh = btc.p2sh(p2wpkh, bitcoinTestnet);
const recipientAddress = params.to;
if (!senderAddress) {
throw new Error("Error: no sender address");
}
if (!recipientAddress) {
throw new Error("Error: no recipient address in ENV");
}
const output = await fetchUtxo(senderAddress);
const tx = new btc.Transaction({
allowUnknowOutput: true,
});
let utxoCnt = 0;
output.forEach((utxo) => {
tx.addInput({
txid: utxo.txid,
index: utxo.vout,
witnessUtxo: {
script: p2sh.script,
amount: BigInt(utxo.value),
},
witnessScript: p2sh.witnessScript,
redeemScript: p2sh.redeemScript,
});
utxoCnt += 1;
});
const changeAddress = senderAddress;
const memo = params.memo.toLowerCase();
const opReturn = btc.Script.encode(["RETURN", Buffer.from(memo, "utf8")]);
tx.addOutputAddress(recipientAddress, BigInt(params.amount), bitcoinTestnet);
tx.addOutput({
script: opReturn,
amount: BigInt(0),
});
tx.addOutputAddress(changeAddress, BigInt(800), bitcoinTestnet);
const psbt = tx.toPSBT(0);
const psbtB64 = base64.encode(psbt);
return { psbtB64, utxoCnt };
}
async function signPsbt( | ||
psbtBase64: string, | ||
utxoCnt: number, | ||
senderAddress: string | ||
) { | ||
// Get the PSBT Base64 from the input | ||
|
||
if (!psbtBase64) { | ||
alert("Please enter a valid PSBT Base64 string."); | ||
return; | ||
} | ||
|
||
const sigInputs = new Array(utxoCnt).fill(0, 0, utxoCnt).map((_, i) => i); | ||
|
||
try { | ||
const adapter = new BaseAdapter("XverseProviders.BitcoinProvider"); | ||
const response = await adapter.request("signPsbt", { | ||
psbt: psbtBase64, | ||
allowedSignHash: btc.SignatureHash.ALL, | ||
broadcast: true, | ||
signInputs: { | ||
[senderAddress]: sigInputs, | ||
}, | ||
}); | ||
|
||
if (response.status === "success") { | ||
alert("PSBT signed successfully!"); | ||
} else { | ||
if (response.error.code === RpcErrorCode.USER_REJECTION) { | ||
alert("Request canceled by user"); | ||
} else { | ||
console.error("Error signing PSBT:", response.error); | ||
alert("Error signing PSBT: " + response.error.message); | ||
} | ||
} | ||
} catch (err) { | ||
console.error("Unexpected error:", err); | ||
alert("Error while signing"); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enhance error handling, type definitions, and code comments.
- Consider using more specific error handling to differentiate between different types of errors.
- Define types for the function parameters to improve type safety.
- Add comments to explain the purpose of each code block for better readability.
type SignPsbtParams = {
psbtBase64: string;
utxoCnt: number;
senderAddress: string;
};
async function signPsbt({ psbtBase64, utxoCnt, senderAddress }: SignPsbtParams) {
if (!psbtBase64) {
alert("Please enter a valid PSBT Base64 string.");
return;
}
const sigInputs = new Array(utxoCnt).fill(0, 0, utxoCnt).map((_, i) => i);
try {
const adapter = new BaseAdapter("XverseProviders.BitcoinProvider");
const response = await adapter.request("signPsbt", {
psbt: psbtBase64,
allowedSignHash: btc.SignatureHash.ALL,
broadcast: true,
signInputs: {
[senderAddress]: sigInputs,
},
});
if (response.status === "success") {
alert("PSBT signed successfully!");
} else {
if (response.error.code === RpcErrorCode.USER_REJECTION) {
alert("Request canceled by user");
} else {
console.error("Error signing PSBT:", response.error);
alert("Error signing PSBT: " + response.error.message);
}
}
} catch (err) {
console.error("Unexpected error:", err);
alert("Error while signing");
}
}
const connectXverse = async () => { | ||
const adapter = new BaseAdapter("XverseProviders.BitcoinProvider"); | ||
const accounts = await adapter.request("getAccounts", { | ||
purposes: [AddressPurpose.Stacks, AddressPurpose.Payment], | ||
}); | ||
console.log(accounts); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling and logging.
Consider adding error handling and logging to the connectXverse
function to handle potential issues gracefully.
const connectXverse = async () => {
try {
const adapter = new BaseAdapter("XverseProviders.BitcoinProvider");
const accounts = await adapter.request("getAccounts", {
purposes: [AddressPurpose.Stacks, AddressPurpose.Payment],
});
console.log(accounts);
} catch (error) {
console.error("Error connecting to Xverse wallet:", error);
}
};
sendTransaction: async ({ | ||
to, | ||
value, | ||
memo, | ||
}: { | ||
to: string; | ||
value: number; | ||
memo?: string; | ||
}) => { | ||
const adapter = new BaseAdapter("XverseProviders.BitcoinProvider"); | ||
const accounts: any = await adapter.request("getAccounts", { | ||
purposes: [AddressPurpose.Payment, AddressPurpose.Payment], | ||
}); | ||
const address = accounts.result[0].address; | ||
const publicKey = accounts.result[0].publicKey; | ||
|
||
const result = await createTransaction(publicKey, address, { | ||
memo, | ||
amount: value * 1e8, | ||
to, | ||
}); | ||
|
||
const res = await signPsbt(result.psbtB64, result.utxoCnt, address); | ||
console.log(res); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle potential errors in sendTransaction
.
The sendTransaction
method creates and signs a transaction correctly. However, it lacks error handling, which could lead to unhandled exceptions.
sendTransaction: async ({
to,
value,
memo,
}: {
to: string;
value: number;
memo?: string;
}) => {
try {
const adapter = new BaseAdapter("XverseProviders.BitcoinProvider");
const accounts: any = await adapter.request("getAccounts", {
purposes: [AddressPurpose.Payment, AddressPurpose.Payment],
});
const address = accounts.result[0].address;
const publicKey = accounts.result[0].publicKey;
const result = await createTransaction(publicKey, address, {
memo,
amount: value * 1e8,
to,
});
const res = await signPsbt(result.psbtB64, result.utxoCnt, address);
console.log(res);
} catch (error) {
console.error("Failed to send transaction:", error);
throw error;
}
},
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
sendTransaction: async ({ | |
to, | |
value, | |
memo, | |
}: { | |
to: string; | |
value: number; | |
memo?: string; | |
}) => { | |
const adapter = new BaseAdapter("XverseProviders.BitcoinProvider"); | |
const accounts: any = await adapter.request("getAccounts", { | |
purposes: [AddressPurpose.Payment, AddressPurpose.Payment], | |
}); | |
const address = accounts.result[0].address; | |
const publicKey = accounts.result[0].publicKey; | |
const result = await createTransaction(publicKey, address, { | |
memo, | |
amount: value * 1e8, | |
to, | |
}); | |
const res = await signPsbt(result.psbtB64, result.utxoCnt, address); | |
console.log(res); | |
}, | |
sendTransaction: async ({ | |
to, | |
value, | |
memo, | |
}: { | |
to: string; | |
value: number; | |
memo?: string; | |
}) => { | |
try { | |
const adapter = new BaseAdapter("XverseProviders.BitcoinProvider"); | |
const accounts: any = await adapter.request("getAccounts", { | |
purposes: [AddressPurpose.Payment, AddressPurpose.Payment], | |
}); | |
const address = accounts.result[0].address; | |
const publicKey = accounts.result[0].publicKey; | |
const result = await createTransaction(publicKey, address, { | |
memo, | |
amount: value * 1e8, | |
to, | |
}); | |
const res = await signPsbt(result.psbtB64, result.utxoCnt, address); | |
console.log(res); | |
} catch (error) { | |
console.error("Failed to send transaction:", error); | |
throw error; | |
} | |
}, |
getAddress: async () => { | ||
const adapter = new BaseAdapter("XverseProviders.BitcoinProvider"); | ||
const accounts: any = await adapter.request("getAccounts", { | ||
purposes: [AddressPurpose.Payment, AddressPurpose.Payment], | ||
}); | ||
console.log(accounts); | ||
return { | ||
address: accounts.result[0].address, | ||
publicKey: accounts.result[0].publicKey, | ||
}; | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle potential errors in getAddress
.
The getAddress
method retrieves account information correctly. However, it lacks error handling, which could lead to unhandled exceptions.
getAddress: async () => {
try {
const adapter = new BaseAdapter("XverseProviders.BitcoinProvider");
const accounts: any = await adapter.request("getAccounts", {
purposes: [AddressPurpose.Payment, AddressPurpose.Payment],
});
console.log(accounts);
return {
address: accounts.result[0].address,
publicKey: accounts.result[0].publicKey,
};
} catch (error) {
console.error("Failed to get address:", error);
throw error;
}
},
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
getAddress: async () => { | |
const adapter = new BaseAdapter("XverseProviders.BitcoinProvider"); | |
const accounts: any = await adapter.request("getAccounts", { | |
purposes: [AddressPurpose.Payment, AddressPurpose.Payment], | |
}); | |
console.log(accounts); | |
return { | |
address: accounts.result[0].address, | |
publicKey: accounts.result[0].publicKey, | |
}; | |
}, | |
getAddress: async () => { | |
try { | |
const adapter = new BaseAdapter("XverseProviders.BitcoinProvider"); | |
const accounts: any = await adapter.request("getAccounts", { | |
purposes: [AddressPurpose.Payment, AddressPurpose.Payment], | |
}); | |
console.log(accounts); | |
return { | |
address: accounts.result[0].address, | |
publicKey: accounts.result[0].publicKey, | |
}; | |
} catch (error) { | |
console.error("Failed to get address:", error); | |
throw error; | |
} | |
}, |
Tasks
Summary by CodeRabbit
New Features
Page
component to support blockchain interactions with new hooks and improved UI for swapping.ConnectBitcoin
component allowing users to connect seamlessly.BitcoinWalletProvider
, enhancing wallet integration.Bug Fixes
Documentation