registry-sdk/src/auction.test.ts

311 lines
11 KiB
TypeScript

import Long from 'long';
import { coin } from '@cosmjs/amino';
import { Registry, Account, createBid } from './index';
import { getConfig } from './testing/helper';
import { DENOM } from './constants';
import { Duration } from './proto/google/protobuf/duration';
jest.setTimeout(30 * 60 * 1000);
const { chainId, rpcEndpoint, gqlEndpoint, privateKey, fee } = getConfig();
const duration = 60;
const commitsDuration = Duration.fromPartial({
seconds: Long.fromNumber(duration),
nanos: 0
});
const revealsDuration = Duration.fromPartial({
seconds: Long.fromNumber(duration),
nanos: 0
});
const commitFee = coin('1000', DENOM);
const revealFee = coin('1000', DENOM);
const creatorInitialBalance = 1000000000000;
const bidderInitialBalance = 20000000;
const createAuctionTests = () => {
let registry: Registry;
let auctionId: string;
let auctionCreatorAccount: { address: string, privateKey: string, bid?: any };
let bidderAccounts: { address: string, privateKey: string, bid?: any }[] = [];
let bidAmounts: { type: string, quantity: string }[] = [];
beforeAll(async () => {
registry = new Registry(gqlEndpoint, rpcEndpoint, { chainId });
// Create auction creator account
const mnenonic1 = Account.generateMnemonic();
const auctionCreator = await Account.generateFromMnemonic(mnenonic1);
await auctionCreator.init();
await registry.sendCoins({ denom: DENOM, amount: creatorInitialBalance.toString(), destinationAddress: auctionCreator.address }, privateKey, fee);
auctionCreatorAccount = { address: auctionCreator.address, privateKey: auctionCreator.privateKey.toString('hex') };
});
test('Setup bidder accounts', async () => {
for (let i = 0; i < 3; i++) {
const mnenonic = Account.generateMnemonic();
const account = await Account.generateFromMnemonic(mnenonic);
await account.init();
await registry.sendCoins({ denom: DENOM, amount: bidderInitialBalance.toString(), destinationAddress: account.address }, privateKey, fee);
bidderAccounts.push({ address: account.address, privateKey: account.privateKey.toString('hex') });
}
});
test('Create vickrey auction', async () => {
const minimumBid = {
denom: 'alnt',
amount: '1000000'
};
const auction = await registry.createAuction({
commitsDuration,
revealsDuration,
commitFee,
revealFee,
minimumBid
},
auctionCreatorAccount.privateKey, fee);
expect(auction.auction?.id).toBeDefined();
auctionId = auction.auction?.id || '';
expect(auction.auction?.status).toEqual('commit');
});
test('Commit bids.', async () => {
for (let i = 0; i < 3; i++) {
bidAmounts.push({
type: DENOM,
quantity: (10000000 + (i * 500)).toString()
});
bidderAccounts[i].bid = await createBid(chainId, auctionId, bidderAccounts[i].address, `${bidAmounts[i].quantity}${bidAmounts[i].type}`);
await registry.commitBid({ auctionId, commitHash: bidderAccounts[i].bid.commitHash }, bidderAccounts[i].privateKey, fee);
}
const [auction] = await registry.getAuctionsByIds([auctionId]);
expect(auction.status).toEqual('commit');
auction.bids.forEach((bid: any) => {
expect(bid.status).toEqual('commit');
});
});
test('Wait for reveal phase.', (done) => {
const commitTime = duration * 1000;
const waitTime = commitTime + (6 * 1000);
setTimeout(done, waitTime);
});
test('Reveal bids.', async () => {
const [auction] = await registry.getAuctionsByIds([auctionId]);
expect(auction.status).toEqual('reveal');
for (let i = 0; i < 3; i++) {
await registry.revealBid({ auctionId, reveal: bidderAccounts[i].bid.revealString }, bidderAccounts[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');
});
const actualBidAmounts = auction.bids.map((bid: any) => bid.bidAmount);
expect(actualBidAmounts).toEqual(expect.arrayContaining(bidAmounts));
});
test('Wait for auction completion.', (done) => {
const revealTime = duration * 1000;
const waitTime = revealTime + (6 * 1000);
setTimeout(done, waitTime);
});
test('Check auction winner, status, and winner balance.', async () => {
const [auction] = await registry.getAuctionsByIds([auctionId]);
expect(auction.status).toEqual('completed');
const highestBidder = bidderAccounts[bidderAccounts.length - 1];
const secondHighestBidder = (bidderAccounts[bidderAccounts.length - 2]);
expect(auction.winnerAddresses[0]).toEqual(highestBidder.address);
expect(highestBidder.bid.reveal.bidAmount).toEqual(`${auction.winnerBids[0].quantity}${auction.winnerBids[0].type}`);
expect(secondHighestBidder.bid.reveal.bidAmount).toEqual(`${auction.winnerPrice.quantity}${auction.winnerPrice.type}`);
const winningPriceAmount = parseInt(auction.winnerPrice.quantity, 10);
const expectedBalance = (bidderInitialBalance - winningPriceAmount);
const [winnerAccountObj] = await registry.getAccounts([highestBidder.address]);
expect(winnerAccountObj).toBeDefined();
expect(winnerAccountObj.address).toBe(highestBidder.address);
const [{ type, quantity }] = winnerAccountObj.balance;
expect(type).toBe(DENOM);
expect(parseInt(quantity)).toBeLessThan(expectedBalance);
});
};
const createProviderAuctionTests = () => {
let registry: Registry;
let auctionId: string;
let auctionCreatorAccount: { address: string, privateKey: string, bid?: any };
let bidderAccounts: { address: string, privateKey: string, bid?: any }[] = [];
let bidAmounts: { type: string, quantity: string }[] = [];
beforeAll(async () => {
registry = new Registry(gqlEndpoint, rpcEndpoint, { chainId });
// Create auction creator account
const mnenonic1 = Account.generateMnemonic();
const auctionCreator = await Account.generateFromMnemonic(mnenonic1);
await auctionCreator.init();
await registry.sendCoins({ denom: DENOM, amount: creatorInitialBalance.toString(), destinationAddress: auctionCreator.address }, privateKey, fee);
auctionCreatorAccount = { address: auctionCreator.address, privateKey: auctionCreator.privateKey.toString('hex') };
});
test('Setup bidder accounts', async () => {
for (let i = 0; i < 4; i++) {
const mnenonic = Account.generateMnemonic();
const account = await Account.generateFromMnemonic(mnenonic);
await account.init();
await registry.sendCoins({ denom: DENOM, amount: bidderInitialBalance.toString(), destinationAddress: account.address }, privateKey, fee);
bidderAccounts.push({ address: account.address, privateKey: account.privateKey.toString('hex') });
}
});
test('Create provider auction', async () => {
const maxPrice = {
denom: 'alnt',
amount: '100000000'
};
const auction = await registry.createProviderAuction({
commitsDuration,
revealsDuration,
commitFee,
revealFee,
maxPrice,
numProviders: 3
},
auctionCreatorAccount.privateKey, fee);
expect(auction.auction?.id).toBeDefined();
auctionId = auction.auction?.id || '';
expect(auction.auction?.status).toEqual('commit');
});
test('Commit bids.', async () => {
for (let i = 0; i < 4; i++) {
bidAmounts.push({
type: DENOM,
quantity: (100000 + (i * 500)).toString()
});
bidderAccounts[i].bid = await createBid(chainId, auctionId, bidderAccounts[i].address, `${bidAmounts[i].quantity}${bidAmounts[i].type}`);
await registry.commitBid({ auctionId, commitHash: bidderAccounts[i].bid.commitHash }, bidderAccounts[i].privateKey, fee);
}
const [auction] = await registry.getAuctionsByIds([auctionId]);
expect(auction.status).toEqual('commit');
auction.bids.forEach((bid: any) => {
expect(bid.status).toEqual('commit');
});
});
test('Wait for reveal phase.', (done) => {
const commitTime = duration * 1000;
const waitTime = commitTime + (6 * 1000);
setTimeout(done, waitTime);
});
test('Reveal bids.', async () => {
const [auction] = await registry.getAuctionsByIds([auctionId]);
expect(auction.status).toEqual('reveal');
for (let i = 0; i < 4; i++) {
await registry.revealBid({ auctionId, reveal: bidderAccounts[i].bid.revealString }, bidderAccounts[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');
});
const actualBidAmounts = auction.bids.map((bid: any) => bid.bidAmount);
expect(actualBidAmounts).toEqual(expect.arrayContaining(bidAmounts));
});
test('Wait for auction completion.', (done) => {
const revealTime = duration * 1000;
const waitTime = revealTime + (6 * 1000);
setTimeout(done, waitTime);
});
test('Check auction winner, status, and all bidder balances.', async () => {
const [auction] = await registry.getAuctionsByIds([auctionId]);
expect(auction.status).toEqual('completed');
const bidWinners = bidderAccounts.slice(0, 3); // Assuming top 3 are winners
for (let i = 0; i < bidWinners.length; i++) {
const winner = bidWinners[i];
expect(auction.winnerAddresses[i]).toEqual(winner.address);
expect(winner.bid.reveal.bidAmount).toEqual(`${auction.winnerBids[i].quantity}${auction.winnerBids[i].type}`);
const [winnerAccountObj] = await registry.getAccounts([winner.address]);
expect(winnerAccountObj).toBeDefined();
expect(winnerAccountObj.address).toBe(winner.address);
const [{ type, quantity }] = winnerAccountObj.balance;
const winningBidAmount = parseInt(auction.winnerPrice.quantity, 10);
const expectedBalance = bidderInitialBalance + winningBidAmount;
expect(type).toBe(DENOM);
expect(parseInt(quantity)).toBeLessThan(expectedBalance);
}
for (const bidder of bidderAccounts) {
const [bidderAccountObj] = await registry.getAccounts([bidder.address]);
expect(bidderAccountObj).toBeDefined();
expect(bidderAccountObj.address).toBe(bidder.address);
const [{ type, quantity }] = bidderAccountObj.balance;
const winningBidAmount = parseInt(auction.winnerPrice.quantity, 10);
const expectedWinningBalance = bidderInitialBalance - winningBidAmount;
expect(type).toBe(DENOM);
expect(parseInt(quantity)).toBeLessThan(expectedWinningBalance);
}
const [creatorAccountObj] = await registry.getAccounts([auctionCreatorAccount.address]);
expect(creatorAccountObj).toBeDefined();
expect(creatorAccountObj.address).toBe(auctionCreatorAccount.address);
const [{ type, quantity }] = creatorAccountObj.balance;
const totalWinningAmount = parseInt(auction.winnerPrice.quantity, 10) * bidWinners.length;
const expectedCreatorBalance = creatorInitialBalance - totalWinningAmount;
expect(type).toBe(DENOM);
expect(parseInt(quantity)).toBeLessThan(expectedCreatorBalance);
});
};
describe('Vickrey Auction', () => createAuctionTests());
describe('Provider Auction', () => createProviderAuctionTests());