Skip to content

Instantly share code, notes, and snippets.

@hantyrram
Last active November 21, 2023 02:22
Show Gist options
  • Save hantyrram/536bdbe970559deb0d9cfbbb6b5e418f to your computer and use it in GitHub Desktop.
Save hantyrram/536bdbe970559deb0d9cfbbb6b5e418f to your computer and use it in GitHub Desktop.
Paytaca Connect Snippets
import { CashAddressNetworkPrefix, CashAddressType, decodeCashAddress, encodeCashAddress, decodeTransaction } from '@bitauth/libauth';
import { NFTCapability, OpReturnData, SendRequest, TokenSendRequest, UtxoI, Wallet, TestnetWallet, hexToBin } from "mainnet-js";
// So that linter won't complain about window.paytaca
export {}
declare global {
interface Window {
paytaca: any
}
}
const config = {
network: 'chipnet'
}
const formatAddress = (address:string): string => { // Just a util function to format address to
if (config.network === 'chipnet' || config.network === 'testnet') { /* testnet/chipnet */
const decoded = decodeCashAddress(address);
if (typeof decoded === "string") {
return '';
}
const testAddress = encodeCashAddress(CashAddressNetworkPrefix.testnet, CashAddressType.p2pkh, decoded.payload);
return testAddress;
}
// else if mainnet
return address;
}
const getWalletClass = () => {
return config.network === 'mainnet'? Wallet: TestnetWallet
}
let wallet: TestnetWallet | Wallet // :Wallet for mainnet
/**
* Connect to the Paytaca browser extension
*/
const connect = async ():string|undefined => {
let paytacaConnection = await window.paytaca!.connect()
if (paytacaConnection.connected) {
if (!paytacaConnection.address.startsWith('bitcoincash')) {
const cashaddr = formatAddress(paytacaConnection.address)
wallet = getWalletClass().watchOnly(cashaddr)
return formatAddress(paytacaConnection.address)
}
}
}
/**
* Prepare request(s) using mainnet-js
*/
const prepareRequest = (
args: {recipient:String, tokenValue:number, tokenId:string, tokenAmount: number, nftCapability?: NFTCapability, commitment?: string}
): (TokenSendRequest|OpReturnData|SendRequest)[] => {
return [new TokenSendRequest({
cashaddr: args.recipient,
value: args.tokenValue,
tokenId: args.tokenId,
amount: args.tokenAmount,
capability: args.nftCapability,
commitment: args.commitment
})]
}
/***
* Build transaction
*/
const buildTransactions = async (requests:(TokenSendRequest|OpReturnData|SendRequest)[]): Promise<{encodedTransaction:any, sourceOutputs:any}> => {
const cost = 20000 // sample only, calculate cost
let genesisInput: UtxoI = (await wallet.getAddressUtxos()).filter((u:UtxoI) => u.vout === 0 && u.satoshis > cost)
let funderInputs: UtxoI[] = [] // can use other utxos to fund the transaction if genesisInput's value is not enough
const { encodedTransaction, sourceOutputs } = await wallet.encodeTransaction(
requests,
false,
{
tokenOperation: 'genesis',
checkTokenQuantities: false,
buildUnsigned: true,
utxoIds: [genesisInput, ...funderInputs],
ensureUtxos: [genesisInput, ...funderInputs]
}
)
return {encodedTransaction, sourceOutputs}
}
/**
* Sign transaction using Paytaca. The parameters `encodedTransaction` and `sourceOutputs`
* are returned by `buildTransactions()`
*/
const signTransaction = async (encodedTransaction:any, sourceOutputs:any, broadcast?:boolean, prompt?:string): Promise<any> => {
const decoded = decodeTransaction(encodedTransaction)
if (typeof decoded === 'string') {
throw new Error('Error decoding transaction')
}
try {
const signResult = await window.paytaca.signTransaction({
transaction: decoded,
sourceOutputs: [...sourceOutputs],
broadcast: Boolean(broadcast),
userPrompt: prompt || 'Signature Requested'
})
return signResult
} catch (error) {
throw error
}
}
/**
* Submits a signed transaction
*/
const submitTransaction = async (signResult:any, ownerWallet: Wallet): Promise<string|undefined> => {
if (signResult?.signedTransaction) {
return ownerWallet!.submitTransaction(hexToBin(signResult.signedTransaction), true)
}
}
const args:{recipient:String, tokenValue:number, tokenId:string, tokenAmount: number, nftCapability?: NFTCapability, commitment?: string} = {/*supply values*/}
const requests = prepareRequest({...args})
const {encodedTransaction, sourceOutputs} = await buildTransactions(requests)
const signResult = await signTransaction(encodedTransaction, sourceOutputs)
if (!signResult) {
// Do something when user 'Rejects'
} else {
const txId = await submitTransaction(signResult, wallet)
console.log('Transaction Id', txId)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment