import { BigNumber } from 'bignumber.js' ; import BigInt from '../../common/bigInt' ; import { TOKEN_TYPE } from '../../consts' ; import { Address } from '../../crypto' ; import { ERROR_CODE } from '../../error' ; import { Transaction } from '../../transaction/transaction' ; import { makeNativeContractTx } from '../../transaction/transactionUtils' ; import { Transfer } from '../../transaction/transfer' ; import { hex2VarBytes , hexstr2str , StringReader } from '../../utils' ; import { buildNativeCodeScript } from '../abi/nativeVmParamsBuilder' ; import Struct from './../abi/struct' ; import { State } from './token' ; export const ONT_CONTRACT = '0000000000000000000000000000000000000001' ; export const ONG_CONTRACT = '0000000000000000000000000000000000000002' ; param tokenType export function getTokenContract ( tokenType ) { if ( tokenType === TOKEN_TYPE . ONT ) { return new Address ( ONT_CONTRACT ) ; } else if ( tokenType === TOKEN_TYPE . ONG ) { return new Address ( ONG_CONTRACT ) ; } else { throw new Error ( 'Error token type.' ) ; } } param amount export function verifyAmount ( amount ) { const value = new BigNumber ( amount ) ; if ( ! value . isInteger ( ) || value . lte ( new BigNumber ( 0 ) ) ) { throw new Error ( 'Amount is invalid.' ) ; } } param tokenType param from param to param amount param gasPrice param gasLimit param payer export function makeTransferTx ( tokenType , from , to , amount , gasPrice , gasLimit , payer ? ) { verifyAmount ( amount ) ; const num = new BigNumber ( amount ) ; const struct = new Struct ( ) ; struct . add ( from , to , num ) ; const list = [ ] ; list . push ( [ struct ] ) ; const contract = getTokenContract ( tokenType ) ; const params = buildNativeCodeScript ( list ) ; const tx = makeNativeContractTx ( 'transfer' , params , contract , gasPrice , gasLimit ) as any ; tx . tokenType = tokenType ; tx . from = from ; tx . to = to ; tx . amount = amount ; tx . method = 'transfer' ; if ( payer ) { tx . payer = payer ; } else { tx . payer = from ; } return tx ; } param tokenType param from param to param amount param gasPrice param gasLimit param payer export function makeTransferTxV2 ( tokenType , from , to , amount , gasPrice , gasLimit , payer ? ) { verifyAmount ( amount ) ; const num = new BigNumber ( amount ) ; const struct = new Struct ( ) ; struct . add ( from , to , num ) ; const list = [ ] ; list . push ( [ struct ] ) ; const contract = getTokenContract ( tokenType ) ; const params = buildNativeCodeScript ( list ) ; const tx = makeNativeContractTx ( 'transferV2' , params , contract , gasPrice , gasLimit ) as any ; tx . tokenType = tokenType ; tx . from = from ; tx . to = to ; tx . amount = amount ; tx . method = 'transferV2' ; if ( payer ) { tx . payer = payer ; } else { tx . payer = from ; } return tx ; } param tokenType param from param to param amounts export function makeTransferStateTx ( tokenType , states , gasPrice , gasLimit , payer ? ) { const structs = [ ] ; for ( const state of states ) { verifyAmount ( state . value ) ; const s = new Struct ( ) ; s . add ( state . from , state . to , new BigNumber ( state . value ) ) ; structs . push ( s ) ; } const list = [ ] ; list . push ( structs ) ; const params = buildNativeCodeScript ( list ) ; const contract = getTokenContract ( tokenType ) ; const tx = makeNativeContractTx ( 'transfer' , params , contract , gasPrice , gasLimit ) ; if ( payer ) { tx . payer = payer ; } return tx ; } param tokenType param from param to param amounts export function makeTransferStateTxV2 ( tokenType , states , gasPrice , gasLimit , payer ? ) { const structs = [ ] ; for ( const state of states ) { verifyAmount ( state . value ) ; const s = new Struct ( ) ; s . add ( state . from , state . to , new BigNumber ( state . value ) ) ; structs . push ( s ) ; } const list = [ ] ; list . push ( structs ) ; const params = buildNativeCodeScript ( list ) ; const contract = getTokenContract ( tokenType ) ; const tx = makeNativeContractTx ( 'transferV2' , params , contract , gasPrice , gasLimit ) ; if ( payer ) { tx . payer = payer ; } return tx ; } param tokenType param from param to param amounts export function makeTransferToMany ( tokenType , from , to , amounts , gasPrice , gasLimit ) { if ( to . length !== amounts . length ) { throw new Error ( 'Params error.' ) ; } const structs = [ ] ; for ( let i = 0 ; i < to . length ; i ++ ) { verifyAmount ( amounts [ i ] ) ; const s = new Struct ( ) ; s . add ( from , to [ i ] , new BigNumber ( amounts [ i ] ) ) ; structs . push ( s ) ; } const list = [ ] ; list . push ( structs ) ; const contract = getTokenContract ( tokenType ) ; const params = buildNativeCodeScript ( list ) ; const tx = makeNativeContractTx ( 'transfer' , params , contract , gasPrice , gasLimit ) as any ; tx . payer = from ; return tx ; } param tokenType param from param to param amounts export function makeTransferToManyV2 ( tokenType , from , to , amounts , gasPrice , gasLimit ) { if ( to . length !== amounts . length ) { throw new Error ( 'Params error.' ) ; } const structs = [ ] ; for ( let i = 0 ; i < to . length ; i ++ ) { verifyAmount ( amounts [ i ] ) ; const s = new Struct ( ) ; s . add ( from , to [ i ] , new BigNumber ( amounts [ i ] ) ) ; structs . push ( s ) ; } const list = [ ] ; list . push ( structs ) ; const contract = getTokenContract ( tokenType ) ; const params = buildNativeCodeScript ( list ) ; const tx = makeNativeContractTx ( 'transferV2' , params , contract , gasPrice , gasLimit ) as any ; tx . payer = from ; return tx ; } param from param to param amount param payer param gasPrice param gasLimit export function makeWithdrawOngTx ( from , to , amount , payer , gasPrice , gasLimit ) { verifyAmount ( amount ) ; const num = new BigNumber ( amount ) ; const list = [ ] ; const struct = new Struct ( ) ; struct . add ( from , new Address ( ONT_CONTRACT ) , to , num ) ; list . push ( struct ) ; const args = buildNativeCodeScript ( list ) ; const tx = makeNativeContractTx ( 'transferFrom' , args , new Address ( ONG_CONTRACT ) , gasPrice , gasLimit ) as any ; tx . payer = payer ; tx . tokenType = 'ONG' ; tx . from = from ; tx . to = to ; tx . amount = amount ; tx . method = 'transferFrom' ; return tx ; } param from param to param amount param payer param gasPrice param gasLimit export function makeWithdrawOngTxV2 ( from , to , amount , payer , gasPrice , gasLimit ) { verifyAmount ( amount ) ; const num = new BigNumber ( amount ) ; const list = [ ] ; const struct = new Struct ( ) ; struct . add ( from , new Address ( ONT_CONTRACT ) , to , num ) ; list . push ( struct ) ; const args = buildNativeCodeScript ( list ) ; const tx = makeNativeContractTx ( 'transferFromV2' , args , new Address ( ONG_CONTRACT ) , gasPrice , gasLimit ) as any ; tx . payer = payer ; tx . tokenType = 'ONG' ; tx . from = from ; tx . to = to ; tx . amount = amount ; tx . method = 'transferFromV2' ; return tx ; } param asset param from param to export function makeQueryAllowanceTx ( asset , from , to ) { asset = asset . toLowerCase ( ) ; if ( asset !== 'ont' && asset !== 'ong' ) { throw ERROR_CODE . INVALID_PARAMS ; } let contract = '' ; if ( asset === 'ong' ) { contract = ONG_CONTRACT ; } else { contract = ONT_CONTRACT ; } const list = [ ] ; const struct = new Struct ( ) ; struct . add ( from , to ) ; list . push ( struct ) ; const params = buildNativeCodeScript ( list ) ; const tx = makeNativeContractTx ( 'allowance' , params , new Address ( contract ) , '0' , '0' ) ; return tx ; } param asset param from param to export function makeQueryAllowanceTxV2 ( asset , from , to ) { asset = asset . toLowerCase ( ) ; if ( asset !== 'ont' && asset !== 'ong' ) { throw ERROR_CODE . INVALID_PARAMS ; } let contract = '' ; if ( asset === 'ong' ) { contract = ONG_CONTRACT ; } else { contract = ONT_CONTRACT ; } const list = [ ] ; const struct = new Struct ( ) ; struct . add ( from , to ) ; list . push ( struct ) ; const params = buildNativeCodeScript ( list ) ; const tx = makeNativeContractTx ( 'allowanceV2' , params , new Address ( contract ) , '0' , '0' ) ; return tx ; } param asset param address export function makeQueryBalanceTx ( asset , address ) { asset = asset . toLowerCase ( ) ; if ( asset !== 'ont' && asset !== 'ong' ) { throw ERROR_CODE . INVALID_PARAMS ; } let contract = '' ; if ( asset === 'ong' ) { contract = ONG_CONTRACT ; } else { contract = ONT_CONTRACT ; } const params = hex2VarBytes ( address . serialize ( ) ) ; const tx = makeNativeContractTx ( 'balanceOf' , params , new Address ( contract ) , '0' , '0' ) ; return tx ; } param asset param address export function makeQueryBalanceTxV2 ( asset , address ) { asset = asset . toLowerCase ( ) ; if ( asset !== 'ont' && asset !== 'ong' ) { throw ERROR_CODE . INVALID_PARAMS ; } let contract = '' ; if ( asset === 'ong' ) { contract = ONG_CONTRACT ; } else { contract = ONT_CONTRACT ; } const params = hex2VarBytes ( address . serialize ( ) ) ; const tx = makeNativeContractTx ( 'balanceOfV2' , params , new Address ( contract ) , '0' , '0' ) ; return tx ; } export function deserializeTransferTx ( str ) { const tx = Transaction . deserialize ( str ) as any ; const code = tx . payload . serialize ( ) ; const contractIndex1 = code . lastIndexOf ( '14' + '000000000000000000000000000000000000000' ) ; const contractIndex2 = code . lastIndexOf ( '14' + '0000000000000000000000000000000000000002' ) ; if ( contractIndex1 > 0 && code . substr ( contractIndex1 + 41 , 1 ) === '1' ) { tx . tokenType = 'ONT' ; } else if ( contractIndex1 > 0 && code . substr ( contractIndex1 + 41 , 1 ) === '2' ) { tx . tokenType = 'ONG' ; } else { throw new Error ( 'Not a transfer tx' ) ; } const contractIndex = Math . max ( contractIndex1 , contractIndex2 ) ; const params = code . substring ( 0 , contractIndex ) ; const paramsEnd = params . indexOf ( '6a7cc86c' ) + 8 ; if ( params . substr ( paramsEnd , 4 ) === '51c1' ) { const methodStr = params . substring ( paramsEnd + 6 ) ; tx . method = hexstr2str ( methodStr ) ; } else { const methodStr = params . substring ( paramsEnd + 2 ) ; tx . method = hexstr2str ( methodStr ) ; } if ( tx . method === 'transfer' ) { const sr = new StringReader ( params ) ; sr . pos += 10 ; const from = new Address ( sr . read ( 20 ) ) ; tx . from = from ; sr . pos += 8 ; const to = new Address ( sr . read ( 20 ) ) ; tx . to = to ; sr . pos += 6 ; const numTmp = parseInt ( sr . read ( 1 ) , 16 ) ; if ( sr . str . substr ( sr . pos , 6 ) === '6a7cc8' ) { tx . amount = numTmp - 80 ; } else { const amount = BigInt . fromHexstr ( sr . read ( numTmp ) ) . value ; tx . amount = new BigNumber ( amount ) . toString ( ) ; } } else if ( tx . method === 'transferFrom' ) { const sr = new StringReader ( params ) ; sr . pos += 10 ; const from = new Address ( sr . read ( 20 ) ) ; tx . from = from ; sr . pos += 56 ; const to = new Address ( sr . read ( 20 ) ) ; tx . to = to ; sr . pos += 6 ; const numTmp = parseInt ( sr . read ( 1 ) , 16 ) ; if ( sr . str . substr ( sr . pos , 6 ) === '6a7cc8' ) { tx . amount = numTmp - 80 ; } else { const amount = BigInt . fromHexstr ( sr . read ( numTmp ) ) . value ; tx . amount = new BigNumber ( amount ) . toString ( ) ; } } else { throw new Error ( 'Not a transfer tx' ) ; } return tx ; } export function deserializeTransferTxV2 ( str ) { const tx = Transaction . deserialize ( str ) as any ; const code = tx . payload . serialize ( ) ; const contractIndex1 = code . lastIndexOf ( '14' + '000000000000000000000000000000000000000' ) ; const contractIndex2 = code . lastIndexOf ( '14' + '0000000000000000000000000000000000000002' ) ; if ( contractIndex1 > 0 && code . substr ( contractIndex1 + 41 , 1 ) === '1' ) { tx . tokenType = 'ONT' ; } else if ( contractIndex1 > 0 && code . substr ( contractIndex1 + 41 , 1 ) === '2' ) { tx . tokenType = 'ONG' ; } else { throw new Error ( 'Not a transfer tx' ) ; } const contractIndex = Math . max ( contractIndex1 , contractIndex2 ) ; const params = code . substring ( 0 , contractIndex ) ; const paramsEnd = params . indexOf ( '6a7cc86c' ) + 8 ; if ( params . substr ( paramsEnd , 4 ) === '51c1' ) { const methodStr = params . substring ( paramsEnd + 6 ) ; tx . method = hexstr2str ( methodStr ) ; } else { const methodStr = params . substring ( paramsEnd + 2 ) ; tx . method = hexstr2str ( methodStr ) ; } if ( tx . method === 'transferV2' ) { const sr = new StringReader ( params ) ; sr . pos += 10 ; const from = new Address ( sr . read ( 20 ) ) ; tx . from = from ; sr . pos += 8 ; const to = new Address ( sr . read ( 20 ) ) ; tx . to = to ; sr . pos += 6 ; const numTmp = parseInt ( sr . read ( 1 ) , 16 ) ; if ( sr . str . substr ( sr . pos , 6 ) === '6a7cc8' ) { tx . amount = numTmp - 80 ; } else { const amount = BigInt . fromHexstr ( sr . read ( numTmp ) ) . value ; tx . amount = new BigNumber ( amount ) . toString ( ) ; } } else if ( tx . method === 'transferFromV2' ) { const sr = new StringReader ( params ) ; sr . pos += 10 ; const from = new Address ( sr . read ( 20 ) ) ; tx . from = from ; sr . pos += 56 ; const to = new Address ( sr . read ( 20 ) ) ; tx . to = to ; sr . pos += 6 ; const numTmp = parseInt ( sr . read ( 1 ) , 16 ) ; if ( sr . str . substr ( sr . pos , 6 ) === '6a7cc8' ) { tx . amount = numTmp - 80 ; } else { const amount = BigInt . fromHexstr ( sr . read ( numTmp ) ) . value ; tx . amount = new BigNumber ( amount ) . toString ( ) ; } } else { throw new Error ( 'Not a transfer tx' ) ; } return tx ; }