Last active
November 21, 2023 02:22
-
-
Save hantyrram/536bdbe970559deb0d9cfbbb6b5e418f to your computer and use it in GitHub Desktop.
Paytaca Connect Snippets
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
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