packages/jellyfish-transaction/src/script/dftx/dftx_pool.ts
import BigNumber from 'bignumber.js'
import { BufferComposer, ComposableBuffer, readCompactSize, writeCompactSize } from '@defichain/jellyfish-buffer'
import { Script } from '../../tx'
import { CScript } from '../../tx_composer'
import { SmartBuffer } from 'smart-buffer'
import { CScriptBalances, CTokenBalance, ScriptBalances, TokenBalanceUInt32 } from './dftx_balance'
/**
* PoolSwap DeFi Transaction
*/
export interface PoolSwap {
fromScript: Script // ----------------| n = VarUInt{1-9 bytes}, + n bytes
fromTokenId: number // ---------------| VarInt{MSB-b128}
fromAmount: BigNumber // -------------| 8 bytes
toScript: Script // ------------------| n = VarUInt{1-9 bytes}, + n bytes
toTokenId: number // -----------------| VarInt{MSB-b128}
maxPrice: BigNumber // ---------------| 8 bytes integer + 8 bytes for fraction
}
/**
* Composable PoolSwap, C stands for Composable.
* Immutable by design, bi-directional fromBuffer, toBuffer deep composer.
* @throws Error if more than 8 decimals
*/
export class CPoolSwap extends ComposableBuffer<PoolSwap> {
static OP_CODE = 0x73
static OP_NAME = 'OP_DEFI_TX_POOL_SWAP'
composers (ps: PoolSwap): BufferComposer[] {
return [
ComposableBuffer.single<Script>(() => ps.fromScript, v => ps.fromScript = v, v => new CScript(v)),
ComposableBuffer.varInt(() => ps.fromTokenId, v => ps.fromTokenId = v),
ComposableBuffer.satoshiAsBigNumber(() => ps.fromAmount, v => ps.fromAmount = v),
ComposableBuffer.single<Script>(() => ps.toScript, v => ps.toScript = v, v => new CScript(v)),
ComposableBuffer.varInt(() => ps.toTokenId, v => ps.toTokenId = v),
ComposableBuffer.maxPriceAsBigNumber(() => ps.maxPrice, v => ps.maxPrice = v)
]
}
}
export interface PoolId {
id: number // ------------------------| VarInt{MSB-b128}
}
/**
* Composable PoolId, C stands for Composable.
* Immutable by design, bi-directional fromBuffer, toBuffer deep composer.
*/
export class CPoolId extends ComposableBuffer<PoolId> {
composers (pi: PoolId): BufferComposer[] {
return [
ComposableBuffer.varInt(() => pi.id, v => pi.id = v)
]
}
}
/**
* CompositeSwap DeFi Transaction
*/
export interface CompositeSwap {
poolSwap: PoolSwap // ----------------| 1 x PoolSwap
pools: PoolId[] // -------------------| n = VarUInt{1-9 bytes}, + n bytes
}
/**
* Composable CompositeSwap, C stands for Composable.
* Extends from CPoolSwap as it contains same data structure but with different DfTx OP_CODE.
* Immutable by design, bi-directional fromBuffer, toBuffer deep composer.
* @throws Error if more than 8 decimals
*/
export class CCompositeSwap extends ComposableBuffer<CompositeSwap> {
static OP_CODE = 0x69 // 'i'
static OP_NAME = 'OP_DEFI_TX_COMPOSITE_SWAP'
composers (cs: CompositeSwap): BufferComposer[] {
return [
ComposableBuffer.single<PoolSwap>(() => cs.poolSwap, v => cs.poolSwap = v, v => new CPoolSwap(v)),
ComposableBuffer.compactSizeArray<PoolId>(() => cs.pools, v => cs.pools = v, v => new CPoolId(v))
]
}
}
/**
* PoolAddLiquidity DeFi Transaction
*/
export interface PoolAddLiquidity {
from: ScriptBalances[] // ------------| c = VarUInt{1-9 bytes}, + c x ScriptBalances
shareAddress: Script // --------------| n = VarUInt{1-9 bytes}, + n bytes
}
/**
* Composable PoolAddLiquidity, C stands for Composable.
* Immutable by design, bi-directional fromBuffer, toBuffer deep composer.
*/
export class CPoolAddLiquidity extends ComposableBuffer<PoolAddLiquidity> {
static OP_CODE = 0x6c
static OP_NAME = 'OP_DEFI_TX_POOL_ADD_LIQUIDITY'
composers (p: PoolAddLiquidity): BufferComposer[] {
return [
ComposableBuffer.compactSizeArray(() => p.from, v => p.from = v, v => new CScriptBalances(v)),
ComposableBuffer.single<Script>(() => p.shareAddress, v => p.shareAddress = v, v => new CScript(v))
]
}
}
/**
* PoolRemoveLiquidity DeFi Transaction
*/
export interface PoolRemoveLiquidity {
script: Script // --------------------| n = VarUInt{1-9 bytes}, + n bytes
tokenId: number // -------------------| VarInt{MSB-b128}
amount: BigNumber // -----------------| 8 bytes
}
/**
* Composable PoolRemoveLiquidity, C stands for Composable.
* Immutable by design, bi-directional fromBuffer, toBuffer deep composer.
*/
export class CPoolRemoveLiquidity extends ComposableBuffer<PoolRemoveLiquidity> {
static OP_CODE = 0x72
static OP_NAME = 'OP_DEFI_TX_POOL_REMOVE_LIQUIDITY'
composers (p: PoolRemoveLiquidity): BufferComposer[] {
return [
ComposableBuffer.single<Script>(() => p.script, v => p.script = v, v => new CScript(v)),
ComposableBuffer.varInt(() => p.tokenId, v => p.tokenId = v),
ComposableBuffer.satoshiAsBigNumber(() => p.amount, v => p.amount = v)
]
}
}
/**
* PoolCreatePair DeFi Transaction
*/
export interface PoolCreatePair {
tokenA: number // -----------------------| VarInt{MSB-b128}
tokenB: number // -----------------------| VarInt{MSB-b128}
commission: BigNumber // ----------------| 8 bytes
ownerAddress: Script // -----------------| n = VarUInt{1-9 bytes}, + n bytes
status: boolean // ----------------------| 1 byte
pairSymbol: string // -------------------| VarUInt{1-9 bytes}, + c bytes UTF encoded string
customRewards: TokenBalanceUInt32[] // --| c = VarUInt{1-9 bytes}, + c x TokenBalance
}
/**
* Composable PoolCreatePair, C stands for Composable.
* Immutable by design, bi-directional fromBuffer, toBuffer deep composer.
*/
export class CPoolCreatePair extends ComposableBuffer<PoolCreatePair> {
static OP_CODE = 0x70
static OP_NAME = 'OP_DEFI_TX_POOL_CREATE_PAIR'
composers (p: PoolCreatePair): BufferComposer[] {
return [
ComposableBuffer.varInt(() => p.tokenA, v => p.tokenA = v),
ComposableBuffer.varInt(() => p.tokenB, v => p.tokenB = v),
ComposableBuffer.satoshiAsBigNumber(() => p.commission, v => p.commission = v),
ComposableBuffer.single<Script>(() => p.ownerAddress, v => p.ownerAddress = v, v => new CScript(v)),
ComposableBuffer.uBool8(() => p.status, v => p.status = v),
ComposableBuffer.compactSizeUtf8BE(() => p.pairSymbol, v => p.pairSymbol = v),
// Note(canonbrother): special fix for inconsistent bytes in "block height >= ClarkeQuayHeight" condition
// https://github.com/DeFiCh/ain/blob/4b70ecd8ee32d00c75be04a786dc75ec4a3c91dd/src/masternodes/rpc_poolpair.cpp#L571-L573
{
fromBuffer: (buffer: SmartBuffer): void => {
if (buffer.remaining() > 0) {
const length = readCompactSize(buffer)
p.customRewards = []
for (let i = 0; i < length; i++) {
p.customRewards.push(new CTokenBalance(buffer).toObject())
}
}
},
toBuffer: (buffer: SmartBuffer): void => {
if (p.customRewards !== undefined) {
writeCompactSize(p.customRewards.length, buffer)
p.customRewards.forEach(data => new CTokenBalance(data).toBuffer(buffer))
}
}
}
]
}
}
/**
* PoolUpdatePair DeFi Transaction
*/
export interface PoolUpdatePair {
poolId: number // -----------------------| VarInt{MSB-b128}
status: boolean // ----------------------| 4 bytes
commission: BigNumber // ----------------| 8 bytes
ownerAddress: Script // -----------------| n = VarUInt{1-9 bytes}, + n bytes
customRewards: TokenBalanceUInt32[] // --| c = VarUInt{1-9 bytes}, + c x TokenBalance
}
/**
* Composable PoolUpdatePair, C stands for Composable.
* Immutable by design, bi-directional fromBuffer, toBuffer deep composer.
*/
export class CPoolUpdatePair extends ComposableBuffer<PoolUpdatePair> {
static OP_CODE = 0x75
static OP_NAME = 'OP_DEFI_TX_POOL_UPDATE_PAIR'
composers (p: PoolUpdatePair): BufferComposer[] {
return [
ComposableBuffer.varInt(() => p.poolId, v => p.poolId = v),
ComposableBuffer.uBool32(() => p.status, v => p.status = v),
ComposableBuffer.satoshiAsBigNumber(() => p.commission, v => p.commission = v),
ComposableBuffer.single<Script>(() => p.ownerAddress, v => p.ownerAddress = v, v => new CScript(v)),
// Note(canonbrother): special fix for inconsistent bytes in "block height >= ClarkeQuayHeight" condition
// https://github.com/DeFiCh/ain/blob/4b70ecd8ee32d00c75be04a786dc75ec4a3c91dd/src/masternodes/rpc_poolpair.cpp#L719-721
{
fromBuffer: (buffer: SmartBuffer): void => {
if (buffer.remaining() > 0) {
const length = readCompactSize(buffer)
p.customRewards = []
for (let i = 0; i < length; i++) {
p.customRewards.push(new CTokenBalance(buffer).toObject())
}
}
},
toBuffer: (buffer: SmartBuffer): void => {
if (p.customRewards !== undefined) {
writeCompactSize(p.customRewards.length, buffer)
p.customRewards.forEach(data => new CTokenBalance(data).toBuffer(buffer))
}
}
}
]
}
}