-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcontract.sol
58 lines (50 loc) · 2.93 KB
/
contract.sol
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
pragma solidity ^0.8.0;
import "https://github.com/open-contracts/ethereum-protocol/blob/main/solidity_contracts/OpenContractRopsten.sol";
contract FiatSwap is OpenContract {
mapping(bytes32 => address) seller;
mapping(bytes32 => address) buyer;
mapping(bytes32 => uint256) amount;
mapping(bytes32 => uint256) lockedUntil;
constructor() {
setOracleHash(this.buyTokens.selector, 0x0722f93ac3d07ca2e62485121cf90e22110aa9990da37eaa813e069a4942894d);
}
// every offer has a unique offerID which can be computed from the off-chain transaction details.
function offerID(string memory sellerHandle, uint256 priceInCent, string memory transactionMessage,
string memory paymentService, string memory buyerSellerSecret) public pure returns(bytes32) {
return keccak256(abi.encode(sellerHandle, priceInCent, transactionMessage, paymentService, buyerSellerSecret));
}
// sellers should lock their offers, to give the buyer time to make and verify their online payment.
function secondsLocked(bytes32 offerID) public view returns(int256) {
return int256(lockedUntil[offerID]) - int256(block.timestamp);
}
// every offer has a unique offerID which can be computed with this function.
function amountOffered(bytes32 offerID) public view returns(uint256) {
require(msg.sender == buyer[offerID], "No ether offered for you at this offerID.");
require(secondsLocked(offerID) > 1200, "Offer isn't locked for at least 20min. Ask the seller for more time.");
return amount[offerID];
}
// to make an offer, the seller specifies the offerID, the buyer, and the time they give the buyer
function offerTokens(bytes32 offerID, address buyerAddress, uint256 lockForSeconds) public payable {
require(secondsLocked(offerID) <= 0, "Can't override offer during the locking period.");
amount[offerID] = msg.value;
buyer[offerID] = buyerAddress;
lockedUntil[offerID] = block.timestamp + lockForSeconds;
seller[offerID] = msg.sender;
}
// to accept a given offerID and buy tokens, buyers have to verify their payment
// using the oracle whose oracleID was specified in the constructor at the top
function buyTokens(address payable user, bytes32 offerID) public requiresOracle returns(bool) {
require(buyer[offerID] == user, "The offer was made to a different buyer.");
uint256 payment = amount[offerID];
amount[offerID] = 0;
return user.send(payment);
}
// sellers can retract their offers once the time lock lapsed.
function retractOffer(bytes32 offerID) public returns(bool) {
require(seller[offerID] == msg.sender, "Only seller can retract offer.");
require(secondsLocked(offerID) <= 0, "Can't retract offer during the locking period.");
uint256 payment = amount[offerID];
amount[offerID] = 0;
return payable(msg.sender).send(payment);
}
}