Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DfTx PoolUpdatePair #314

Merged
merged 7 commits into from
Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@ dist
lerna-debug.log

coverage

# vscode
.vscode
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import BigNumber from 'bignumber.js'
import { SmartBuffer } from 'smart-buffer'
import { OP_DEFI_TX } from '../../../../src/script/defi'
import { CPoolUpdatePair, PoolUpdatePair } from '../../../../src/script/defi/dftx_pool'
import { OP_CODES } from '../../../../src'
import { toBuffer, toOPCodes } from '../../../../src/script/_buffer'

it('should bi-directional buffer-object-buffer', () => {
const fixtures = [
// regtest fixtures
// height >= ClarkeQuayHeight (encoding includes customRewards)
// status, commission
'6a144466547875020000000100e1f505000000000000',
// ownerAddress
'6a2b44665478750200000000ffffffffffffffff17a91440d54b7a72387cb5c6d0125f2890eabf052f01908700',
// customRewards 2 tokens
'6a2c44665478750200000000ffffffffffffffff00020000000000e1f505000000000100000000a3e11100000000',
// customRewards 1 token
'6a2044665478750200000000ffffffffffffffff0001000000000008af2f00000000',
// all
'6a434466547875020000000120a107000000000017a914fd190704714762e6c30eb5b39071c1a52e6130ad87020000000000ca9a3b00000000010000000094357700000000',

// height < ClarkeQuayHeight (exclude customRewards from being encoded)
// all
'6a2a44665478750300000001c0cf6a000000000017a9141205616a55fbbdd91ec97e222fae709acc4fd2c887'
]

fixtures.forEach(hex => {
const stack: any = toOPCodes(
SmartBuffer.fromBuffer(Buffer.from(hex, 'hex'))
)
const buffer = toBuffer(stack)
expect((stack[1] as OP_DEFI_TX).tx.type).toBe(0x75)
expect(buffer.toString('hex')).toBe(hex)
})
})

const header = '6a434466547875' // OP_RETURN, PUSH_DATA(44665478, 75)
const data = '020000000120a107000000000017a914fd190704714762e6c30eb5b39071c1a52e6130ad87020000000000ca9a3b00000000010000000094357700000000'
const poolUpdatePair: PoolUpdatePair = {
poolId: 2,
status: true,
commission: new BigNumber('0.005'),
ownerAddress: {
stack: [
OP_CODES.OP_HASH160,
OP_CODES.OP_PUSHDATA_HEX_LE('fd190704714762e6c30eb5b39071c1a52e6130ad'),
OP_CODES.OP_EQUAL
]
},
customRewards: [
{ token: 0, amount: new BigNumber('10') },
{ token: 1, amount: new BigNumber('20') }
]
}

it('should craft dftx with OP_CODES._()', () => {
const stack = [
OP_CODES.OP_RETURN,
OP_CODES.OP_DEFI_TX_POOL_UPDATE_PAIR(poolUpdatePair)
]

const buffer = toBuffer(stack)
expect(buffer.toString('hex')).toBe(header + data)
})

describe('Composable', () => {
it('should compose from buffer to composable', () => {
const buffer = SmartBuffer.fromBuffer(Buffer.from(data, 'hex'))
const composable = new CPoolUpdatePair(buffer)

expect(composable.toObject()).toEqual(poolUpdatePair)
})

it('should compose from composable to buffer', () => {
const composable = new CPoolUpdatePair(poolUpdatePair)
const buffer = new SmartBuffer()
composable.toBuffer(buffer)

expect(buffer.toBuffer().toString('hex')).toEqual(data)
})
})
19 changes: 19 additions & 0 deletions packages/jellyfish-transaction/src/buffer/buffer_composer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,4 +498,23 @@ export abstract class ComposableBuffer<T> implements BufferComposer {
}
}
}

