비공개 최저가 경매 컨트랙트
이 Compact 컨트랙트는 비공개 최저가 경매를 구현하며, 입찰 금액은 공개하되 입찰자의 프라이버시는 보호합니다. 다음 기능을 시연합니다:
- 공개 ledger에서 정보 숨기기
- DApp 전용 공개 키를 통한 사용자 추적 방지
Map연산
pragma language_version 0.22;
import CompactStandardLibrary;
export enum AuctionState {
CLOSED,
OPEN
}
export sealed ledger auctionOrganizer: Bytes<32>;
export sealed ledger hiddenPrice: Bytes<32>;
export sealed ledger maxBids: Uint<16>;
export ledger publicPrice: Uint<16>;
export ledger bidders: Map<Bytes<32>, Uint<16>>;// 고유 입찰자, 입찰 덮어쓰기 허용
export ledger bidCount: Counter;// 입찰 횟수
export ledger highestBid: Uint<16>;
export ledger auctionState: AuctionState;
witness localSk(): Bytes<32>;
constructor(_minPrice: Uint<16>, maxBidCount: Uint<16>) {
const _sk = localSk();
const pubKey = getDappPubKey(_sk);
auctionOrganizer = disclose(pubKey);
const hashedPrice = commitWithSk(_minPrice as Bytes<32>, _sk);
maxBids = disclose(maxBidCount);
hiddenPrice = hashedPrice;
highestBid = 0;
auctionState = AuctionState.OPEN;
}
// 입찰자는 여러 번 입찰할 수 있습니다
export circuit bid(bidAmount: Uint<16>): [] {
assert(bidCount < maxBids, "Sorry, bids are full");
assert(auctionState == AuctionState.OPEN, "The auction has ended");
const _sk = localSk();
const key = getDappPubKey(_sk);
const pubKey = disclose(key);
const publicBid = disclose(bidAmount);
if(bidders.member(pubKey)){
assert(bidders.lookup(pubKey) < publicBid, "New bid lower than your previous bid");
}
bidders.insert(pubKey, publicBid);
bidCount.increment(1);
if(publicBid > highestBid){
highestBid = publicBid;
}
if(bidCount == maxBids){
auctionState = AuctionState.CLOSED;
}
}
// maxBids에 도달하지 않은 경우 주최자가 경매를 종료할 수 있게 합니다
export circuit closeAuction(minPrice: Uint<16>): Uint<16> {
const _sk = localSk();
const pubKey = getDappPubKey(_sk);
assert(disclose(pubKey) == auctionOrganizer, "You are not the auction organizer");
assert(auctionState == AuctionState.OPEN, "The auction has already been closed");
auctionState = AuctionState.CLOSED;
return revealWin(minPrice);
}
export circuit revealWin(minPrice: Uint<16>): Uint<16> {
const _sk = localSk();
const pubKey = getDappPubKey(_sk);
assert(auctionOrganizer == disclose(pubKey), "You are not the auction organizer");
assert(auctionState == AuctionState.CLOSED, "The auction is still open");
const hashedPrice = commitWithSk(minPrice as Bytes<32>, _sk);
assert(hashedPrice == hiddenPrice, "Attempt to change min price detected, shame on you.");
// 모든 투표가 완료되었으므로 공개 가격을 공개할 수 있습니다
publicPrice = disclose(minPrice);
// 공개 가격을 충족하지 못하면 최고 입찰가는 의미가 없습니다
if(highestBid < publicPrice){
return 0;
} else {
return highestBid;
}
}
circuit commitWithSk(_minPrice: Bytes<32>, _sk: Bytes<32>): Bytes<32> {
const hash = persistentHash<Vector<2, Bytes<32>>>([_minPrice, _sk]);
return disclose(hash);
}
// 사용자가 추적될 수 없도록 이 DApp에 특화된 "공개 키"를 해시합니다
export circuit getDappPubKey(_sk: Bytes<32>): Bytes<32> {
return persistentHash<Vector<2, Bytes<32>>>([pad(32, "silent-auction:pk:"), _sk]);
}