-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathOILToken.sol
More file actions
121 lines (96 loc) · 4.24 KB
/
OILToken.sol
File metadata and controls
121 lines (96 loc) · 4.24 KB
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// File: OILToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/// @title OILToken
/// @notice Bonding-curve commodity token for Oil, with dev fee and adjustable tariff.
contract OILToken is ERC20, Ownable {
using SafeERC20 for IERC20;
IERC20 public usdc; // USDC token contract, set post-deploy
uint256 public reserve; // USDC reserve in curve
uint256 public k; // constant = reserve * totalSupply
uint256 public constant feeDevBP = 100; // 1% developer fee (in basis points)
uint256 public taxBP; // tariff (0-2000 bp)
address public devWallet; // developer fee recipient
address[] public vaults; // registered staking vaults
mapping(address => bool) public isStakingVault;
event Bought(address indexed user, uint256 usdcIn, uint256 tokensOut);
event Sold(address indexed user, uint256 tokensIn, uint256 usdcOut);
event TaxDistributed(uint256 amount);
/// @param initialSupply total token supply minted at genesis
/// @param _devWallet address receiving the 1% dev fee
constructor(
uint256 initialSupply,
address _devWallet
) ERC20("Oil", "OIL") {
require(initialSupply > 0, "Supply>0");
devWallet = _devWallet;
_mint(address(this), initialSupply);
reserve = 0;
k = 0;
}
/// @notice Set the USDC token contract address (after deployment).
function setUSDC(address _usdc) external onlyOwner {
require(address(usdc) == address(0), "USDC already set");
usdc = IERC20(_usdc);
}
/// @notice Seed curve reserve with USDC and initialize k. Call once: amount = 10000e6 for $10k.
function depositReserve(uint256 amount) external onlyOwner {
require(reserve == 0, "Already seeded");
require(address(usdc) != address(0), "Set USDC first");
usdc.safeTransferFrom(msg.sender, address(this), amount);
reserve = amount;
k = reserve * totalSupply();
}
function buy(uint256 usdcAmount) external {
require(usdcAmount > 0, "Zero amount");
uint256 feeDev = (usdcAmount * feeDevBP) / 10000;
uint256 tax = (usdcAmount * taxBP) / 10000;
uint256 net = usdcAmount - feeDev - tax;
usdc.safeTransferFrom(msg.sender, devWallet, feeDev);
usdc.safeTransferFrom(msg.sender, address(this), net + tax);
uint256 newReserve = reserve + net;
uint256 newSupply = k / newReserve;
uint256 tokensOut = totalSupply() - newSupply;
_transfer(address(this), msg.sender, tokensOut);
reserve = newReserve;
k = reserve * totalSupply();
_distributeTax(tax);
emit Bought(msg.sender, usdcAmount, tokensOut);
}
function sell(uint256 tokenAmount) external {
require(tokenAmount > 0, "Zero amount");
uint256 newSupply = totalSupply() + tokenAmount;
uint256 newReserve = k / newSupply;
uint256 usdcGross = reserve - newReserve;
uint256 feeDev = (usdcGross * feeDevBP) / 10000;
uint256 tax = (usdcGross * taxBP) / 10000;
uint256 net = usdcGross - feeDev - tax;
_transfer(msg.sender, address(this), tokenAmount);
usdc.safeTransfer(devWallet, feeDev);
usdc.safeTransfer(msg.sender, net);
reserve = newReserve;
k = reserve * totalSupply();
_distributeTax(tax);
emit Sold(msg.sender, tokenAmount, net);
}
function _distributeTax(uint256 amount) internal {
if (amount == 0 || vaults.length == 0) return;
uint256 share = amount / vaults.length;
for (uint i = 0; i < vaults.length; i++) {
usdc.safeTransfer(vaults[i], share);
}
emit TaxDistributed(amount);
}
function setTaxBP(uint256 newTaxBP) external onlyOwner {
require(newTaxBP <= 2000, "Max 20%");
taxBP = newTaxBP;
}
function registerVault(address vault) external onlyOwner {
require(!isStakingVault[vault], "Already added");
isStakingVault[vault] = true;
vaults.push(vault);
}
}