/**
* Unsigned Boolean 4 bytes, 1 = true, 0 = false
*
* @param getter to read from to buffer
* @param setter to set to from buffer
* @returns
canonbrother marked this conversation as resolved.
Show resolved Hide resolved
*/
static uBool32 (getter: () => boolean, setter: (data: boolean) => void): BufferComposer {
return {
fromBuffer: (buffer: SmartBuffer): void => {
setter(buffer.readInt32BE() === 1)
},
toBuffer: (buffer: SmartBuffer): void => {
var v = getter().toString().toLowerCase() === 'true' ? 1 : 0
canonbrother marked this conversation as resolved.
Show resolved Hide resolved
buffer.writeBuffer(Buffer.from([0, 0, 0, v]))
}
}
}
canonbrother marked this conversation as resolved.
Show resolved Hide resolved
}
6 changes: 4 additions & 2 deletions packages/jellyfish-transaction/src/script/defi/dftx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import {
import { CCreateMasterNode, CreateMasterNode, CResignMasterNode, ResignMasterNode } from './dftx_masternode'
import { CAutoAuthPrep } from './dftx_misc'
import {
CPoolAddLiquidity, CPoolRemoveLiquidity, CPoolSwap, PoolAddLiquidity, PoolRemoveLiquidity,
PoolSwap
CPoolAddLiquidity, CPoolRemoveLiquidity, CPoolSwap, CPoolUpdatePair, PoolAddLiquidity, PoolRemoveLiquidity,
PoolSwap, PoolUpdatePair
} from './dftx_pool'
import { CTokenCreate, CTokenMint, CTokenUpdate, CTokenUpdateAny, TokenCreate, TokenMint, TokenUpdate, TokenUpdateAny } from './dftx_token'
import {
Expand Down Expand Up @@ -110,6 +110,8 @@ export class CDfTx extends ComposableBuffer<DfTx<any>> {
return compose<PoolAddLiquidity>(CPoolAddLiquidity.OP_NAME, d => new CPoolAddLiquidity(d))
case CPoolRemoveLiquidity.OP_CODE:
return compose<PoolRemoveLiquidity>(CPoolRemoveLiquidity.OP_NAME, d => new CPoolRemoveLiquidity(d))
case CPoolUpdatePair.OP_CODE:
return compose<PoolUpdatePair>(CPoolUpdatePair.OP_NAME, d => new CPoolUpdatePair(d))
case CTokenMint.OP_CODE:
return compose<TokenMint>(CTokenMint.OP_NAME, d => new CTokenMint(d))
case CTokenCreate.OP_CODE:
Expand Down
51 changes: 50 additions & 1 deletion packages/jellyfish-transaction/src/script/defi/dftx_pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { Script } from '../../tx'
import { CScript } from '../../tx_composer'
import { SmartBuffer } from 'smart-buffer'
import { readBigNumberUInt64, writeBigNumberUInt64 } from '../../buffer/buffer_bignumber'
import { CScriptBalances, ScriptBalances } from './dftx_balance'
import { CScriptBalances, ScriptBalances, CTokenBalance, TokenBalance } from './dftx_balance'
import { writeVarUInt, readVarUInt } from '../../buffer/buffer_varuint'

// Disabling no-return-assign makes the code cleaner with the setter and getter */
/* eslint-disable no-return-assign */
Expand Down Expand Up @@ -104,3 +105,51 @@ export class CPoolRemoveLiquidity extends ComposableBuffer<PoolRemoveLiquidity>
]
}
}

/**
* PoolUpdatePair DeFi Transaction
*/
export interface PoolUpdatePair {
poolId: number // -----------------------| VarUInt{1-9 bytes}
status: boolean // ----------------------| 4 bytes
commission: BigNumber // ----------------| 8 bytes
ownerAddress: Script // -----------------| n = VarUInt{1-9 bytes}, + n bytes
customRewards: TokenBalance[] // --------| 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[] {
fuxingloh marked this conversation as resolved.
Show resolved Hide resolved
return [
ComposableBuffer.varUInt(() => 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 = readVarUInt(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) {
writeVarUInt(p.customRewards.length, buffer)
p.customRewards.forEach(data => new CTokenBalance(data).toBuffer(buffer))
}
}
fuxingloh marked this conversation as resolved.
Show resolved Hide resolved
}
]
}
}
12 changes: 11 additions & 1 deletion packages/jellyfish-transaction/src/script/mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import {
CPoolAddLiquidity,
CPoolRemoveLiquidity,
CPoolSwap,
CPoolUpdatePair,
PoolAddLiquidity,
PoolRemoveLiquidity,
PoolSwap
PoolSwap,
PoolUpdatePair
} from './defi/dftx_pool'
import { CTokenCreate, CTokenUpdate, CTokenUpdateAny, CTokenMint, TokenCreate, TokenUpdate, TokenUpdateAny, TokenMint } from './defi/dftx_token'
import {
Expand Down Expand Up @@ -154,6 +156,14 @@ export const OP_CODES = {
data: poolRemoveLiquidity
})
},
OP_DEFI_TX_POOL_UPDATE_PAIR: (poolCreatePair: PoolUpdatePair): OP_DEFI_TX => {
return new OP_DEFI_TX({
signature: CDfTx.SIGNATURE,
type: CPoolUpdatePair.OP_CODE,
name: CPoolUpdatePair.OP_NAME,
data: poolCreatePair
})
},
OP_DEFI_TX_TOKEN_MINT: (tokenMint: TokenMint): OP_DEFI_TX => {
return new OP_DEFI_TX({
signature: CDfTx.SIGNATURE,
Expand Down