-
Notifications
You must be signed in to change notification settings - Fork 220
/
Copy pathsecondPriceAuction.js
102 lines (87 loc) · 3.2 KB
/
secondPriceAuction.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// @ts-check
import { E } from '@agoric/eventual-send';
// Eventually will be importable from '@agoric/zoe-contract-support'
import {
defaultAcceptanceMsg,
assertIssuerKeywords,
assertProposalShape,
} from '../../contractSupport';
import { calcWinnerAndClose } from './secondPriceLogic';
import { assertBidSeat } from './assertBidSeat';
import '../../../exported';
/**
* NOT TO BE USED IN PRODUCTION CODE. BIDS ARE PUBLIC. An auction
* contract in which the seller offers an Asset for sale, and states a
* minimum price. The auction closes at the deadline specified by the
* timeAuthority and closesAfter parameters in the terms provided by
* the creator of the contract instance. The second price rule is
* followed, so the highest bidder pays the amount bid by the second
* highest bidder.
* https://agoric.com/documentation/zoe/guide/contracts/second-price-auction.html
*
* startInstance() specifies the issuers and the terms. An invitation
* for the seller is returned as the creatorInvitation. The seller's
* offer should look like { give: { Asset: asset }, want: { Ask:
* minimumBidAmount}} The asset can be non-fungible, but the Ask
* amount should be of a fungible brand. The bidder invitations can be
* made by calling makeBidInvitation on the object returned from the
* seller's offer. Each bidder can submit an offer: { give: { Bid:
* null } want: { Asset: null } }.
*
* @type {ContractStartFn}
*/
const start = zcf => {
const { timeAuthority, closesAfter } = zcf.getTerms();
let sellSeat;
const bidSeats = [];
// seller will use 'Asset' and 'Ask'. buyer will use 'Asset' and 'Bid'
assertIssuerKeywords(zcf, harden(['Asset', 'Ask']));
E(timeAuthority)
.setWakeup(
closesAfter,
harden({ wake: () => calcWinnerAndClose(zcf, sellSeat, bidSeats) }),
)
.catch(err => {
console.error(
`Could not schedule the close of the auction at the 'closesAfter' deadline ${closesAfter} using this timer ${timeAuthority}`,
);
console.error(err);
throw err;
});
const makeBidInvitation = () => {
/** @type {OfferHandler} */
const performBid = seat => {
assertProposalShape(seat, {
give: { Bid: null },
want: { Asset: null },
});
assertBidSeat(zcf, sellSeat, seat);
bidSeats.push(seat);
return defaultAcceptanceMsg;
};
const customProperties = harden({
auctionedAssets: sellSeat.getProposal().give.Asset,
minimumBid: sellSeat.getProposal().want.Ask,
closesAfter,
timeAuthority,
});
return zcf.makeInvitation(performBid, 'bid', customProperties);
};
const sell = seat => {
assertProposalShape(seat, {
give: { Asset: null },
want: { Ask: null },
// The auction is not over until the deadline according to the
// provided timer. The seller cannot exit beforehand.
exit: { waived: null },
});
// Save the seat for when the auction closes.
sellSeat = seat;
// The bid invitations can only be sent out after the assets to be
// auctioned are escrowed.
return harden({ makeBidInvitation });
};
const creatorInvitation = zcf.makeInvitation(sell, 'sellAssets');
return harden({ creatorInvitation });
};
export { start };