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 { 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));
}

View File

@ -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
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.
*/
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.
*/