Atomic Order Matching - Tests

This commit is contained in:
Greg Hysen
2018-05-10 14:22:49 -07:00
parent a4c821eb60
commit 9b1015bbce
10 changed files with 1412 additions and 33 deletions

View File

@@ -8,6 +8,9 @@ export const assetProxyUtils = {
encodeAssetProxyId(assetProxyId: AssetProxyId): Buffer {
return ethUtil.toBuffer(assetProxyId);
},
decodeAssetProxyId(encodedAssetProxyId: Buffer): AssetProxyId {
return ethUtil.bufferToInt(encodedAssetProxyId);
},
encodeAddress(address: string): Buffer {
if (!ethUtil.isValidAddress(address)) {
throw new Error(`Invalid Address: ${address}`);
@@ -15,12 +18,24 @@ export const assetProxyUtils = {
const encodedAddress = ethUtil.toBuffer(address);
return encodedAddress;
},
decodeAddress(encodedAddress: Buffer): string {
const address = ethUtil.bufferToHex(encodedAddress);
if (!ethUtil.isValidAddress(address)) {
throw new Error(`Invalid Address: ${address}`);
}
return address;
},
encodeUint256(value: BigNumber): Buffer {
const formattedValue = new BN(value.toString(10));
const encodedValue = ethUtil.toBuffer(formattedValue);
const paddedValue = ethUtil.setLengthLeft(encodedValue, 32);
return paddedValue;
},
decodeUint256(encodedValue: Buffer): BigNumber {
const formattedValue = ethUtil.bufferToHex(encodedValue);
const value = new BigNumber(formattedValue, 16);
return value;
},
encodeERC20ProxyData(tokenAddress: string): string {
const encodedAssetProxyId = assetProxyUtils.encodeAssetProxyId(AssetProxyId.ERC20);
const encodedAddress = assetProxyUtils.encodeAddress(tokenAddress);
@@ -28,6 +43,28 @@ export const assetProxyUtils = {
const encodedMetadataHex = ethUtil.bufferToHex(encodedMetadata);
return encodedMetadataHex;
},
decodeERC20ProxyData(proxyData: string): string /* tokenAddress */ {
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
if (encodedProxyMetadata.byteLength !== 21) {
throw new Error(
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be 21. Got ${
encodedProxyMetadata.byteLength
}`,
);
}
const encodedAssetProxyId = encodedProxyMetadata.slice(0, 1);
const assetProxyId = assetProxyUtils.decodeAssetProxyId(encodedAssetProxyId);
if (assetProxyId !== AssetProxyId.ERC20) {
throw new Error(
`Could not decode ERC20 Proxy Data. Expected Asset Proxy Id to be ERC20 (${
AssetProxyId.ERC20
}), but got ${assetProxyId}`,
);
}
const encodedTokenAddress = encodedProxyMetadata.slice(1, 21);
const tokenAddress = assetProxyUtils.decodeAddress(encodedTokenAddress);
return tokenAddress;
},
encodeERC721ProxyData(tokenAddress: string, tokenId: BigNumber): string {
const encodedAssetProxyId = assetProxyUtils.encodeAssetProxyId(AssetProxyId.ERC721);
const encodedAddress = assetProxyUtils.encodeAddress(tokenAddress);
@@ -36,4 +73,41 @@ export const assetProxyUtils = {
const encodedMetadataHex = ethUtil.bufferToHex(encodedMetadata);
return encodedMetadataHex;
},
decodeERC721ProxyData(proxyData: string): [string /* tokenAddress */, BigNumber /* tokenId */] {
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
if (encodedProxyMetadata.byteLength !== 53) {
throw new Error(
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be 53. Got ${
encodedProxyMetadata.byteLength
}`,
);
}
const encodedAssetProxyId = encodedProxyMetadata.slice(0, 1);
const assetProxyId = assetProxyUtils.decodeAssetProxyId(encodedAssetProxyId);
if (assetProxyId !== AssetProxyId.ERC721) {
throw new Error(
`Could not decode ERC721 Proxy Data. Expected Asset Proxy Id to be ERC721 (${
AssetProxyId.ERC721
}), but got ${assetProxyId}`,
);
}
const encodedTokenAddress = encodedProxyMetadata.slice(1, 21);
const tokenAddress = assetProxyUtils.decodeAddress(encodedTokenAddress);
const encodedTokenId = encodedProxyMetadata.slice(21, 53);
const tokenId = assetProxyUtils.decodeUint256(encodedTokenId);
return [tokenAddress, tokenId];
},
decodeProxyDataId(proxyData: string): AssetProxyId {
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
if (encodedProxyMetadata.byteLength < 1) {
throw new Error(
`Could not decode Proxy Data. Expected length of encoded data to be at least 1. Got ${
encodedProxyMetadata.byteLength
}`,
);
}
const encodedAssetProxyId = encodedProxyMetadata.slice(0, 1);
const assetProxyId = assetProxyUtils.decodeAssetProxyId(encodedAssetProxyId);
return assetProxyId;
},
};

View File

@@ -231,4 +231,26 @@ export class ExchangeWrapper {
tx.logs = _.map(tx.logs, log => this._logDecoder.decodeLogOrThrow(log));
return tx;
}
public async getOrderInfoAsync(
signedOrder: SignedOrder,
): Promise<[number /* orderStatus */, string /* orderHash */, BigNumber /* orderTakerAssetAmountFilled */]> {
const orderInfo: [number, string, BigNumber] = await this._exchange.getOrderInfo.callAsync(signedOrder);
return orderInfo;
}
public async matchOrdersAsync(
signedOrderLeft: SignedOrder,
signedOrderRight: SignedOrder,
from: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
const txHash = await this._exchange.matchOrders.sendTransactionAsync(
params.left,
params.right,
params.leftSignature,
params.rightSignature,
{ from },
);
const tx = await this._getTxWithDecodedExchangeLogsAsync(txHash);
return tx;
}
}

View File

@@ -80,4 +80,13 @@ export const orderUtils = {
const orderHashHex = `0x${orderHashBuff.toString('hex')}`;
return orderHashHex;
},
createMatchOrders(signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder) {
const fill = {
left: orderUtils.getOrderStruct(signedOrderLeft),
right: orderUtils.getOrderStruct(signedOrderRight),
leftSignature: signedOrderLeft.signature,
rightSignature: signedOrderRight.signature,
};
return fill;
},
};

View File

@@ -74,12 +74,27 @@ export interface Token {
swarmHash: string;
}
export enum ExchangeContractErrs {
ERROR_ORDER_EXPIRED,
ERROR_ORDER_FULLY_FILLED,
ERROR_ORDER_CANCELLED,
ERROR_ROUNDING_ERROR_TOO_LARGE,
ERROR_INSUFFICIENT_BALANCE_OR_ALLOWANCE,
export enum ExchangeStatus {
/// Default Status ///
INVALID, // General invalid status
/// General Exchange Statuses ///
SUCCESS, // Indicates a successful operation
ROUNDING_ERROR_TOO_LARGE, // Rounding error too large
INSUFFICIENT_BALANCE_OR_ALLOWANCE, // Insufficient balance or allowance for token transfer
TAKER_ASSET_FILL_AMOUNT_TOO_LOW, // takerAssetFillAmount is <= 0
INVALID_SIGNATURE, // Invalid signature
INVALID_SENDER, // Invalid sender
INVALID_TAKER, // Invalid taker
INVALID_MAKER, // Invalid maker
/// Order State Statuses ///
ORDER_INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount
ORDER_INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount
ORDER_FILLABLE, // Order is fillable
ORDER_EXPIRED, // Order has already expired
ORDER_FULLY_FILLED, // Order is fully filled
ORDER_CANCELLED, // Order has been cancelled
}
export enum ContractName {
@@ -143,3 +158,24 @@ export interface SignedTransaction {
data: string;
signature: string;
}
export interface TransferAmountsByMatchOrders {
// Left Maker
amountBoughtByLeftMaker: BigNumber;
amountSoldByLeftMaker: BigNumber;
amountReceivedByLeftMaker: BigNumber;
feePaidByLeftMaker: BigNumber;
// Right Maker
amountBoughtByRightMaker: BigNumber;
amountSoldByRightMaker: BigNumber;
amountReceivedByRightMaker: BigNumber;
feePaidByRightMaker: BigNumber;
// Taker
amountReceivedByTaker: BigNumber;
feePaidByTakerLeft: BigNumber;
feePaidByTakerRight: BigNumber;
totalFeePaidByTaker: BigNumber;
// Fee Recipients
feeReceivedLeft: BigNumber;
feeReceivedRight: BigNumber;
}