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 TokenCreate #208

Merged
merged 13 commits into from
May 25, 2021
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { SmartBuffer } from 'smart-buffer'
import { OP_DEFI_TX } from '../../../../src/script/defi'
import { CTokenCreate, TokenCreate } from '../../../../src/script/defi/dftx_token'
import { OP_CODES } from '../../../../src/script'
import { toBuffer, toOPCodes } from '../../../../src/script/_buffer'
import BigNumber from 'bignumber.js'

/**
* using createToken sample from
* https://explorer.defichain.io/#/DFI/mainnet/tx/8a5066b4ea77c8d0b705ba94f47585f944ae587700f0f43f8655d01f38921f40
* https://explorer.defichain.io/#/DFI/mainnet/tx/baeddea27199a9e9001133f18942353dc79a765f0c437a1eda550f7675dc6b8b
* https://explorer.defichain.io/#/DFI/mainnet/tx/11fb90953bbd2a8f8649c116e6071dc73d428c5eba97c5a4a6dac550df2ab78c
canonbrother marked this conversation as resolved.
Show resolved Hide resolved
*/
it('should bi-directional buffer-object-buffer', () => {
const fixtures = [
'6a1b44665478540342544307426974636f696e08000000000000000003',
'6a19446654785404474f4c4404476f6c6408000000000000000003',
'6a224466547854035753420e77616c6c7374726565746265747308000000000000000003',

// regtest fixtures
'6a174466547854034748490347484908000000000000000004',
'6a174466547854034a4b4c034a4b4c08000000000000000000',
'6a174466547854034d4e4f034d4e4f08000000000000000001',
'6a174466547854035051520350515208000000000000000007',
'6a174466547854034142430341424308000000000000000005'
]

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

const header = '6a224466547854' // OP_RETURN, PUSH_DATA(44665478, 54)
const data = '035753420e77616c6c7374726565746265747308000000000000000003'
const tokenCreate: TokenCreate = {
symbol: 'WSB',
name: 'wallstreetbets',
decimal: 8,
limit: new BigNumber('0'),
mintable: true,
tradeable: true,
isDAT: false
}

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

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 CTokenCreate(buffer)

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

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

expect(buffer.toBuffer().toString('hex')).toEqual(data)
})
})
12 changes: 12 additions & 0 deletions packages/jellyfish-transaction/src/buffer/buffer_bitmask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Extracts the "truthiness" of a bit given a position
* @param {number} binaryNum - The number to query from
* @param {number} position - This is the zero-indexed position of the bit from the right
* @returns {boolean} - "Truthiness" of the bit we're interested in
*/
export function getBitsFrom (binaryNum: number, position: number): boolean {
// Bit-shifts according to zero-indexed position
const mask = 1 << position
const query = binaryNum & mask
return Boolean(query)
}
22 changes: 22 additions & 0 deletions packages/jellyfish-transaction/src/buffer/buffer_composer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import BigNumber from 'bignumber.js'
import { SmartBuffer } from 'smart-buffer'
import { writeVarUInt, readVarUInt } from './buffer_varuint'
import { getBitsFrom } from './buffer_bitmask'
import { ONE_HUNDRED_MILLION, readBigNumberUInt64, writeBigNumberUInt64 } from './buffer_bignumber'

export interface BufferComposer {
Expand Down Expand Up @@ -438,4 +439,25 @@ export abstract class ComposableBuffer<T> implements BufferComposer {
}
}
}

static mask (
canonbrother marked this conversation as resolved.
Show resolved Hide resolved
getter: () => boolean[],
setter: (data: boolean[]) => void
): BufferComposer {
return {
fromBuffer: (buffer: SmartBuffer): void => {
const num = buffer.readInt8()
canonbrother marked this conversation as resolved.
Show resolved Hide resolved
const array: boolean[] = []
for (let i = 0; i < getter().length; i += 1) {
canonbrother marked this conversation as resolved.
Show resolved Hide resolved
array.unshift(getBitsFrom(num, i))
}
setter(array)
},
toBuffer: (buffer: SmartBuffer): void => {
const bools = getter().map(bool => bool.toString().toLowerCase() === 'true' ? 1 : 0)
const num = parseInt(bools.join(''), 2)
buffer.writeBuffer(Buffer.from([num]))
}
}
}
}
4 changes: 3 additions & 1 deletion packages/jellyfish-transaction/src/script/defi/dftx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
CPoolAddLiquidity, CPoolRemoveLiquidity, CPoolSwap, PoolAddLiquidity, PoolRemoveLiquidity,
PoolSwap
} from './dftx_pool'
import { CTokenMint, TokenMint } from './dftx_token'
import { CTokenCreate, CTokenMint, TokenCreate, TokenMint } from './dftx_token'
import { CDeFiOpUnmapped, DeFiOpUnmapped } from './dftx_unmapped'

