Add auction tests for commitBid and revealBid

This commit is contained in:
nabarun 2022-04-12 11:38:16 +05:30 committed by Ashwin Phatak
parent d51f9618e0
commit 838edaa9a6
4 changed files with 351 additions and 19 deletions

View File

@ -1,6 +1,6 @@
import assert from 'assert'; import assert from 'assert';
import { Registry, Account } from './index'; import { Registry, Account, createBid } from './index';
import { getConfig } from './testing/helper'; import { getConfig } from './testing/helper';
jest.setTimeout(30 * 60 * 1000); jest.setTimeout(30 * 60 * 1000);
@ -10,7 +10,7 @@ const { chainId, restEndpoint, gqlEndpoint, privateKey, accountAddress, fee } =
const auctionTests = (numBidders = 3) => { const auctionTests = (numBidders = 3) => {
let registry: Registry; let registry: Registry;
const accounts: { address: string, privateKey: string }[] = []; const accounts: { address: string, privateKey: string, bid?: any }[] = [];
let auctionId: string; let auctionId: string;
let authorityName: string; let authorityName: string;
@ -28,11 +28,11 @@ const auctionTests = (numBidders = 3) => {
await account.init(); await account.init();
const bidderAddress = account.formattedCosmosAddress; const bidderAddress = account.formattedCosmosAddress;
assert(bidderAddress) 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.push({ address: bidderAddress, privateKey: account.privateKey.toString('hex') });
} }
accounts.unshift({ address: accountAddress, privateKey }); accounts[0] = { address: accountAddress, privateKey };
}); });
test('Reserve authority.', async () => { test('Reserve authority.', async () => {
@ -51,6 +51,68 @@ const auctionTests = (numBidders = 3) => {
auctionId = record.auction.id; 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); const withNumBidders = (numBidders: number) => () => auctionTests(numBidders);
@ -70,6 +132,6 @@ if (!process.env.AUCTIONS_ENABLED) {
yarn test:auctions yarn test:auctions
*/ */
describe('Auction (1 bidder)', withNumBidders(1)); describe('Auction (1 bidder)', withNumBidders(1));
describe('Auction (2 bidders)', withNumBidders(2)); xdescribe('Auction (2 bidders)', withNumBidders(2));
describe('Auction (4 bidders)', withNumBidders(4)); xdescribe('Auction (4 bidders)', withNumBidders(4));
} }

View File

@ -9,12 +9,40 @@ import {
MessageSendParams MessageSendParams
} from '@tharsis/transactions' } from '@tharsis/transactions'
import { createTxMsgCancelBond, createTxMsgCreateBond, createTxMsgRefillBond, createTxMsgWithdrawBond, MessageMsgCancelBond, MessageMsgCreateBond, MessageMsgRefillBond, MessageMsgWithdrawBond } from "./messages/bond";
import { RegistryClient } from "./registry-client"; import { RegistryClient } from "./registry-client";
import { Account } from "./account"; import { Account } from "./account";
import { createTransaction } from "./txbuilder"; 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 { 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.'; const DEFAULT_WRITE_ERROR = 'Unable to write to chiba-clonk.';
@ -35,6 +63,32 @@ export const parseTxResponse = (result: any) => {
return { hash, height, ...txResponse }; 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 const isKeyValid = (key: string) => key && key.match(/^[0-9a-fA-F]{64}$/);
export class Registry { export class Registry {
@ -71,7 +125,7 @@ export class Registry {
/** /**
* Get account by addresses. * Get account by addresses.
*/ */
async getAccount(address: string) { async getAccount(address: string) {
return this._client.getAccount(address); return this._client.getAccount(address);
} }
@ -108,7 +162,7 @@ export class Registry {
/** /**
* Send coins. * Send coins.
*/ */
async sendCoins(params: MessageSendParams, senderAddress: string, privateKey: string, fee: Fee) { async sendCoins(params: MessageSendParams, senderAddress: string, privateKey: string, fee: Fee) {
let result; let result;
const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress); 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. * Computes the next bondId for the given account private key.
*/ */
async getNextBondId(address: string) { async getNextBondId(address: string) {
let result; let result;
const { account } = await this.getAccount(address); const { account } = await this.getAccount(address);
const accountObj = account.base_account; const accountObj = account.base_account;
@ -142,21 +196,21 @@ export class Registry {
/** /**
* Get bonds by ids. * Get bonds by ids.
*/ */
async getBondsByIds(ids: string[]) { async getBondsByIds(ids: string[]) {
return this._client.getBondsByIds(ids); return this._client.getBondsByIds(ids);
} }
/** /**
* Query bonds by attributes. * Query bonds by attributes.
*/ */
async queryBonds(attributes = {}) { async queryBonds(attributes = {}) {
return this._client.queryBonds(attributes); return this._client.queryBonds(attributes);
} }
/** /**
* Create bond. * Create bond.
*/ */
async createBond(params: MessageMsgCreateBond, senderAddress: string, privateKey: string, fee: Fee) { async createBond(params: MessageMsgCreateBond, senderAddress: string, privateKey: string, fee: Fee) {
let result; let result;
const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress); const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress);
@ -176,7 +230,7 @@ export class Registry {
/** /**
* Refill bond. * Refill bond.
*/ */
async refillBond(params: MessageMsgRefillBond, senderAddress: string, privateKey: string, fee: Fee) { async refillBond(params: MessageMsgRefillBond, senderAddress: string, privateKey: string, fee: Fee) {
let result; let result;
const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress); const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress);
@ -196,7 +250,7 @@ export class Registry {
/** /**
* Withdraw (from) bond. * 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; let result;
const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress); const { account: { base_account: accountInfo } } = await this.getAccount(senderAddress);
@ -277,6 +331,53 @@ export class Registry {
return parseTxResponse(result); 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. * Lookup authorities by names.
*/ */

149
src/messages/auction.ts Normal file
View 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',
}
}

View File

@ -136,7 +136,7 @@ export class RegistryClient {
/** /**
* Fetch Account. * Fetch Account.
*/ */
async getAccount(address: string) { async getAccount(address: string) {
assert(address); assert(address);
let { data } = await axios.get(`${this._restEndpoint}${generateEndpointAccount(address)}`) let { data } = await axios.get(`${this._restEndpoint}${generateEndpointAccount(address)}`)
@ -147,7 +147,7 @@ export class RegistryClient {
/** /**
* Get records by attributes. * 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) { if (!attributes) {
attributes = {}; attributes = {};
} }
@ -179,7 +179,7 @@ export class RegistryClient {
/** /**
* Lookup authorities by names. * Lookup authorities by names.
*/ */
async lookupAuthorities(names: string[], auction = false) { async lookupAuthorities(names: string[], auction = false) {
assert(names.length); assert(names.length);
const query = `query ($names: [String!]) { const query = `query ($names: [String!]) {
@ -203,6 +203,26 @@ export class RegistryClient {
return result['lookupAuthorities']; 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. * Lookup names.
*/ */