-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Daniel McGregor <[email protected]> Co-authored-by: Tristan Menzel <[email protected]>
- Loading branch information
Showing
762 changed files
with
96,439 additions
and
15,365 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Port of Beaker auction contract to TEALScript. Original source: https://github.com/algorand-devrel/beaker-auction/tree/7e1fe62b852c0d819954a931f10cf39d841cbc02 | ||
|
||
|
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import { Contract } from '../../src/lib/index'; | ||
|
||
// eslint-disable-next-line no-unused-vars | ||
class Auction extends Contract { | ||
previousBidder = GlobalStateKey<Address>(); | ||
|
||
auctionEnd = GlobalStateKey<uint64>(); | ||
|
||
previousBid = GlobalStateKey<uint64>(); | ||
|
||
asaAmt = GlobalStateKey<uint64>(); | ||
|
||
asa = GlobalStateKey<Asset>(); | ||
|
||
claimableAmount = LocalStateKey<uint64>(); | ||
|
||
createApplication(): void { | ||
this.auctionEnd.value = 0; | ||
this.previousBid.value = 0; | ||
this.asaAmt.value = 0; | ||
this.asa.value = Asset.zeroIndex; | ||
|
||
// Use zero address rather than an empty string for Account type safety | ||
this.previousBidder.value = globals.zeroAddress; | ||
} | ||
|
||
optIntoAsset(asset: Asset): void { | ||
/// Only allow app creator to opt the app account into a ASA | ||
verifyTxn(this.txn, { sender: globals.creatorAddress }); | ||
|
||
/// Verify a ASA hasn't already been opted into | ||
assert(this.asa.value === Asset.zeroIndex); | ||
|
||
/// Save ASA ID in global state | ||
this.asa.value = asset; | ||
|
||
/// Submit opt-in transaction: 0 asset transfer to self | ||
sendAssetTransfer({ | ||
assetReceiver: this.app.address, | ||
xferAsset: asset, | ||
assetAmount: 0, | ||
}); | ||
} | ||
|
||
startAuction(startingPrice: uint64, length: uint64, axfer: AssetTransferTxn): void { | ||
verifyTxn(this.txn, { sender: globals.creatorAddress }); | ||
|
||
/// Ensure the auction hasn't already been started | ||
assert(this.auctionEnd.value === 0); | ||
|
||
/// Verify axfer | ||
verifyTxn(axfer, { assetReceiver: this.app.address }); | ||
|
||
/// Set global state | ||
this.asaAmt.value = axfer.assetAmount; | ||
this.auctionEnd.value = globals.latestTimestamp + length; | ||
this.previousBid.value = startingPrice; | ||
} | ||
|
||
private pay(receiver: Account, amount: uint64): void { | ||
sendPayment({ | ||
receiver: receiver, | ||
amount: amount, | ||
}); | ||
} | ||
|
||
optInToApplication(): void {} | ||
|
||
// eslint-disable-next-line no-unused-vars | ||
bid(payment: PayTxn): void { | ||
/// Ensure auction hasn't ended | ||
assert(globals.latestTimestamp < this.auctionEnd.value); | ||
|
||
/// Verify payment transaction | ||
verifyTxn(payment, { | ||
sender: this.txn.sender, | ||
amount: { greaterThan: this.previousBid.value }, | ||
}); | ||
|
||
/// Set global state | ||
this.previousBid.value = payment.amount; | ||
this.previousBidder.value = payment.sender; | ||
|
||
/// Update claimable amount | ||
this.claimableAmount(this.txn.sender).value = payment.amount; | ||
} | ||
|
||
claimBids(): void { | ||
const originalAmount = this.claimableAmount(this.txn.sender).value; | ||
let amount = originalAmount; | ||
|
||
/// subtract previous bid if sender is previous bidder | ||
if (this.txn.sender === this.previousBidder.value) amount = amount - this.previousBid.value; | ||
|
||
this.pay(this.txn.sender, amount); | ||
this.claimableAmount(this.txn.sender).value = originalAmount - amount; | ||
} | ||
|
||
claim_asset(asset: Asset): void { | ||
assert(globals.latestTimestamp > this.auctionEnd.value); | ||
|
||
/// Send ASA to previous bidder | ||
sendAssetTransfer({ | ||
assetReceiver: this.previousBidder.value, | ||
xferAsset: asset, | ||
assetAmount: this.asaAmt.value, | ||
assetCloseTo: this.previousBidder.value, | ||
}); | ||
} | ||
|
||
deleteApplication(): void { | ||
sendPayment({ | ||
receiver: globals.creatorAddress, | ||
closeRemainderTo: globals.creatorAddress, | ||
amount: 0, | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
from algopy import ( | ||
ARC4Contract, | ||
AssetTransferTransaction, | ||
CreateInnerTransaction, | ||
Global, | ||
Local, | ||
PaymentTransaction, | ||
Transaction, | ||
TransactionType, | ||
UInt64, | ||
arc4, | ||
subroutine, | ||
) | ||
from algopy._reference import Asset | ||
|
||
|
||
class Auction(ARC4Contract): | ||
def __init__(self) -> None: | ||
self.auction_end = UInt64(0) | ||
self.previous_bid = UInt64(0) | ||
self.asa_amount = UInt64(0) | ||
self.asa = Asset(0) | ||
# Use zero address rather than an empty string for Account type safety | ||
self.previous_bidder = Global.zero_address() | ||
self.claimable_amount = Local(UInt64) | ||
|
||
@arc4.abimethod | ||
def opt_into_asset(self, asset: Asset) -> None: | ||
# Only allow app creator to opt the app account into a ASA | ||
assert Transaction.sender() == Global.creator_address(), "Only creator can opt in to ASA" | ||
# Verify a ASA hasn't already been opted into | ||
assert self.asa.asset_id == 0, "ASA already opted in" | ||
# Save ASA ID in global state | ||
self.asa = asset | ||
|
||
# Submit opt-in transaction: 0 asset transfer to self | ||
CreateInnerTransaction.begin() | ||
CreateInnerTransaction.set_type_enum(TransactionType.AssetTransfer) | ||
CreateInnerTransaction.set_fee(UInt64(0)) # cover fee with outer txn | ||
CreateInnerTransaction.set_asset_receiver(Global.current_application_address()) | ||
CreateInnerTransaction.set_xfer_asset(asset.asset_id) | ||
CreateInnerTransaction.submit() | ||
|
||
@arc4.abimethod | ||
def start_auction( | ||
self, starting_price: arc4.UInt64, length: arc4.UInt64, axfer: AssetTransferTransaction | ||
) -> None: | ||
assert ( | ||
Transaction.sender() == Global.creator_address() | ||
), "auction must be started by creator" | ||
|
||
# Ensure the auction hasn't already been started | ||
assert self.auction_end == 0, "auction already started" | ||
|
||
# Verify axfer | ||
assert ( | ||
axfer.asset_receiver == Global.current_application_address() | ||
), "axfer must transfer to this app" | ||
|
||
# Set global state | ||
self.asa_amount = axfer.asset_amount | ||
self.auction_end = Global.latest_timestamp() + length.decode() | ||
self.previous_bid = starting_price.decode() | ||
|
||
@arc4.abimethod | ||
def opt_in(self) -> None: | ||
pass | ||
|
||
@arc4.abimethod | ||
def bid(self, pay: PaymentTransaction) -> None: | ||
# Ensure auction hasn't ended | ||
assert Global.latest_timestamp() < self.auction_end, "auction has ended" | ||
|
||
# Verify payment transaction | ||
assert pay.sender == Transaction.sender(), "payment sender must match transaction sender" | ||
assert pay.amount > self.previous_bid, "Bid must be higher than previous bid" | ||
|
||
# set global state | ||
self.previous_bid = pay.amount | ||
self.previous_bidder = pay.sender | ||
|
||
# Update claimable amount | ||
self.claimable_amount[Transaction.sender()] = pay.amount | ||
|
||
@arc4.abimethod | ||
def claim_bids(self) -> None: | ||
original_amount = self.claimable_amount[Transaction.sender()] | ||
|
||
amount = original_amount | ||
|
||
# subtract previous bid if sender is previous bidder | ||
if Transaction.sender() == self.previous_bidder: | ||
amount -= self.previous_bid | ||
|
||
CreateInnerTransaction.begin() | ||
CreateInnerTransaction.set_type_enum(TransactionType.Payment) | ||
CreateInnerTransaction.set_fee(UInt64(0)) # cover fee with outer txn | ||
CreateInnerTransaction.set_receiver(Transaction.sender()) | ||
CreateInnerTransaction.set_asset_amount(amount) | ||
CreateInnerTransaction.submit() | ||
|
||
self.claimable_amount[Transaction.sender()] = original_amount - amount | ||
|
||
@arc4.abimethod | ||
def claim_asset(self, asset: Asset) -> None: | ||
assert Global.latest_timestamp() > self.auction_end, "auction has not ended" | ||
|
||
# Send ASA to previous bidder | ||
CreateInnerTransaction.begin() | ||
CreateInnerTransaction.set_type_enum(TransactionType.AssetTransfer) | ||
CreateInnerTransaction.set_fee(UInt64(0)) # cover fee with outer txn | ||
CreateInnerTransaction.set_asset_receiver(self.previous_bidder) | ||
CreateInnerTransaction.set_xfer_asset(asset.asset_id) | ||
CreateInnerTransaction.set_asset_amount(self.asa_amount) | ||
CreateInnerTransaction.set_asset_close_to(self.previous_bidder) | ||
CreateInnerTransaction.submit() | ||
|
||
@subroutine | ||
def delete_application(self) -> None: | ||
CreateInnerTransaction.begin() | ||
CreateInnerTransaction.set_type_enum(TransactionType.Payment) | ||
CreateInnerTransaction.set_fee(UInt64(0)) # cover fee with outer txn | ||
CreateInnerTransaction.set_receiver(Global.creator_address()) | ||
CreateInnerTransaction.set_close_remainder_to(Global.creator_address()) | ||
CreateInnerTransaction.submit() | ||
|
||
def clear_state_program(self) -> bool: | ||
return True |
Oops, something went wrong.