import bigInt from 'big-integer' ; import { JSONPath } from 'jsonpath-plus' ; import { KeyStore , Signer } from '../../../types/ExternalInterfaces' ; import * as TezosTypes from '../../../types/tezos/TezosChainTypes' ; import { TezosNodeReader } from '../TezosNodeReader' ; import { TezosNodeWriter } from '../TezosNodeWriter' ; import { TezosContractUtils } from './TezosContractUtils' ; import { TezosMessageUtils } from '../TezosMessageUtil' ; interface DexterPoolSimpleStorage { balanceMap : number ; administrator : string ; token : string ; tokenBalance : number ; xtzBalance : number ; selfIsUpdatingTokenPool : boolean ; freeze_baker : boolean ; lqt_total : number ; } /**
 * Contract wrapper for http://dexter.exchange/ pool contracts, intended for use on mainnet with KT1Puc9St8wdNoGtLiD2WXaHbWU7styaxYhD (usdtz) and KT1DrJV8vhkdLEj76h1H9Q4irZDqAkMPo1Qf (tzbtc).
 *
 * Tested on carthagenet with KT1RtNatBzmk2AvJKm9Mx6b55GcQejJneK7t.
 *
 * Based on integration documentation provided at https://gitlab.com/camlcase-dev/dexter-integration.
 */ export namespace DexterPoolHelper { const DexterPoolLiquidityOperationGasLimit = 500000 ; const DexterPoolLiquidityOperationStorageLimit = 5000 ; const DexterPoolExchangeOperationGasLimit = 500000 ; const DexterPoolExchangeOperationStorageLimit = 5000 ; const ExchangeMultiplier = 997 ; param server param address export async function verifyDestination ( server , address ) { return TezosContractUtils . verifyDestination ( server , address , 'a72954311c48dcc28279590d82870611' ) ; } param script export function verifyScript ( script ) { return TezosContractUtils . verifyScript ( script , 'yyy' ) ; } param server param address returns export async function getSimpleStorage ( server , address ) { const storageResult = await TezosNodeReader . getContractStorage ( server , address ) ; return { balanceMap : Number ( JSONPath ( { path : '$.args[0].int' , json : storageResult } ) [ 0 ] ) , administrator : JSONPath ( { path : '$.args[2].args[0].string' , json : storageResult } ) [ 0 ] , token : JSONPath ( { path : '$.args[2].args[1].string' , json : storageResult } ) [ 0 ] , tokenBalance : Number ( JSONPath ( { path : '$.args[3].int' , json : storageResult } ) [ 0 ] ) , xtzBalance : Number ( JSONPath ( { path : '$.args[4].int' , json : storageResult } ) [ 0 ] ) , selfIsUpdatingTokenPool : ( JSONPath ( { path : '$.args[1].args[0].prim' , json : storageResult } ) [ 0 ] ) . toString ( ) . toLowerCase ( ) . startsWith ( 't' ) , freeze_baker : ( JSONPath ( { path : '$.args[1].args[0].prim' , json : storageResult } ) [ 0 ] ) . toString ( ) . toLowerCase ( ) . startsWith ( 't' ) , lqt_total : Number ( JSONPath ( { path : '$.args[1].args[2].int' , json : storageResult } ) [ 0 ] ) } ; } param server param mapid param account export async function getAccountBalance ( server , mapid , account ) { try { const packedKey = TezosMessageUtils . encodeBigMapKey ( Buffer . from ( TezosMessageUtils . writePackedData ( account , 'address' ) , 'hex' ) ) ; const mapResult = await TezosNodeReader . getValueForBigMapKey ( server , mapid , packedKey ) ; if ( mapResult === undefined ) { throw new Error ( `Map ${ mapid } does not contain a record for ${ account }` ) ; } const jsonresult = JSONPath ( { path : '$.args[0].int' , json : mapResult } ) ; return Number ( jsonresult [ 0 ] ) ; } catch { return 0 ; } } param server param address param account returns export async function getAccountPoolShare ( server , address , account ) { try { const storage = await getSimpleStorage ( server , address ) ; const packedKey = TezosMessageUtils . encodeBigMapKey ( Buffer . from ( TezosMessageUtils . writePackedData ( account , 'address' ) , 'hex' ) ) ; const mapResult = await TezosNodeReader . getValueForBigMapKey ( server , storage . balanceMap , packedKey ) ; if ( mapResult === undefined ) { throw new Error ( `Map ${ storage . balanceMap } does not contain a record for ${ account }` ) ; } const poolBalance = bigInt ( JSONPath ( { path : '$.args[0].int' , json : mapResult } ) [ 0 ] ) ; const poolTotal = bigInt ( storage . lqt_total ) ; const tokenBalance = bigInt ( storage . tokenBalance ) ; const xtzBalance = bigInt ( storage . xtzBalance ) ; return { token : tokenBalance . multiply ( poolBalance ) . divide ( poolTotal ) . toJSNumber ( ) , xtz : xtzBalance . multiply ( poolBalance ) . divide ( poolTotal ) . toJSNumber ( ) } ; } catch ( error ) { return { token : 0 , xtz : 0 } ; } } param server param mapid param account param spender export async function getAccountAllowance ( server , mapid , account , spender ) { const packedKey = TezosMessageUtils . encodeBigMapKey ( Buffer . from ( TezosMessageUtils . writePackedData ( account , 'address' ) , 'hex' ) ) ; const mapResult = await TezosNodeReader . getValueForBigMapKey ( server , mapid , packedKey ) ; if ( mapResult === undefined ) { throw new Error ( `Map ${ mapid } does not contain a record for ${ account }/${ spender }` ) ; } let allowances = new Map < string , number > ( ) ; JSONPath ( { path : '$.args[1][*].args' , json : mapResult } ) . forEach ( v => allowances [ v [ 0 ] [ 'string' ] ] = Number ( v [ 1 ] [ 'int' ] ) ) ; return allowances [ spender ] || 0 ; } param server param signer param keyStore param contract param fee param liquidityAmount param xtzAmount param tokenAmount param expiration export async function addLiquidity ( server , signer , keyStore , contract , fee , liquidityAmount , xtzAmount , tokenAmount , expiration ) { const parameters = `(Pair (Pair "${ keyStore . publicKeyHash }" ${ liquidityAmount }) (Pair ${ tokenAmount } "${ expiration . toISOString ( ) }"))` ; const nodeResult = await TezosNodeWriter . sendContractInvocationOperation ( server , signer , keyStore , contract , xtzAmount , fee , DexterPoolLiquidityOperationStorageLimit , DexterPoolLiquidityOperationGasLimit , 'addLiquidity' , parameters , TezosTypes . TezosParameterFormat . Michelson ) ; return TezosContractUtils . clearRPCOperationGroupHash ( nodeResult . operationGroupID ) ; } param server param signer param keyStore param contract param fee param balance param xtzBalance param tokenBalance param expiration export async function removeLiquidity ( server , signer , keyStore , contract , fee , balance , xtzBalance , tokenBalance , expiration ) { const parameters = `(Pair (Pair "${ keyStore . publicKeyHash }" (Pair "${ keyStore . publicKeyHash }" ${ balance })) (Pair ${ xtzBalance } (Pair ${ tokenBalance } "${ expiration . toISOString ( ) }")))` ; const nodeResult = await TezosNodeWriter . sendContractInvocationOperation ( server , signer , keyStore , contract , 0 , fee , DexterPoolLiquidityOperationStorageLimit , DexterPoolLiquidityOperationGasLimit , 'removeLiquidity' , parameters , TezosTypes . TezosParameterFormat . Michelson ) ; return TezosContractUtils . clearRPCOperationGroupHash ( nodeResult . operationGroupID ) ; } param server param signer param keyStore param contract param fee param xtzAmount param tokenAmount param expiration export async function xtzToToken ( server , signer , keyStore , contract , fee , xtzAmount , tokenAmount , expiration ) { const parameters = `(Pair "${ keyStore . publicKeyHash }" (Pair ${ tokenAmount } "${ expiration . toISOString ( ) }"))` ; const nodeResult = await TezosNodeWriter . sendContractInvocationOperation ( server , signer , keyStore , contract , xtzAmount , fee , DexterPoolExchangeOperationStorageLimit , DexterPoolExchangeOperationGasLimit , 'xtzToToken' , parameters , TezosTypes . TezosParameterFormat . Michelson ) ; return TezosContractUtils . clearRPCOperationGroupHash ( nodeResult . operationGroupID ) ; } param server param signer param keyStore param contract param fee param xtzAmount param tokenAmount param expiration export async function tokenToXtz ( server , signer , keyStore , contract , fee , xtzAmount , tokenAmount , expiration ) { const parameters = `(Pair (Pair "${ keyStore . publicKeyHash }" "${ keyStore . publicKeyHash }") (Pair ${ tokenAmount } (Pair ${ xtzAmount } "${ expiration . toISOString ( ) }")))` ; const nodeResult = await TezosNodeWriter . sendContractInvocationOperation ( server , signer , keyStore , contract , 0 , fee , DexterPoolExchangeOperationStorageLimit , DexterPoolExchangeOperationGasLimit , 'tokenToXtz' , parameters , TezosTypes . TezosParameterFormat . Michelson ) ; return TezosContractUtils . clearRPCOperationGroupHash ( nodeResult . operationGroupID ) ; } param server param signer param keyStore param contract param fee param otherPoolContract param sellAmount param buyAmount param expiration export async function tokenToToken ( server , signer , keyStore , contract , fee , otherPoolContract , sellAmount , buyAmount , expiration ) { const parameters = `(Pair (Pair "${ otherPoolContract }" (Pair ${ buyAmount } "${ keyStore . publicKeyHash }")) (Pair "${ keyStore . publicKeyHash }" (Pair ${ sellAmount } "${ expiration . toISOString ( ) }")))` ; const nodeResult = await TezosNodeWriter . sendContractInvocationOperation ( server , signer , keyStore , contract , 0 , fee , DexterPoolExchangeOperationStorageLimit , 1000000 , 'tokenToToken' , parameters , TezosTypes . TezosParameterFormat . Michelson ) ; return TezosContractUtils . clearRPCOperationGroupHash ( nodeResult . operationGroupID ) ; } param server param signer param keyStore param contract param fee param spender param newAllowance param currentAllowance export async function approve ( server , signer , keyStore , contract , fee , spender , newAllowance , currentAllowance ) { const parameters = `(Pair "${ spender }" (Pair ${ newAllowance } ${ currentAllowance }))` ; const nodeResult = await TezosNodeWriter . sendContractInvocationOperation ( server , signer , keyStore , contract , 0 , fee , DexterPoolExchangeOperationStorageLimit , DexterPoolExchangeOperationGasLimit , 'approve' , parameters , TezosTypes . TezosParameterFormat . Michelson ) ; return TezosContractUtils . clearRPCOperationGroupHash ( nodeResult . operationGroupID ) ; } /**
     * Show pending applied operations against this contract in the mempool
     */ export async function previewTransactions ( ) { } param xtzDeposit param tokenBalance param xtzBalance return { number } export function calcTokenLiquidityRequirement ( xtzDeposit , tokenBalance , xtzBalance ) { return bigInt ( xtzDeposit ) . multiply ( bigInt ( tokenBalance ) ) . divide ( bigInt ( xtzBalance ) ) . toJSNumber ( ) ; } param xtzAmount param tokenBalance param xtzBalance export function getTokenExchangeRate ( xtzAmount , tokenBalance , xtzBalance , xtzDecimals = 6 ) { const n = bigInt ( xtzAmount ) . multiply ( bigInt ( tokenBalance ) ) . multiply ( bigInt ( ExchangeMultiplier ) ) ; const d = bigInt ( xtzBalance ) . multiply ( bigInt ( 1000 ) ) . add ( bigInt ( xtzAmount ) . multiply ( bigInt ( ExchangeMultiplier ) ) ) ; const tokenAmount = n . divide ( d ) ; const dm = tokenAmount . divmod ( bigInt ( xtzAmount ) ) ; const f = dm . remainder . multiply ( bigInt ( 10 ** xtzDecimals ) ) . divide ( bigInt ( xtzAmount ) ) ; return { tokenAmount : tokenAmount . toJSNumber ( ) , rate : parseFloat ( `${ dm . quotient . toJSNumber ( ) }.${ f . toJSNumber ( ) }` ) } ; } param tokenAmount param tokenBalance param xtzBalance export function getXTZExchangeRate ( tokenAmount , tokenBalance , xtzBalance , tokenDecimals = 6 ) { const n = bigInt ( tokenAmount ) . multiply ( bigInt ( xtzBalance ) ) . multiply ( bigInt ( ExchangeMultiplier ) ) ; const d = bigInt ( tokenBalance ) . multiply ( bigInt ( 1000 ) ) . add ( bigInt ( tokenAmount ) . multiply ( bigInt ( ExchangeMultiplier ) ) ) ; const xtzAmount = n . divide ( d ) ; const dm = xtzAmount . divmod ( bigInt ( tokenAmount ) ) ; const f = dm . remainder . multiply ( bigInt ( 10 ** tokenDecimals ) ) . divide ( bigInt ( tokenAmount ) ) ; return { xtzAmount : xtzAmount . toJSNumber ( ) , rate : parseFloat ( `${ dm . quotient . toJSNumber ( ) }.${ f . toJSNumber ( ) }` ) } ; } param xtzDeposit param liquidityBalance param xtzBalance export function estimateLiquidityAmount ( xtzDeposit , liquidityBalance , xtzBalance ) { return bigInt ( xtzDeposit ) . multiply ( bigInt ( liquidityBalance ) ) . divide ( bigInt ( xtzBalance ) ) . toJSNumber ( ) ; } /**
     * Estimates the cost of buying 1% share of the pool in terms of XTZ
     */ export function estimateShareCost ( xtzBalance , tokenBalance , liquidityBalance ) { const xtzShare = bigInt ( xtzBalance ) . divide ( bigInt ( 99 ) ) . toJSNumber ( ) ; const tokenShare = calcTokenLiquidityRequirement ( xtzShare , tokenBalance , xtzBalance ) ; return { xtzCost : xtzShare , tokenCost : tokenShare } ; } }