Add instruction layouts

This commit is contained in:
Gary Wang 2020-08-08 23:01:26 -07:00
parent ec3bf95181
commit c0a5f28e96
4 changed files with 127 additions and 13 deletions

70
src/instructions.js Normal file
View File

@ -0,0 +1,70 @@
import { blob, Layout, struct, u16, u32, u8, union } from 'buffer-layout';
import { u64 } from './layout';
class VersionedLayout extends Layout {
constructor(version, inner, property) {
super(inner.span > 0 ? inner.span + 1 : inner.span, property);
this.version = version;
this.inner = inner;
}
decode(b, offset = 0) {
if (b.readUInt8(offset) !== this._version) {
throw new Error('invalid version');
}
return this.inner.decode(b, offset + 1);
}
encode(src, b, offset = 0) {
b.writeUInt8(this.version, offset);
return 1 + this.inner.encode(src, b, offset + 1);
}
getSpan(b, offset = 0) {
return 1 + this.inner.getSpan(b, offset + 1);
}
}
export const INSTRUCTION_LAYOUT = new VersionedLayout(
0,
union(u32('instruction')),
);
INSTRUCTION_LAYOUT.inner.addVariant(
0,
struct([
u64('baseLotSize'),
u64('quoteLotSize'),
u16('feeRateBps'),
u64('vaultSignerNonce'),
u64('quoteDustThreshold'),
]),
'initializeMarket',
);
INSTRUCTION_LAYOUT.inner.addVariant(
1,
struct([
u8('side'), // buy = 0, sell = 1
blob(3),
u64('limitPrice'),
u64('maxQuantity'),
u8('orderType'), // limit = 0, ioc = 1, postOnly = 2
blob(3),
]),
'newOrder',
);
INSTRUCTION_LAYOUT.inner.addVariant(
2,
struct([u16('limit'), blob(2)]),
'matchOrders',
);
INSTRUCTION_LAYOUT.inner.addVariant(
3,
struct([u16('limit'), blob(2)]),
'consumeEvents',
);
INSTRUCTION_LAYOUT.inner.addVariant(4, struct([]), 'cancelOrder');
export function encodeInstruction(instruction) {
const b = Buffer.alloc(100);
return b.slice(0, INSTRUCTION_LAYOUT.encode(instruction, b));
}

33
src/instructions.test.js Normal file
View File

@ -0,0 +1,33 @@
import { encodeInstruction, INSTRUCTION_LAYOUT } from './instructions';
import BN from 'bn.js';
describe('instruction', () => {
it('encodes initialize market', () => {
let b = encodeInstruction({
initializeMarket: {
baseLotSize: new BN(10),
quoteLotSize: new BN(100000),
feeRateBps: 5,
vaultSignerNonce: new BN(1),
quoteDustThreshold: new BN(10),
},
});
expect(b.toString('hex')).toEqual(
'00000000000a00000000000000a086010000000000050001000000000000000a00000000000000',
);
});
it('encodes new order', () => {
let b = encodeInstruction({
newOrder: {
side: 1, // buy
limitPrice: new BN(10),
maxQuantity: new BN(5),
orderType: 2, // postOnly
},
});
expect(b.toString('hex')).toEqual(
'0001000000010000000a00000000000000050000000000000002000000',
);
});
});

View File

@ -2,16 +2,17 @@ import { seq, struct } from 'buffer-layout';
import { publicKeyLayout, u128, u64, WideBits } from './layout';
import { SLAB_LAYOUT } from './slab-layout';
const ACCOUNT_FLAGS_LAYOUT = new WideBits();
ACCOUNT_FLAGS_LAYOUT.addBoolean('initialized');
ACCOUNT_FLAGS_LAYOUT.addBoolean('market');
ACCOUNT_FLAGS_LAYOUT.addBoolean('openOrders');
ACCOUNT_FLAGS_LAYOUT.addBoolean('requestQueue');
ACCOUNT_FLAGS_LAYOUT.addBoolean('eventQueue');
ACCOUNT_FLAGS_LAYOUT.addBoolean('bids');
ACCOUNT_FLAGS_LAYOUT.addBoolean('asks');
export function accountFlags(property = 'accountFlags') {
const layout = new WideBits(property);
layout.addBoolean('initialized');
layout.addBoolean('market');
layout.addBoolean('openOrders');
layout.addBoolean('requestQueue');
layout.addBoolean('eventQueue');
layout.addBoolean('bids');
layout.addBoolean('asks');
return layout;
return ACCOUNT_FLAGS_LAYOUT.replicate(property);
}
export const MARKET_STATE_LAYOUT = struct([

View File

@ -3,12 +3,17 @@ import { publicKeyLayout, u128, u64, zeros } from './layout';
const SLAB_HEADER_LAYOUT = struct(
[
// Number of modified slab nodes
u32('bumpIndex'),
zeros(4), // Consider slabs with more than 2^32 nodes to be invalid
// Linked list of unused nodes
u32('freeListLen'),
zeros(4),
u32('freeListHead'),
u32('root'),
u32('leafCount'),
zeros(4),
],
@ -19,17 +24,22 @@ const SLAB_NODE_LAYOUT = union(u32('tag'), blob(60), 'node');
SLAB_NODE_LAYOUT.addVariant(0, struct([]), 'uninitialized');
SLAB_NODE_LAYOUT.addVariant(
1,
struct([u32('prefixLen'), u128('key'), seq(u32(), 2, 'children')]),
struct([
// Only the first prefixLen high-order bits of key are meaningful
u32('prefixLen'),
u128('key'),
seq(u32(), 2, 'children'),
]),
'innerNode',
);
SLAB_NODE_LAYOUT.addVariant(
2,
struct([
u8('ownerSlot'),
u8('ownerSlot'), // Index into OPEN_ORDERS_LAYOUT.orders
blob(3),
u128('key'),
u128('key'), // (price, seqNum)
publicKeyLayout('owner'),
u64('quantity'),
u64('quantity'), // In units of lot size
]),
'leafNode',
);