Add auction tests for commitBid and revealBid
This commit is contained in:
parent
d51f9618e0
commit
838edaa9a6
@ -1,6 +1,6 @@
|
||||
import assert from 'assert';
|
||||
|
||||
import { Registry, Account } from './index';
|
||||
import { Registry, Account, createBid } from './index';
|
||||
import { getConfig } from './testing/helper';
|
||||
|
||||
jest.setTimeout(30 * 60 * 1000);
|
||||
@ -10,7 +10,7 @@ const { chainId, restEndpoint, gqlEndpoint, privateKey, accountAddress, fee } =
|
||||
const auctionTests = (numBidders = 3) => {
|
||||
let registry: Registry;
|
||||
|
||||
const accounts: { address: string, privateKey: string }[] = [];
|
||||
const accounts: { address: string, privateKey: string, bid?: any }[] = [];
|
||||
|
||||
let auctionId: string;
|
||||
let authorityName: string;
|
||||
@ -28,11 +28,11 @@ const auctionTests = (numBidders = 3) => {
|
||||
await account.init();
|
||||
const bidderAddress = account.formattedCosmosAddress;
|
||||
assert(bidderAddress)
|
||||
await registry.sendCoins({ denom: 'uwire', amount: '1000000000', destinationAddress: bidderAddress }, accountAddress, privateKey, fee);
|
||||
await registry.sendCoins({ denom: 'aphoton', amount: '1000000000', destinationAddress: bidderAddress }, accountAddress, privateKey, fee);
|
||||
accounts.push({ address: bidderAddress, privateKey: account.privateKey.toString('hex') });
|
||||
}
|
||||
|
||||
accounts.unshift({ address: accountAddress, privateKey });
|
||||
accounts[0] = { address: accountAddress, privateKey };
|
||||
});
|
||||
|
||||
test('Reserve authority.', async () => {
|
||||
@ -51,6 +51,68 @@ const auctionTests = (numBidders = 3) => {
|
||||
|
||||
auctionId = record.auction.id;
|
||||
});
|
||||
|
||||
test('Commit bids.', async () => {
|
||||
for (let i = 0; i < numBidders; i++) {
|
||||
accounts[i].bid = await createBid(chainId, auctionId, accounts[i].address, `${10000000 + (i * 500)}aphoton`);
|
||||
await registry.commitBid({ auctionId, commitHash: accounts[i].bid.commitHash }, accounts[i].address, accounts[i].privateKey, fee);
|
||||
}
|
||||
});
|
||||
|
||||
test('Check bids are committed', async () => {
|
||||
const [record] = await registry.lookupAuthorities([authorityName], true);
|
||||
expect(record.auction.id).toBeDefined();
|
||||
expect(record.auction.status).toEqual('commit');
|
||||
expect(record.auction.bids).toHaveLength(accounts.length);
|
||||
|
||||
record.auction.bids.forEach((bid: any) => {
|
||||
expect(bid.status).toEqual('commit');
|
||||
});
|
||||
});
|
||||
|
||||
test('Wait for reveal phase.', (done) => {
|
||||
setTimeout(done, 60 * 1000);
|
||||
});
|
||||
|
||||
test('Reveal bids.', async () => {
|
||||
const [auction] = await registry.getAuctionsByIds([auctionId]);
|
||||
expect(auction.status).toEqual('reveal');
|
||||
|
||||
for (let i = 0; i < numBidders; i++) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await registry.revealBid({ auctionId, reveal: accounts[i].bid.revealString }, accounts[i].address, accounts[i].privateKey, fee);
|
||||
}
|
||||
});
|
||||
|
||||
test('Check bids are revealed', async () => {
|
||||
const [auction] = await registry.getAuctionsByIds([auctionId]);
|
||||
expect(auction.status).toEqual('reveal');
|
||||
|
||||
auction.bids.forEach((bid: any) => {
|
||||
expect(bid.status).toEqual('reveal');
|
||||
});
|
||||
});
|
||||
|
||||
test('Wait for auction completion.', (done) => {
|
||||
setTimeout(done, 60 * 1000);
|
||||
});
|
||||
|
||||
test('Check auction winner, authority owner and status.', async () => {
|
||||
const [auction] = await registry.getAuctionsByIds([auctionId]);
|
||||
expect(auction.status).toEqual('completed');
|
||||
|
||||
const highestBidder = accounts[accounts.length - 1];
|
||||
const secondHighestBidder = (accounts.length > 1 ? accounts[accounts.length - 2] : highestBidder);
|
||||
|
||||
expect(auction.winnerAddress).toEqual(highestBidder.address);
|
||||
expect(highestBidder.bid.reveal.bidAmount).toEqual(`${auction.winnerBid.quantity}${auction.winnerBid.type}`);
|
||||
expect(secondHighestBidder.bid.reveal.bidAmount).toEqual(`${auction.winnerPrice.quantity}${auction.winnerPrice.type}`);
|
||||
|
||||
const [record] = await registry.lookupAuthorities([authorityName], true);
|
||||
expect(record.ownerAddress).toEqual(highestBidder.address);
|
||||
expect(record.height).toBeDefined();
|
||||
expect(record.status).toEqual('active');
|
||||
});
|
||||
};
|
||||
|
||||
const withNumBidders = (numBidders: number) => () => auctionTests(numBidders);
|
||||
@ -70,6 +132,6 @@ if (!process.env.AUCTIONS_ENABLED) {
|
||||
yarn test:auctions
|
||||
*/
|
||||
describe('Auction (1 bidder)', withNumBidders(1));
|
||||
describe('Auction (2 bidders)', withNumBidders(2));
|
||||
describe('Auction (4 bidders)', withNumBidders(4));
|
||||
xdescribe('Auction (2 bidders)', withNumBidders(2));
|
||||
xdescribe('Auction (4 bidders)', withNumBidders(4));
|
||||
}
|
||||
|
121
src/index.ts
121
src/index.ts
@ -9,12 +9,40 @@ import {
|
||||
MessageSendParams
|
||||
} from '@tharsis/transactions'
|
||||
|
||||
import { createTxMsgCancelBond, createTxMsgCreateBond, createTxMsgRefillBond, createTxMsgWithdrawBond, MessageMsgCancelBond, MessageMsgCreateBond, MessageMsgRefillBond, MessageMsgWithdrawBond } from "./messages/bond";
|
||||
import { RegistryClient } from "./registry-client";
|
||||
import { Account } from "./account";
|
||||
import { createTransaction } from "./txbuilder";
|
||||
import { createTxMsgDeleteName, createTxMsgReserveAuthority, createTxMsgSetAuthorityBond, createTxMsgSetName, createTxMsgSetRecord, MessageMsgDeleteName, MessageMsgReserveAuthority, MessageMsgSetAuthorityBond, MessageMsgSetName, MessageMsgSetRecord, NAMESERVICE_ERRORS } from './messages/nameservice';
|
||||
import { Payload, Record } from './types';
|
||||
import { Util } from './util';
|
||||
import {
|
||||
createTxMsgCancelBond,
|
||||
createTxMsgCreateBond,
|
||||
createTxMsgRefillBond,
|
||||
createTxMsgWithdrawBond,
|
||||
MessageMsgCancelBond,
|
||||
MessageMsgCreateBond,
|
||||
MessageMsgRefillBond,
|
||||
MessageMsgWithdrawBond
|
||||
} from "./messages/bond";
|
||||
import {
|
||||
createTxMsgDeleteName,
|
||||
createTxMsgReserveAuthority,
|
||||
createTxMsgSetAuthorityBond,
|
||||
createTxMsgSetName,
|
||||
createTxMsgSetRecord,
|
||||
MessageMsgDeleteName,
|
||||
MessageMsgReserveAuthority,
|
||||
MessageMsgSetAuthorityBond,
|
||||
MessageMsgSetName,
|
||||
MessageMsgSetRecord,
|
||||
NAMESERVICE_ERRORS
|
||||
} from './messages/nameservice';
|
||||
import {
|
||||
createTxMsgCommitBid,
|
||||
createTxMsgRevealBid,
|
||||
MessageMsgCommitBid,
|
||||
MessageMsgRevealBid
|
||||
} from './messages/auction';
|
||||
|
||||
const DEFAULT_WRITE_ERROR = 'Unable to write to chiba-clonk.';
|
||||
|
||||
@ -35,6 +63,32 @@ export const parseTxResponse = (result: any) => {
|
||||
return { hash, height, ...txResponse };
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an auction bid.
|
||||
*/
|
||||
export const createBid = async (chainId: string, auctionId: string, bidderAddress: string, bidAmount: string, noise?: string) => {
|
||||
if (!noise) {
|
||||
noise = Account.generateMnemonic();
|
||||
}
|
||||
|
||||
const reveal = {
|
||||
chainId,
|
||||
auctionId,
|
||||
bidderAddress,
|
||||
bidAmount,
|
||||
noise
|
||||
};
|
||||
|
||||
const commitHash = await Util.getContentId(reveal);
|
||||
const revealString = Buffer.from(JSON.stringify(reveal)).toString('hex');
|
||||
|
||||
return {
|
||||
commitHash,
|
||||
reveal,
|
||||
revealString
|
||||
};
|
||||
};
|
||||
|
||||
export const isKeyValid = (key: string) => key && key.match(/^[0-9a-fA-F]{64}$/);
|
||||
|
||||
export class Registry {
|
||||
@ -71,7 +125,7 @@ export class Registry {
|
||||
/**
|
||||
* Get account by addresses.
|
||||
*/
|
||||
async getAccount(address: string) {
|
||||
async getAccount(address: string) {
|
||||
return this._client.getAccount(address);
|
||||
}
|
||||
|
||||
@ -108,7 +162,7 @@ export class Registry {
|
||||
/**
|
||||
* Send coins.
|
||||
*/
|
||||
async sendCoins(params: MessageSendParams, senderAddress: string, privateKey: string, fee: Fee) {
|
||||
async sendCoins(params: MessageSendParams, senderAddress: string, privateKey: string, fee: Fee) {
|
||||
let result;
|
||||
const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress);
|
||||
|
||||
@ -128,7 +182,7 @@ export class Registry {
|
||||
/**
|
||||
* Computes the next bondId for the given account private key.
|
||||
*/
|
||||
async getNextBondId(address: string) {
|
||||
async getNextBondId(address: string) {
|
||||
let result;
|
||||
const { account } = await this.getAccount(address);
|
||||
const accountObj = account.base_account;
|
||||
@ -142,21 +196,21 @@ export class Registry {
|
||||
/**
|
||||
* Get bonds by ids.
|
||||
*/
|
||||
async getBondsByIds(ids: string[]) {
|
||||
async getBondsByIds(ids: string[]) {
|
||||
return this._client.getBondsByIds(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query bonds by attributes.
|
||||
*/
|
||||
async queryBonds(attributes = {}) {
|
||||
async queryBonds(attributes = {}) {
|
||||
return this._client.queryBonds(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create bond.
|
||||
*/
|
||||
async createBond(params: MessageMsgCreateBond, senderAddress: string, privateKey: string, fee: Fee) {
|
||||
async createBond(params: MessageMsgCreateBond, senderAddress: string, privateKey: string, fee: Fee) {
|
||||
let result;
|
||||
const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress);
|
||||
|
||||
@ -176,7 +230,7 @@ export class Registry {
|
||||
/**
|
||||
* Refill bond.
|
||||
*/
|
||||
async refillBond(params: MessageMsgRefillBond, senderAddress: string, privateKey: string, fee: Fee) {
|
||||
async refillBond(params: MessageMsgRefillBond, senderAddress: string, privateKey: string, fee: Fee) {
|
||||
let result;
|
||||
const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress);
|
||||
|
||||
@ -196,7 +250,7 @@ export class Registry {
|
||||
/**
|
||||
* Withdraw (from) bond.
|
||||
*/
|
||||
async withdrawBond(params: MessageMsgWithdrawBond, senderAddress: string, privateKey: string, fee: Fee) {
|
||||
async withdrawBond(params: MessageMsgWithdrawBond, senderAddress: string, privateKey: string, fee: Fee) {
|
||||
let result;
|
||||
const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress);
|
||||
|
||||
@ -277,6 +331,53 @@ export class Registry {
|
||||
return parseTxResponse(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit auction bid.
|
||||
*/
|
||||
async commitBid(params: MessageMsgCommitBid, senderAddress: string, privateKey: string, fee: Fee) {
|
||||
let result;
|
||||
const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress);
|
||||
|
||||
const sender = {
|
||||
accountAddress: accountInfo.address,
|
||||
sequence: accountInfo.sequence,
|
||||
accountNumber: accountInfo.account_number,
|
||||
pubkey: accountInfo.pub_key.key,
|
||||
}
|
||||
|
||||
const msg = createTxMsgCommitBid(this._chain, sender, fee, '', params)
|
||||
result = await this._submitTx(msg, privateKey, sender);
|
||||
|
||||
return parseTxResponse(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reveal auction bid.
|
||||
*/
|
||||
async revealBid(params: MessageMsgRevealBid, senderAddress: string, privateKey: string, fee: Fee) {
|
||||
let result;
|
||||
const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress);
|
||||
|
||||
const sender = {
|
||||
accountAddress: accountInfo.address,
|
||||
sequence: accountInfo.sequence,
|
||||
accountNumber: accountInfo.account_number,
|
||||
pubkey: accountInfo.pub_key.key,
|
||||
}
|
||||
|
||||
const msg = createTxMsgRevealBid(this._chain, sender, fee, '', params)
|
||||
result = await this._submitTx(msg, privateKey, sender);
|
||||
|
||||
return parseTxResponse(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get records by ids.
|
||||
*/
|
||||
async getAuctionsByIds(ids: string[]) {
|
||||
return this._client.getAuctionsByIds(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup authorities by names.
|
||||
*/
|
||||
|
149
src/messages/auction.ts
Normal file
149
src/messages/auction.ts
Normal file
@ -0,0 +1,149 @@
|
||||
import {
|
||||
generateTypes,
|
||||
} from '@tharsis/eip712'
|
||||
import {
|
||||
Chain,
|
||||
Sender,
|
||||
Fee,
|
||||
} from '@tharsis/transactions'
|
||||
|
||||
import * as auctionTx from '../proto/vulcanize/auction/v1beta1/tx'
|
||||
import { createTx } from './util'
|
||||
|
||||
const MSG_COMMIT_BID_TYPES = {
|
||||
MsgValue: [
|
||||
{ name: 'auction_id', type: 'string' },
|
||||
{ name: 'commit_hash', type: 'string' },
|
||||
{ name: 'signer', type: 'string' },
|
||||
]
|
||||
}
|
||||
|
||||
export interface MessageMsgCommitBid {
|
||||
auctionId: string,
|
||||
commitHash: string,
|
||||
}
|
||||
|
||||
const MSG_REVEAL_BID_TYPES = {
|
||||
MsgValue: [
|
||||
{ name: 'auction_id', type: 'string' },
|
||||
{ name: 'reveal', type: 'string' },
|
||||
{ name: 'signer', type: 'string' },
|
||||
]
|
||||
}
|
||||
|
||||
export interface MessageMsgRevealBid {
|
||||
auctionId: string,
|
||||
reveal: string,
|
||||
}
|
||||
|
||||
export function createTxMsgCommitBid(
|
||||
chain: Chain,
|
||||
sender: Sender,
|
||||
fee: Fee,
|
||||
memo: string,
|
||||
params: MessageMsgCommitBid,
|
||||
) {
|
||||
const types = generateTypes(MSG_COMMIT_BID_TYPES)
|
||||
|
||||
const msg = createMsgCommitBid(
|
||||
params.auctionId,
|
||||
params.commitHash,
|
||||
sender.accountAddress,
|
||||
)
|
||||
|
||||
const msgCosmos = protoCreateMsgCommitBid(
|
||||
params.auctionId,
|
||||
params.commitHash,
|
||||
sender.accountAddress,
|
||||
)
|
||||
|
||||
return createTx(chain, sender, fee, memo, types, msg, msgCosmos)
|
||||
}
|
||||
|
||||
export function createTxMsgRevealBid(
|
||||
chain: Chain,
|
||||
sender: Sender,
|
||||
fee: Fee,
|
||||
memo: string,
|
||||
params: MessageMsgRevealBid,
|
||||
) {
|
||||
const types = generateTypes(MSG_REVEAL_BID_TYPES)
|
||||
|
||||
const msg = createMsgRevealBid(
|
||||
params.auctionId,
|
||||
params.reveal,
|
||||
sender.accountAddress,
|
||||
)
|
||||
|
||||
const msgCosmos = protoCreateMsgRevealBid(
|
||||
params.auctionId,
|
||||
params.reveal,
|
||||
sender.accountAddress,
|
||||
)
|
||||
|
||||
return createTx(chain, sender, fee, memo, types, msg, msgCosmos)
|
||||
}
|
||||
|
||||
function createMsgCommitBid(
|
||||
auctionId: string,
|
||||
commitHash: string,
|
||||
signer: string
|
||||
) {
|
||||
return {
|
||||
type: 'auction/MsgCommitBid',
|
||||
value: {
|
||||
auction_id: auctionId,
|
||||
commit_hash: commitHash,
|
||||
signer,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const protoCreateMsgCommitBid = (
|
||||
auctionId: string,
|
||||
commitHash: string,
|
||||
signer: string
|
||||
) => {
|
||||
const commitBidMessage = new auctionTx.vulcanize.auction.v1beta1.MsgCommitBid({
|
||||
auction_id: auctionId,
|
||||
commit_hash: commitHash,
|
||||
signer,
|
||||
})
|
||||
|
||||
return {
|
||||
message: commitBidMessage,
|
||||
path: 'vulcanize.auction.v1beta1.MsgCommitBid',
|
||||
}
|
||||
}
|
||||
|
||||
function createMsgRevealBid(
|
||||
auctionId: string,
|
||||
reveal: string,
|
||||
signer: string
|
||||
) {
|
||||
return {
|
||||
type: 'auction/MsgRevealBid',
|
||||
value: {
|
||||
auction_id: auctionId,
|
||||
reveal,
|
||||
signer,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const protoCreateMsgRevealBid = (
|
||||
auctionId: string,
|
||||
reveal: string,
|
||||
signer: string
|
||||
) => {
|
||||
const revealBidMessage = new auctionTx.vulcanize.auction.v1beta1.MsgRevealBid({
|
||||
auction_id: auctionId,
|
||||
reveal,
|
||||
signer,
|
||||
})
|
||||
|
||||
return {
|
||||
message: revealBidMessage,
|
||||
path: 'vulcanize.auction.v1beta1.MsgRevealBid',
|
||||
}
|
||||
}
|
@ -136,7 +136,7 @@ export class RegistryClient {
|
||||
/**
|
||||
* Fetch Account.
|
||||
*/
|
||||
async getAccount(address: string) {
|
||||
async getAccount(address: string) {
|
||||
assert(address);
|
||||
|
||||
let { data } = await axios.get(`${this._restEndpoint}${generateEndpointAccount(address)}`)
|
||||
@ -147,7 +147,7 @@ export class RegistryClient {
|
||||
/**
|
||||
* Get records by attributes.
|
||||
*/
|
||||
async queryRecords(attributes: {[key: string]: any}, all = false, refs = false) {
|
||||
async queryRecords(attributes: {[key: string]: any}, all = false, refs = false) {
|
||||
if (!attributes) {
|
||||
attributes = {};
|
||||
}
|
||||
@ -179,7 +179,7 @@ export class RegistryClient {
|
||||
/**
|
||||
* Lookup authorities by names.
|
||||
*/
|
||||
async lookupAuthorities(names: string[], auction = false) {
|
||||
async lookupAuthorities(names: string[], auction = false) {
|
||||
assert(names.length);
|
||||
|
||||
const query = `query ($names: [String!]) {
|
||||
@ -203,6 +203,26 @@ export class RegistryClient {
|
||||
return result['lookupAuthorities'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get auctions by ids.
|
||||
*/
|
||||
async getAuctionsByIds(ids: string[]) {
|
||||
assert(ids);
|
||||
assert(ids.length);
|
||||
|
||||
const query = `query ($ids: [String!]) {
|
||||
getAuctionsByIds(ids: $ids) {
|
||||
${auctionFields}
|
||||
}
|
||||
}`;
|
||||
|
||||
const variables = {
|
||||
ids
|
||||
};
|
||||
|
||||
return RegistryClient.getResult(this._graph(query)(variables), 'getAuctionsByIds');
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup names.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user