// Disabling no-return-assign makes the code cleaner with the setter and getter */
Expand Down Expand Up @@ -100,6 +100,8 @@ export class CDfTx extends ComposableBuffer<DfTx<any>> {
return compose<PoolRemoveLiquidity>(CPoolRemoveLiquidity.OP_NAME, d => new CPoolRemoveLiquidity(d))
case CTokenMint.OP_CODE:
return compose<TokenMint>(CTokenMint.OP_NAME, d => new CTokenMint(d))
case CTokenCreate.OP_CODE:
return compose<TokenCreate>(CTokenCreate.OP_NAME, d => new CTokenCreate(d))
case CUtxosToAccount.OP_CODE:
return compose<UtxosToAccount>(CUtxosToAccount.OP_NAME, d => new CUtxosToAccount(d))
case CAccountToUtxos.OP_CODE:
Expand Down
37 changes: 37 additions & 0 deletions packages/jellyfish-transaction/src/script/defi/dftx_token.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BufferComposer, ComposableBuffer } from '../../buffer/buffer_composer'
import { TokenBalance, CTokenBalance } from './dftx_balance'
import BigNumber from 'bignumber.js'

// Disabling no-return-assign makes the code cleaner with the setter and getter */
/* eslint-disable no-return-assign */
Expand All @@ -25,3 +26,39 @@ export class CTokenMint extends ComposableBuffer<TokenMint> {
]
}
}

/**
* TokenCreate DeFi Transaction
*/
export interface TokenCreate {
symbol: string // ---------------------| VarUInt{1-9 bytes}, + n bytes
name: string // -----------------------| VarUInt{1-9 bytes}, + n bytes
decimal: number // --------------------| 1 byte
limit: BigNumber // -------------------| 64 bytes
canonbrother marked this conversation as resolved.
Show resolved Hide resolved
isDAT: boolean // ---------------------| 1 byte
tradeable: boolean // -----------------| 1 byte
mintable: boolean // ------------------| 1 byte
canonbrother marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Composable TokenMint, C stands for Composable.
* Immutable by design, bi-directional fromBuffer, toBuffer deep composer.
*/
export class CTokenCreate extends ComposableBuffer<TokenCreate> {
static OP_CODE = 0x54 /// 'T'
static OP_NAME = 'DEFI_OP_TOKEN_CREATE'
canonbrother marked this conversation as resolved.
Show resolved Hide resolved

composers (tc: TokenCreate): BufferComposer[] {
return [
ComposableBuffer.varUIntUtf8BE(() => tc.symbol, v => tc.symbol = v),
ComposableBuffer.varUIntUtf8BE(() => tc.name, v => tc.name = v),
ComposableBuffer.uInt8(() => tc.decimal, v => tc.decimal = v),
ComposableBuffer.bigNumberUInt64(() => tc.limit, v => tc.limit = v),
ComposableBuffer.mask(() => [tc.isDAT, tc.tradeable, tc.mintable], v => {
tc.isDAT = v[0]
tc.tradeable = v[1]
tc.mintable = v[2]
})
canonbrother marked this conversation as resolved.
Show resolved Hide resolved
]
}
}
10 changes: 9 additions & 1 deletion packages/jellyfish-transaction/src/script/mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
PoolRemoveLiquidity,
PoolSwap
} from './defi/dftx_pool'
import { CTokenMint, TokenMint } from './defi/dftx_token'
import { CTokenCreate, CTokenMint, TokenCreate, TokenMint } from './defi/dftx_token'
import {
AccountToAccount,
AccountToUtxos,
Expand Down Expand Up @@ -150,6 +150,14 @@ export const OP_CODES = {
data: tokenMint
})
},
OP_DEFI_TX_TOKEN_CREATE: (tokenCreate: TokenCreate): OP_DEFI_TX => {
return new OP_DEFI_TX({
signature: CDfTx.SIGNATURE,
type: CTokenCreate.OP_CODE,
name: CTokenCreate.OP_NAME,
data: tokenCreate
})
},
OP_DEFI_TX_UTXOS_TO_ACCOUNT: (utxosToAccount: UtxosToAccount): OP_DEFI_TX => {
return new OP_DEFI_TX({
signature: CDfTx.SIGNATURE,
Expand Down