Add methods for creating auctions and add auction tests #28

Merged
nabarun merged 32 commits from deep-stack/registry-sdk:iv-create-auction-test into main 2024-09-25 13:21:05 +00:00
3 changed files with 100 additions and 92 deletions
Showing only changes of commit 1bb84c510c - Show all commits

View File

@ -12,29 +12,24 @@ jest.setTimeout(30 * 60 * 1000);
const { chainId, rpcEndpoint, gqlEndpoint, privateKey, fee } = getConfig(); const { chainId, rpcEndpoint, gqlEndpoint, privateKey, fee } = getConfig();
const duration = 60; const duration = 60;
const commitsDuration = Duration.fromPartial({ seconds: Long.fromNumber(60) });
const commitsDuration = Duration.fromPartial({ const revealsDuration = Duration.fromPartial({ seconds: Long.fromNumber(60) });
seconds: Long.fromNumber(duration),
nanos: 0
});
const revealsDuration = Duration.fromPartial({
seconds: Long.fromNumber(duration),
nanos: 0
});
const commitFee = coin('1000', DENOM); const commitFee = coin('1000', DENOM);
const revealFee = coin('1000', DENOM); const revealFee = coin('1000', DENOM);
const creatorInitialBalance = 1000000000000; const creatorInitialBalance = 1000000000000;
const bidderInitialBalance = 20000000; const bidderInitialBalance = 20000000;
const lowestBidAmount = 10000000;
const createAuctionTests = () => { const auctionTests = () => {
let registry: Registry; let registry: Registry;
let auctionId: string; let auctionId: string;
let auctionCreatorAccount: { address: string, privateKey: string, bid?: any }; let auctionCreatorAccount: { address: string, privateKey: string };
let bidderAccounts: { address: string, privateKey: string, bid?: any }[] = []; let bidderAccounts: { address: string, privateKey: string, bid?: any }[] = [];
const numBidders = 3;
let bidAmounts: Coin[] = []; let bidAmounts: Coin[] = [];
beforeAll(async () => { beforeAll(async () => {
@ -44,31 +39,36 @@ const createAuctionTests = () => {
const mnenonic1 = Account.generateMnemonic(); const mnenonic1 = Account.generateMnemonic();
const auctionCreator = await Account.generateFromMnemonic(mnenonic1); const auctionCreator = await Account.generateFromMnemonic(mnenonic1);
await auctionCreator.init(); await auctionCreator.init();
await registry.sendCoins({ denom: DENOM, amount: creatorInitialBalance.toString(), destinationAddress: auctionCreator.address }, privateKey, fee); await registry.sendCoins({ denom: DENOM, amount: creatorInitialBalance.toString(), destinationAddress: auctionCreator.address }, privateKey, fee);
auctionCreatorAccount = { address: auctionCreator.address, privateKey: auctionCreator.privateKey.toString('hex') }; auctionCreatorAccount = { address: auctionCreator.address, privateKey: auctionCreator.privateKey.toString('hex') };
}); });
test('Setup bidder accounts', async () => { test('Setup bidder accounts', async () => {
for (let i = 0; i < 3; i++) { for (let i = 0; i < numBidders; i++) {
const mnenonic = Account.generateMnemonic(); const mnenonic = Account.generateMnemonic();
const account = await Account.generateFromMnemonic(mnenonic); const account = await Account.generateFromMnemonic(mnenonic);
await account.init(); await account.init();
await registry.sendCoins({ denom: DENOM, amount: bidderInitialBalance.toString(), destinationAddress: account.address }, privateKey, fee); await registry.sendCoins({ denom: DENOM, amount: bidderInitialBalance.toString(), destinationAddress: account.address }, privateKey, fee);
bidderAccounts.push({ address: account.address, privateKey: account.privateKey.toString('hex') }); bidderAccounts.push({ address: account.address, privateKey: account.privateKey.toString('hex') });
} }
}); });
test('Create vickrey auction', async () => { test('Create a vickrey auction', async () => {
const minimumBid = coin('1000000', DENOM); const minimumBid = coin('1000000', DENOM);
const auction = await registry.createAuction({ const auction = await registry.createAuction(
{
commitsDuration, commitsDuration,
revealsDuration, revealsDuration,
commitFee, commitFee,
revealFee, revealFee,
minimumBid minimumBid
}, },
auctionCreatorAccount.privateKey, fee); auctionCreatorAccount.privateKey,
fee
);
expect(auction.auction?.id).toBeDefined(); expect(auction.auction?.id).toBeDefined();
auctionId = auction.auction?.id || ''; auctionId = auction.auction?.id || '';
@ -76,8 +76,8 @@ const createAuctionTests = () => {
}); });
test('Commit bids.', async () => { test('Commit bids.', async () => {
for (let i = 0; i < 3; i++) { for (let i = 0; i < numBidders; i++) {
bidAmounts.push(coin((10000000 + (i * 500)).toString(), DENOM)); bidAmounts.push(coin((lowestBidAmount + (i * 500)).toString(), DENOM));
bidderAccounts[i].bid = await createBid(chainId, auctionId, bidderAccounts[i].address, `${bidAmounts[i].amount}${bidAmounts[i].denom}`); bidderAccounts[i].bid = await createBid(chainId, auctionId, bidderAccounts[i].address, `${bidAmounts[i].amount}${bidAmounts[i].denom}`);
await registry.commitBid({ auctionId, commitHash: bidderAccounts[i].bid.commitHash }, bidderAccounts[i].privateKey, fee); await registry.commitBid({ auctionId, commitHash: bidderAccounts[i].bid.commitHash }, bidderAccounts[i].privateKey, fee);
} }
@ -101,7 +101,7 @@ const createAuctionTests = () => {
const [auction] = await registry.getAuctionsByIds([auctionId]); const [auction] = await registry.getAuctionsByIds([auctionId]);
expect(auction.status).toEqual('reveal'); expect(auction.status).toEqual('reveal');
for (let i = 0; i < 3; i++) { for (let i = 0; i < numBidders; i++) {
await registry.revealBid({ auctionId, reveal: bidderAccounts[i].bid.revealString }, bidderAccounts[i].privateKey, fee); await registry.revealBid({ auctionId, reveal: bidderAccounts[i].bid.revealString }, bidderAccounts[i].privateKey, fee);
} }
}); });
@ -129,33 +129,35 @@ const createAuctionTests = () => {
expect(auction.status).toEqual('completed'); expect(auction.status).toEqual('completed');
const highestBidder = bidderAccounts[bidderAccounts.length - 1]; const highestBidder = bidderAccounts[bidderAccounts.length - 1];
const secondHighestBidder = (bidderAccounts[bidderAccounts.length - 2]); const secondHighestBidder = bidderAccounts[bidderAccounts.length - 2];
expect(auction.winnerAddresses).toHaveLength(1);
expect(auction.winnerAddresses[0]).toEqual(highestBidder.address); expect(auction.winnerAddresses[0]).toEqual(highestBidder.address);
expect(highestBidder.bid.reveal.bidAmount).toEqual(`${auction.winnerBids[0].quantity}${auction.winnerBids[0].type}`); 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}`); expect(secondHighestBidder.bid.reveal.bidAmount).toEqual(`${auction.winnerPrice.quantity}${auction.winnerPrice.type}`);
const winningPriceAmount = parseInt(auction.winnerPrice.quantity, 10); const winningPriceAmount = parseInt(auction.winnerPrice.quantity);
const expectedBalance = (bidderInitialBalance - winningPriceAmount);
const [winnerAccountObj] = await registry.getAccounts([highestBidder.address]); const [winnerAccountObj] = await registry.getAccounts([highestBidder.address]);
expect(winnerAccountObj).toBeDefined(); expect(winnerAccountObj).toBeDefined();
expect(winnerAccountObj.address).toBe(highestBidder.address);
// Balance should be less than bidder's initial balance - winning price as tx fees also gets deducted
const [{ type, quantity }] = winnerAccountObj.balance; const [{ type, quantity }] = winnerAccountObj.balance;
expect(type).toBe(DENOM); expect(type).toBe(DENOM);
expect(parseInt(quantity)).toBeLessThan(expectedBalance); expect(parseInt(quantity)).toBeLessThan(bidderInitialBalance - winningPriceAmount);
}); });
}; };
const createProviderAuctionTests = () => { const providerAuctionTests = () => {
let registry: Registry; let registry: Registry;
let auctionId: string; let auctionId: string;
let auctionCreatorAccount: { address: string, privateKey: string, bid?: any }; let auctionCreatorAccount: { address: string, privateKey: string, bid?: any };
let bidderAccounts: { address: string, privateKey: string, bid?: any }[] = []; let bidderAccounts: { address: string, privateKey: string, bid?: any }[] = [];
const numBidders = 4;
const numProviders = 3;
let bidAmounts: Coin[] = []; let bidAmounts: Coin[] = [];
beforeAll(async () => { beforeAll(async () => {
@ -165,32 +167,36 @@ const createProviderAuctionTests = () => {
const mnenonic1 = Account.generateMnemonic(); const mnenonic1 = Account.generateMnemonic();
const auctionCreator = await Account.generateFromMnemonic(mnenonic1); const auctionCreator = await Account.generateFromMnemonic(mnenonic1);
await auctionCreator.init(); await auctionCreator.init();
await registry.sendCoins({ denom: DENOM, amount: creatorInitialBalance.toString(), destinationAddress: auctionCreator.address }, privateKey, fee); await registry.sendCoins({ denom: DENOM, amount: creatorInitialBalance.toString(), destinationAddress: auctionCreator.address }, privateKey, fee);
auctionCreatorAccount = { address: auctionCreator.address, privateKey: auctionCreator.privateKey.toString('hex') }; auctionCreatorAccount = { address: auctionCreator.address, privateKey: auctionCreator.privateKey.toString('hex') };
}); });
test('Setup bidder accounts', async () => { test('Setup bidder accounts', async () => {
for (let i = 0; i < 4; i++) { for (let i = 0; i < numBidders; i++) {
const mnenonic = Account.generateMnemonic(); const mnenonic = Account.generateMnemonic();
const account = await Account.generateFromMnemonic(mnenonic); const account = await Account.generateFromMnemonic(mnenonic);
await account.init(); await account.init();
await registry.sendCoins({ denom: DENOM, amount: bidderInitialBalance.toString(), destinationAddress: account.address }, privateKey, fee); await registry.sendCoins({ denom: DENOM, amount: bidderInitialBalance.toString(), destinationAddress: account.address }, privateKey, fee);
bidderAccounts.push({ address: account.address, privateKey: account.privateKey.toString('hex') }); bidderAccounts.push({ address: account.address, privateKey: account.privateKey.toString('hex') });
} }
}); });
test('Create provider auction', async () => { test('Create a provider auction', async () => {
const maxPrice = coin('100000000', DENOM); const maxPrice = coin((10 * lowestBidAmount).toString(), DENOM);
const auction = await registry.createProviderAuction({ const auction = await registry.createProviderAuction(
{
commitsDuration, commitsDuration,
revealsDuration, revealsDuration,
commitFee, commitFee,
revealFee, revealFee,
maxPrice, maxPrice,
numProviders: 3 numProviders
}, },
auctionCreatorAccount.privateKey, fee); auctionCreatorAccount.privateKey, fee
);
expect(auction.auction?.id).toBeDefined(); expect(auction.auction?.id).toBeDefined();
auctionId = auction.auction?.id || ''; auctionId = auction.auction?.id || '';
@ -198,15 +204,15 @@ const createProviderAuctionTests = () => {
}); });
test('Commit bids.', async () => { test('Commit bids.', async () => {
for (let i = 0; i < 4; i++) { for (let i = 0; i < numBidders; i++) {
bidAmounts.push(coin((100000 + (i * 500)).toString(), DENOM)); bidAmounts.push(coin((lowestBidAmount + (i * 500)).toString(), DENOM));
bidderAccounts[i].bid = await createBid(chainId, auctionId, bidderAccounts[i].address, `${bidAmounts[i].amount}${bidAmounts[i].denom}`); bidderAccounts[i].bid = await createBid(chainId, auctionId, bidderAccounts[i].address, `${bidAmounts[i].amount}${bidAmounts[i].denom}`);
await registry.commitBid({ auctionId, commitHash: bidderAccounts[i].bid.commitHash }, bidderAccounts[i].privateKey, fee); await registry.commitBid({ auctionId, commitHash: bidderAccounts[i].bid.commitHash }, bidderAccounts[i].privateKey, fee);
} }
const [auction] = await registry.getAuctionsByIds([auctionId]); const [auction] = await registry.getAuctionsByIds([auctionId]);
expect(auction.status).toEqual('commit'); expect(auction.status).toEqual('commit');
expect(auction.bids.length).toEqual(3); expect(auction.bids.length).toEqual(numBidders);
auction.bids.forEach((bid: any) => { auction.bids.forEach((bid: any) => {
expect(bid.status).toEqual('commit'); expect(bid.status).toEqual('commit');
}); });
@ -223,7 +229,7 @@ const createProviderAuctionTests = () => {
const [auction] = await registry.getAuctionsByIds([auctionId]); const [auction] = await registry.getAuctionsByIds([auctionId]);
expect(auction.status).toEqual('reveal'); expect(auction.status).toEqual('reveal');
for (let i = 0; i < 4; i++) { for (let i = 0; i < numBidders; i++) {
await registry.revealBid({ auctionId, reveal: bidderAccounts[i].bid.revealString }, bidderAccounts[i].privateKey, fee); await registry.revealBid({ auctionId, reveal: bidderAccounts[i].bid.revealString }, bidderAccounts[i].privateKey, fee);
} }
}); });
@ -250,51 +256,49 @@ const createProviderAuctionTests = () => {
const [auction] = await registry.getAuctionsByIds([auctionId]); const [auction] = await registry.getAuctionsByIds([auctionId]);
expect(auction.status).toEqual('completed'); expect(auction.status).toEqual('completed');
const bidWinners = bidderAccounts.slice(0, 3); const bidWinners = bidderAccounts.slice(0, numProviders);
const bidLosers = bidderAccounts.slice(numProviders, numBidders);
// Check balances of auction winners // Check balances of auction winners
for (let i = 0; i < bidWinners.length; i++) { for (let i = 0; i < bidWinners.length; i++) {
const winner = bidWinners[i]; const expectedWinner = bidWinners[i];
expect(auction.winnerAddresses[i]).toEqual(winner.address); expect(auction.winnerAddresses[i]).toEqual(expectedWinner.address);
expect(winner.bid.reveal.bidAmount).toEqual(`${auction.winnerBids[i].quantity}${auction.winnerBids[i].type}`); expect(expectedWinner.bid.reveal.bidAmount).toEqual(`${auction.winnerBids[i].quantity}${auction.winnerBids[i].type}`);
const [winnerAccountObj] = await registry.getAccounts([winner.address]); const [winnerAccountObj] = await registry.getAccounts([expectedWinner.address]);
expect(winnerAccountObj).toBeDefined(); expect(winnerAccountObj).toBeDefined();
expect(winnerAccountObj.address).toBe(winner.address);
const [{ type, quantity }] = winnerAccountObj.balance; const [{ type, quantity }] = winnerAccountObj.balance;
const winningBidAmount = parseInt(auction.winnerPrice.quantity, 10); const actualBalance = parseInt(quantity);
const expectedBalance = bidderInitialBalance + winningBidAmount; const winningBidAmount = parseInt(auction.winnerPrice.quantity);
// The actual balance would be less than expected balance as fees would also get deducted // Balance should be more than bidder's initial balance but
// less than initial balance + winning price as tx fees also gets deducted
expect(type).toBe(DENOM); expect(type).toBe(DENOM);
expect(expectedBalance).toBeLessThan(parseInt(quantity)); expect(actualBalance).toBeGreaterThan(bidderInitialBalance);
expect(actualBalance).toBeLessThan(bidderInitialBalance + winningBidAmount);
} }
// Check balances of non-winners // Check balances of non-winners
for (let i = 3; i < bidderAccounts.length; i++) { for (const bidder of bidLosers) {
const bidder = bidderAccounts[i];
const [bidderAccountObj] = await registry.getAccounts([bidder.address]); const [bidderAccountObj] = await registry.getAccounts([bidder.address]);
expect(bidderAccountObj).toBeDefined(); expect(bidderAccountObj).toBeDefined();
expect(bidderAccountObj.address).toBe(bidder.address);
const [{ type, quantity }] = bidderAccountObj.balance; const [{ type, quantity }] = bidderAccountObj.balance;
// The balance would be less than initial balance as fees would get deducted // Balance should be less than initial balance as fees would get deducted
expect(type).toBe(DENOM); expect(type).toBe(DENOM);
expect(parseInt(quantity)).toBeLessThan(bidderInitialBalance); expect(parseInt(quantity)).toBeLessThan(bidderInitialBalance);
} }
const [creatorAccountObj] = await registry.getAccounts([auctionCreatorAccount.address]); const [creatorAccountObj] = await registry.getAccounts([auctionCreatorAccount.address]);
expect(creatorAccountObj).toBeDefined(); expect(creatorAccountObj).toBeDefined();
expect(creatorAccountObj.address).toBe(auctionCreatorAccount.address);
const [{ type, quantity }] = creatorAccountObj.balance; const [{ type, quantity }] = creatorAccountObj.balance;
const totalWinningAmount = parseInt(auction.winnerPrice.quantity, 10) * bidWinners.length; const totalWinningAmount = parseInt(auction.winnerPrice.quantity) * bidWinners.length;
const expectedCreatorBalance = creatorInitialBalance + totalWinningAmount; const expectedCreatorBalance = creatorInitialBalance - totalWinningAmount;
// The balance would be less than expected balance // The balance would be less than expected balance
expect(type).toBe(DENOM); expect(type).toBe(DENOM);
@ -302,5 +306,5 @@ const createProviderAuctionTests = () => {
}); });
}; };
describe('Vickrey Auction', () => createAuctionTests()); describe('Vickrey Auction', () => auctionTests());
describe('Provider Auction', () => createProviderAuctionTests()); describe('Provider Auction', () => providerAuctionTests());

View File

@ -33,8 +33,8 @@ import { Coin } from './proto/cosmos/base/v1beta1/coin';
import { MsgCancelBondResponse, MsgCreateBondResponse, MsgRefillBondResponse, MsgWithdrawBondResponse } from './proto/cerc/bond/v1/tx'; import { MsgCancelBondResponse, MsgCreateBondResponse, MsgRefillBondResponse, MsgWithdrawBondResponse } from './proto/cerc/bond/v1/tx';
import { MsgOnboardParticipantResponse } from './proto/cerc/onboarding/v1/tx'; import { MsgOnboardParticipantResponse } from './proto/cerc/onboarding/v1/tx';
import { MsgSendResponse } from './proto/cosmos/bank/v1beta1/tx'; import { MsgSendResponse } from './proto/cosmos/bank/v1beta1/tx';
import { DEFAULT_GAS_ESTIMATION_MULTIPLIER } from './constants'; import { AUCTION_KIND_PROVIDER, AUCTION_KIND_VICKREY, DEFAULT_GAS_ESTIMATION_MULTIPLIER } from './constants';
import { MsgCreateAuction, MsgCreateAuctionResponse } from './proto/cerc/auction/v1/tx'; import { MsgCreateAuctionResponse } from './proto/cerc/auction/v1/tx';
/** /**
* Create an auction bid. * Create an auction bid.
@ -503,7 +503,8 @@ export class Registry {
); );
} }
async createAuction ({ async createAuction (
{
commitsDuration, commitsDuration,
revealsDuration, revealsDuration,
commitFee, commitFee,
@ -511,14 +512,15 @@ export class Registry {
minimumBid minimumBid
}: MsgCreateVickreyAuction, }: MsgCreateVickreyAuction,
privateKey: string, privateKey: string,
fee: StdFee | number = DEFAULT_GAS_ESTIMATION_MULTIPLIER): Promise<MsgCreateAuctionResponse> { fee: StdFee | number = DEFAULT_GAS_ESTIMATION_MULTIPLIER
): Promise<MsgCreateAuctionResponse> {
const account = new Account(Buffer.from(privateKey, 'hex')); const account = new Account(Buffer.from(privateKey, 'hex'));
await account.init(); await account.init();
const laconicClient = await this.getLaconicClient(account); const laconicClient = await this.getLaconicClient(account);
return laconicClient.createAuction( return laconicClient.createAuction(
account.address, account.address,
'vickrey', AUCTION_KIND_VICKREY,
commitsDuration, commitsDuration,
revealsDuration, revealsDuration,
commitFee, commitFee,
@ -530,7 +532,8 @@ export class Registry {
); );
} }
async createProviderAuction ({ async createProviderAuction (
{
commitsDuration, commitsDuration,
revealsDuration, revealsDuration,
commitFee, commitFee,
@ -539,14 +542,15 @@ export class Registry {
numProviders numProviders
}: MsgCreateProviderAuction, }: MsgCreateProviderAuction,
privateKey: string, privateKey: string,
fee: StdFee | number = DEFAULT_GAS_ESTIMATION_MULTIPLIER): Promise<MsgCreateAuctionResponse> { fee: StdFee | number = DEFAULT_GAS_ESTIMATION_MULTIPLIER
): Promise<MsgCreateAuctionResponse> {
const account = new Account(Buffer.from(privateKey, 'hex')); const account = new Account(Buffer.from(privateKey, 'hex'));
await account.init(); await account.init();
const laconicClient = await this.getLaconicClient(account); const laconicClient = await this.getLaconicClient(account);
return laconicClient.createAuction( return laconicClient.createAuction(
account.address, account.address,
'provider', AUCTION_KIND_PROVIDER,
commitsDuration, commitsDuration,
revealsDuration, revealsDuration,
commitFee, commitFee,

View File

@ -431,13 +431,13 @@ export class LaconicClient extends SigningStargateClient {
const createAuctionMsg: MsgCreateAuctionEncodeObject = { const createAuctionMsg: MsgCreateAuctionEncodeObject = {
typeUrl: typeUrlMsgCreateAuction, typeUrl: typeUrlMsgCreateAuction,
value: { value: {
signer,
kind,
commitsDuration, commitsDuration,
revealsDuration, revealsDuration,
commitFee, commitFee,
revealFee, revealFee,
minimumBid, minimumBid,
signer,
kind,
maxPrice, maxPrice,
numProviders numProviders
} }