mirror of
https://github.com/autistic-symposium/web3-starter-sol.git
synced 2025-07-22 14:40:35 -04:00
Clean up
This commit is contained in:
parent
c2d0866191
commit
db37d209ab
58 changed files with 4663 additions and 1043 deletions
5
advanced_knowledge/applications_contracts/README.md
Normal file
5
advanced_knowledge/applications_contracts/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
## a place to dump application contracts
|
||||
|
||||
<br>
|
||||
|
||||
* disclaimer: these boilerplates might not be my code, but rather well-known references.
|
136
advanced_knowledge/applications_contracts/crowd_fund.sol
Normal file
136
advanced_knowledge/applications_contracts/crowd_fund.sol
Normal file
|
@ -0,0 +1,136 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.17;
|
||||
|
||||
/*
|
||||
Crowd fund ERC20 token
|
||||
|
||||
User creates a campaign.
|
||||
Users can pledge, transferring their token to a campaign.
|
||||
After the campaign ends, campaign creator can claim the funds if total amount pledged is more than the campaign goal.
|
||||
Otherwise, campaign did not reach it's goal, users can withdraw their pledge.
|
||||
*/
|
||||
|
||||
|
||||
interface IERC20 {
|
||||
function transfer(address, uint) external returns (bool);
|
||||
|
||||
function transferFrom(address, address, uint) external returns (bool);
|
||||
}
|
||||
|
||||
contract CrowdFund {
|
||||
event Launch(
|
||||
uint id,
|
||||
address indexed creator,
|
||||
uint goal,
|
||||
uint32 startAt,
|
||||
uint32 endAt
|
||||
);
|
||||
event Cancel(uint id);
|
||||
event Pledge(uint indexed id, address indexed caller, uint amount);
|
||||
event Unpledge(uint indexed id, address indexed caller, uint amount);
|
||||
event Claim(uint id);
|
||||
event Refund(uint id, address indexed caller, uint amount);
|
||||
|
||||
struct Campaign {
|
||||
// Creator of campaign
|
||||
address creator;
|
||||
// Amount of tokens to raise
|
||||
uint goal;
|
||||
// Total amount pledged
|
||||
uint pledged;
|
||||
// Timestamp of start of campaign
|
||||
uint32 startAt;
|
||||
// Timestamp of end of campaign
|
||||
uint32 endAt;
|
||||
// True if goal was reached and creator has claimed the tokens.
|
||||
bool claimed;
|
||||
}
|
||||
|
||||
IERC20 public immutable token;
|
||||
// Total count of campaigns created.
|
||||
// It is also used to generate id for new campaigns.
|
||||
uint public count;
|
||||
// Mapping from id to Campaign
|
||||
mapping(uint => Campaign) public campaigns;
|
||||
// Mapping from campaign id => pledger => amount pledged
|
||||
mapping(uint => mapping(address => uint)) public pledgedAmount;
|
||||
|
||||
constructor(address _token) {
|
||||
token = IERC20(_token);
|
||||
}
|
||||
|
||||
function launch(uint _goal, uint32 _startAt, uint32 _endAt) external {
|
||||
require(_startAt >= block.timestamp, "start at < now");
|
||||
require(_endAt >= _startAt, "end at < start at");
|
||||
require(_endAt <= block.timestamp + 90 days, "end at > max duration");
|
||||
|
||||
count += 1;
|
||||
campaigns[count] = Campaign({
|
||||
creator: msg.sender,
|
||||
goal: _goal,
|
||||
pledged: 0,
|
||||
startAt: _startAt,
|
||||
endAt: _endAt,
|
||||
claimed: false
|
||||
});
|
||||
|
||||
emit Launch(count, msg.sender, _goal, _startAt, _endAt);
|
||||
}
|
||||
|
||||
function cancel(uint _id) external {
|
||||
Campaign memory campaign = campaigns[_id];
|
||||
require(campaign.creator == msg.sender, "not creator");
|
||||
require(block.timestamp < campaign.startAt, "started");
|
||||
|
||||
delete campaigns[_id];
|
||||
emit Cancel(_id);
|
||||
}
|
||||
|
||||
function pledge(uint _id, uint _amount) external {
|
||||
Campaign storage campaign = campaigns[_id];
|
||||
require(block.timestamp >= campaign.startAt, "not started");
|
||||
require(block.timestamp <= campaign.endAt, "ended");
|
||||
|
||||
campaign.pledged += _amount;
|
||||
pledgedAmount[_id][msg.sender] += _amount;
|
||||
token.transferFrom(msg.sender, address(this), _amount);
|
||||
|
||||
emit Pledge(_id, msg.sender, _amount);
|
||||
}
|
||||
|
||||
function unpledge(uint _id, uint _amount) external {
|
||||
Campaign storage campaign = campaigns[_id];
|
||||
require(block.timestamp <= campaign.endAt, "ended");
|
||||
|
||||
campaign.pledged -= _amount;
|
||||
pledgedAmount[_id][msg.sender] -= _amount;
|
||||
token.transfer(msg.sender, _amount);
|
||||
|
||||
emit Unpledge(_id, msg.sender, _amount);
|
||||
}
|
||||
|
||||
function claim(uint _id) external {
|
||||
Campaign storage campaign = campaigns[_id];
|
||||
require(campaign.creator == msg.sender, "not creator");
|
||||
require(block.timestamp > campaign.endAt, "not ended");
|
||||
require(campaign.pledged >= campaign.goal, "pledged < goal");
|
||||
require(!campaign.claimed, "claimed");
|
||||
|
||||
campaign.claimed = true;
|
||||
token.transfer(campaign.creator, campaign.pledged);
|
||||
|
||||
emit Claim(_id);
|
||||
}
|
||||
|
||||
function refund(uint _id) external {
|
||||
Campaign memory campaign = campaigns[_id];
|
||||
require(block.timestamp > campaign.endAt, "not ended");
|
||||
require(campaign.pledged < campaign.goal, "pledged >= goal");
|
||||
|
||||
uint bal = pledgedAmount[_id][msg.sender];
|
||||
pledgedAmount[_id][msg.sender] = 0;
|
||||
token.transfer(msg.sender, bal);
|
||||
|
||||
emit Refund(_id, msg.sender, bal);
|
||||
}
|
||||
}
|
63
advanced_knowledge/applications_contracts/dutch_auction.sol
Normal file
63
advanced_knowledge/applications_contracts/dutch_auction.sol
Normal file
|
@ -0,0 +1,63 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.17;
|
||||
|
||||
/*
|
||||
Dutch auction for NFT.
|
||||
|
||||
Auction
|
||||
Seller of NFT deploys this contract setting a starting price for the NFT.
|
||||
Auction lasts for 7 days.
|
||||
Price of NFT decreases over time.
|
||||
Participants can buy by depositing ETH greater than the current price computed by the smart contract.
|
||||
Auction ends when a buyer buys the NFT.
|
||||
*/
|
||||
|
||||
interface IERC721 {
|
||||
function transferFrom(address _from, address _to, uint _nftId) external;
|
||||
}
|
||||
|
||||
contract DutchAuction {
|
||||
uint private constant DURATION = 7 days;
|
||||
|
||||
IERC721 public immutable nft;
|
||||
uint public immutable nftId;
|
||||
|
||||
address payable public immutable seller;
|
||||
uint public immutable startingPrice;
|
||||
uint public immutable startAt;
|
||||
uint public immutable expiresAt;
|
||||
uint public immutable discountRate;
|
||||
|
||||
constructor(uint _startingPrice, uint _discountRate, address _nft, uint _nftId) {
|
||||
seller = payable(msg.sender);
|
||||
startingPrice = _startingPrice;
|
||||
startAt = block.timestamp;
|
||||
expiresAt = block.timestamp + DURATION;
|
||||
discountRate = _discountRate;
|
||||
|
||||
require(_startingPrice >= _discountRate * DURATION, "starting price < min");
|
||||
|
||||
nft = IERC721(_nft);
|
||||
nftId = _nftId;
|
||||
}
|
||||
|
||||
function getPrice() public view returns (uint) {
|
||||
uint timeElapsed = block.timestamp - startAt;
|
||||
uint discount = discountRate * timeElapsed;
|
||||
return startingPrice - discount;
|
||||
}
|
||||
|
||||
function buy() external payable {
|
||||
require(block.timestamp < expiresAt, "auction expired");
|
||||
|
||||
uint price = getPrice();
|
||||
require(msg.value >= price, "ETH < price");
|
||||
|
||||
nft.transferFrom(seller, msg.sender, nftId);
|
||||
uint refund = msg.value - price;
|
||||
if (refund > 0) {
|
||||
payable(msg.sender).transfer(refund);
|
||||
}
|
||||
selfdestruct(seller);
|
||||
}
|
||||
}
|
101
advanced_knowledge/applications_contracts/english_auction.sol
Normal file
101
advanced_knowledge/applications_contracts/english_auction.sol
Normal file
|
@ -0,0 +1,101 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.17
|
||||
|
||||
/*
|
||||
English auction for NFT.
|
||||
|
||||
Auction
|
||||
Seller of NFT deploys this contract.
|
||||
Auction lasts for 7 days.
|
||||
Participants can bid by depositing ETH greater than the current highest bidder.
|
||||
All bidders can withdraw their bid if it is not the current highest bid.
|
||||
After the auction
|
||||
Highest bidder becomes the new owner of NFT.
|
||||
The seller receives the highest bid of ETH.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
interface IERC721 {
|
||||
function safeTransferFrom(address from, address to, uint tokenId) external;
|
||||
|
||||
function transferFrom(address, address, uint) external;
|
||||
}
|
||||
|
||||
contract EnglishAuction {
|
||||
event Start();
|
||||
event Bid(address indexed sender, uint amount);
|
||||
event Withdraw(address indexed bidder, uint amount);
|
||||
event End(address winner, uint amount);
|
||||
|
||||
IERC721 public nft;
|
||||
uint public nftId;
|
||||
|
||||
address payable public seller;
|
||||
uint public endAt;
|
||||
bool public started;
|
||||
bool public ended;
|
||||
|
||||
address public highestBidder;
|
||||
uint public highestBid;
|
||||
mapping(address => uint) public bids;
|
||||
|
||||
constructor(address _nft, uint _nftId, uint _startingBid) {
|
||||
nft = IERC721(_nft);
|
||||
nftId = _nftId;
|
||||
|
||||
seller = payable(msg.sender);
|
||||
highestBid = _startingBid;
|
||||
}
|
||||
|
||||
function start() external {
|
||||
require(!started, "started");
|
||||
require(msg.sender == seller, "not seller");
|
||||
|
||||
nft.transferFrom(msg.sender, address(this), nftId);
|
||||
started = true;
|
||||
endAt = block.timestamp + 7 days;
|
||||
|
||||
emit Start();
|
||||
}
|
||||
|
||||
function bid() external payable {
|
||||
require(started, "not started");
|
||||
require(block.timestamp < endAt, "ended");
|
||||
require(msg.value > highestBid, "value < highest");
|
||||
|
||||
if (highestBidder != address(0)) {
|
||||
bids[highestBidder] += highestBid;
|
||||
}
|
||||
|
||||
highestBidder = msg.sender;
|
||||
highestBid = msg.value;
|
||||
|
||||
emit Bid(msg.sender, msg.value);
|
||||
}
|
||||
|
||||
function withdraw() external {
|
||||
uint bal = bids[msg.sender];
|
||||
bids[msg.sender] = 0;
|
||||
payable(msg.sender).transfer(bal);
|
||||
|
||||
emit Withdraw(msg.sender, bal);
|
||||
}
|
||||
|
||||
function end() external {
|
||||
require(started, "not started");
|
||||
require(block.timestamp >= endAt, "not ended");
|
||||
require(!ended, "ended");
|
||||
|
||||
ended = true;
|
||||
if (highestBidder != address(0)) {
|
||||
nft.safeTransferFrom(address(this), highestBidder, nftId);
|
||||
seller.transfer(highestBid);
|
||||
} else {
|
||||
nft.safeTransferFrom(address(this), seller, nftId);
|
||||
}
|
||||
|
||||
emit End(highestBidder, highestBid);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.17;
|
||||
|
||||
// An example of calling multiple functions with a single transaction, using delegatecall.
|
||||
|
||||
contract MultiDelegatecall {
|
||||
error DelegatecallFailed();
|
||||
|
||||
function multiDelegatecall(
|
||||
bytes[] memory data
|
||||
) external payable returns (bytes[] memory results) {
|
||||
results = new bytes[](data.length);
|
||||
|
||||
for (uint i; i < data.length; i++) {
|
||||
(bool ok, bytes memory res) = address(this).delegatecall(data[i]);
|
||||
if (!ok) {
|
||||
revert DelegatecallFailed();
|
||||
}
|
||||
results[i] = res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Why use multi delegatecall? Why not multi call?
|
||||
// alice -> multi call --- call ---> test (msg.sender = multi call)
|
||||
// alice -> test --- delegatecall ---> test (msg.sender = alice)
|
||||
contract TestMultiDelegatecall is MultiDelegatecall {
|
||||
event Log(address caller, string func, uint i);
|
||||
|
||||
function func1(uint x, uint y) external {
|
||||
// msg.sender = alice
|
||||
emit Log(msg.sender, "func1", x + y);
|
||||
}
|
||||
|
||||
function func2() external returns (uint) {
|
||||
// msg.sender = alice
|
||||
emit Log(msg.sender, "func2", 2);
|
||||
return 111;
|
||||
}
|
||||
|
||||
mapping(address => uint) public balanceOf;
|
||||
|
||||
// WARNING: unsafe code when used in combination with multi-delegatecall
|
||||
// user can mint multiple times for the price of msg.value
|
||||
function mint() external payable {
|
||||
balanceOf[msg.sender] += msg.value;
|
||||
}
|
||||
}
|
||||
|
||||
contract Helper {
|
||||
function getFunc1Data(uint x, uint y) external pure returns (bytes memory) {
|
||||
return abi.encodeWithSelector(TestMultiDelegatecall.func1.selector, x, y);
|
||||
}
|
||||
|
||||
function getFunc2Data() external pure returns (bytes memory) {
|
||||
return abi.encodeWithSelector(TestMultiDelegatecall.func2.selector);
|
||||
}
|
||||
|
||||
function getMintData() external pure returns (bytes memory) {
|
||||
return abi.encodeWithSelector(TestMultiDelegatecall.mint.selector);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue