import { Address , BigNumber , Block , solana , SwapParams , Transaction , TxStatus } from '@liquality/types' ; import { addressToString , validateSecretAndHash , validateValue , validateExpiration , validateSecretHash } from '@liquality/utils' ; import { InvalidAddressError } from '@liquality/errors' ; import { base58 } from '@liquality/crypto' ; import { ParsedConfirmedTransaction } from '@solana/web3.js' ; import { serialize , deserialize as deserializer } from 'borsh' ; import filter from 'lodash/filter' ; import { initSchema , claimSchema , refundSchema , InitData , Template as _Template } from './layouts' ; const FINALIZED_CONFIRMATIONS = 31 ; export const Template = _Template ; export function validateAddress ( _address ) { const address = addressToString ( _address ) ; if ( typeof address !== 'string' ) { throw new InvalidAddressError ( `Invalid address: ${ address }` ) ; } if ( address . length !== 44 ) { throw new InvalidAddressError ( `Invalid address. Length should be 44` ) ; } } export function doesTransactionMatchInitiation ( swapParams , transactionParams ) { return ( swapParams . recipientAddress === transactionParams . buyer && swapParams . refundAddress === transactionParams . seller && swapParams . secretHash === transactionParams . secret_hash && new BigNumber ( swapParams . expiration ) . eq ( transactionParams . expiration ) && swapParams . value . eq ( transactionParams . value ) ) ; } export function deserialize ( data ) { if ( data ) { const decoded = base58 . decode ( data ) ; const instruction = decoded [ 0 ] ; let schemaToUse ; switch ( instruction ) { case 0 : { schemaToUse = initSchema ; break ; } case 1 : { schemaToUse = claimSchema ; break ; } case 2 : { schemaToUse = refundSchema ; break ; } default : { break ; } } return deserializer ( schemaToUse , Template , decoded ) ; } } export const createRefundBuffer = ( ) => { const refund = new Template ( { instruction : 2 } ) ; return serialize ( refundSchema , refund ) ; } ; export const createClaimBuffer = ( secret ) => { const claim = new Template ( { instruction : 1 , secret : secret . toString ( ) } ) ; return serialize ( claimSchema , claim ) ; } ; export const createInitBuffer = ( { buyer , seller , expiration , secret_hash , value } ) => { const initTemplate = new Template ( { instruction : 0 , buyer , seller , secret_hash , expiration , value } ) ; return serialize ( initSchema , initTemplate ) ; } ; export function validateSecret ( swapParams , data ) { validateSecretAndHash ( data . secret , swapParams . secretHash ) ; return true ; } export function normalizeTransaction ( tx , signatureStatus ? ) { const { transaction : { message : { accountKeys , instructions } , signatures } } = tx ; const [ hash ] = signatures ; const [ firstInstruction ] = instructions as any ; const transactionData = { lamports : 0 , programId : '' , _raw : { } } ; const txData = filter ( instructions as any , 'data' ) ; let deserialized ; if ( txData . length ) { deserialized = deserialize ( txData [ 0 ] . data ) ; transactionData . _raw = { ... transactionData . _raw , ... deserialized } ; if ( deserialized . secret ) { transactionData . secret = deserialized . secret ; } } if ( firstInstruction . parsed ) { transactionData . lamports = firstInstruction . parsed . info . lamports ; const { type } = firstInstruction . parsed ; switch ( type ) { case 'finalize' : { transactionData . programId = firstInstruction . parsed . info . account ; break ; } case 'createAccount' : { transactionData . _raw . programAccount = firstInstruction . parsed . info . newAccount ; break ; } default : { break ; } } } if ( ! transactionData . programId ) { transactionData . programId = accountKeys [ accountKeys . length - 1 ] . pubkey . toString ( ) ; } if ( signatureStatus ?. value ?. confirmationStatus === 'finalized' ) { transactionData . confirmations = FINALIZED_CONFIRMATIONS ; transactionData . status = signatureStatus ?. value ?. status ?. Err ? TxStatus . Failed : TxStatus . Success ; } else { transactionData . status = TxStatus . Pending ; } return { hash , value : transactionData . lamports , status : transactionData . status , ... ( transactionData . secret && { secret : transactionData . secret } ) , ... ( transactionData . confirmations && { confirmations : transactionData . confirmations } ) , _raw : { programId : transactionData . programId , ... transactionData . _raw , value : new BigNumber ( transactionData . lamports ) } } ; } export function normalizeBlock ( block ) { return { hash : block . blockhash , number : block . parentSlot + 1 , parentHash : block . previousBlockhash , size : block . blockHeight , timestamp : block . blockTime , transactions : [ ] } ; } export function validateSwapParams ( swapParams ) { validateValue ( swapParams . value ) ; validateSecretHash ( swapParams . secretHash ) ; validateExpiration ( swapParams . expiration ) ; validateAddress ( swapParams . recipientAddress ) ; validateAddress ( swapParams . refundAddress ) ; }