编译器
0.8.18+commit.87f61d96
文件 1 的 19:AggregatorV3Interface.sol
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
文件 2 的 19:BankXToken.sol
pragma solidity ^0.8.0;
import "../ERC20/ERC20Custom.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../XSD/XSDStablecoin.sol";
contract BankXToken is ERC20Custom {
string public symbol;
string public name;
uint8 public constant decimals = 18;
uint256 public genesis_supply;
address public pool_address;
address public treasury;
address public router;
XSDStablecoin private XSD;
address public smartcontract_owner;
modifier onlyPools() {
require(XSD.xsd_pools(msg.sender) == true, "Only xsd pools can mint new BankX");
_;
}
modifier onlyByOwner() {
require(msg.sender == smartcontract_owner, "You are not an owner");
_;
}
constructor(
string memory _name,
string memory _symbol,
uint256 _pool_amount,
uint256 _genesis_supply,
address _treasury,
address _smartcontract_owner
) {
require((_treasury != address(0)), "Zero address detected");
name = _name;
symbol = _symbol;
genesis_supply = _genesis_supply + _pool_amount;
treasury = _treasury;
_mint(_msgSender(), _pool_amount);
_mint(treasury, _genesis_supply);
smartcontract_owner = _smartcontract_owner;
}
function setPool(address new_pool) external onlyByOwner {
require(new_pool != address(0), "Zero address detected");
pool_address = new_pool;
}
function setTreasury(address new_treasury) external onlyByOwner {
require(new_treasury != address(0), "Treasury address cannot be 0");
treasury = new_treasury;
}
function setRouterAddress(address _router) external onlyByOwner {
require(_router != address(0), "Zero address detected");
router = _router;
}
function setXSDAddress(address xsd_contract_address) external onlyByOwner {
require(xsd_contract_address != address(0), "Zero address detected");
XSD = XSDStablecoin(xsd_contract_address);
emit XSDAddressSet(xsd_contract_address);
}
function mint(address to, uint256 amount) public onlyPools {
_mint(to, amount);
emit BankXMinted(address(this), to, amount);
}
function genesisSupply() public view returns(uint256){
return genesis_supply;
}
function pool_mint(address m_address, uint256 m_amount) external onlyPools {
super._mint(m_address, m_amount);
emit BankXMinted(address(this), m_address, m_amount);
}
function pool_burn_from(address b_address, uint256 b_amount) external onlyPools {
super._burnFrom(b_address, b_amount);
emit BankXBurned(b_address, address(this), b_amount);
}
function burnpoolBankX(uint _bankx_amount) public {
require(msg.sender == router, "Only Router can access this function");
require(totalSupply()>genesis_supply,"BankX must be deflationary");
super._burn(pool_address, _bankx_amount);
IBankXWETHpool(pool_address).sync();
emit BankXBurned(msg.sender, address(this), _bankx_amount);
}
function setSmartContractOwner(address _smartcontract_owner) external{
require(msg.sender == smartcontract_owner, "Only the smart contract owner can access this function");
require(msg.sender != address(0), "Zero address detected");
smartcontract_owner = _smartcontract_owner;
}
function renounceOwnership() external{
require(msg.sender == smartcontract_owner, "Only the smart contract owner can access this function");
smartcontract_owner = address(0);
}
event BankXBurned(address indexed from, address indexed to, uint256 amount);
event BankXMinted(address indexed from, address indexed to, uint256 amount);
event XSDAddressSet(address addr);
}
文件 3 的 19:ChainlinkETHUSDPriceConsumer.sol
pragma solidity ^0.8.0;
import "./AggregatorV3Interface.sol";
contract ChainlinkETHUSDPriceConsumer {
AggregatorV3Interface internal priceFeed;
constructor() {
priceFeed = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419);
}
function getLatestPrice() public view returns (int) {
(
,
int price,
,
,
) = priceFeed.latestRoundData();
return price;
}
function getDecimals() public view returns (uint8) {
return priceFeed.decimals();
}
}
文件 4 的 19:ChainlinkXAGUSDPriceConsumer.sol
pragma solidity ^0.8.0;
import "./AggregatorV3Interface.sol";
contract ChainlinkXAGUSDPriceConsumer {
AggregatorV3Interface internal priceFeed;
constructor() {
priceFeed = AggregatorV3Interface(0x379589227b15F1a12195D3f2d90bBc9F31f95235);
}
function getLatestPrice() public view returns (int) {
(
,
int price,
,
,
) = priceFeed.latestRoundData();
return price;
}
function getDecimals() public view returns (uint8) {
return priceFeed.decimals();
}
}
文件 5 的 19:CollateralPool.sol
pragma solidity ^0.8.0;
import '@uniswap/lib/contracts/libraries/TransferHelper.sol';
import '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import "../../BankX/BankXToken.sol";
import "../XSDStablecoin.sol";
import "./Interfaces/IBankXWETHpool.sol";
import "./Interfaces/IXSDWETHpool.sol";
import '../../Oracle/Interfaces/IPIDController.sol';
import "../../ERC20/IWETH.sol";
import "./CollateralPoolLibrary.sol";
contract CollateralPool is ReentrancyGuard {
address public WETH;
address public smartcontract_owner;
address public xsd_contract_address;
address public bankx_contract_address;
address public xsdweth_pool;
address public bankxweth_pool;
address public pid_address;
BankXToken private BankX;
XSDStablecoin private XSD;
IPIDController private pid_controller;
uint256 public collat_XSD;
bool public mint_paused;
bool public redeem_paused;
bool public buyback_paused;
struct MintInfo {
uint256 accum_interest;
uint256 interest_rate;
uint256 time;
uint256 amount;
}
mapping(address=>MintInfo) public mintMapping;
mapping (address => uint256) public redeemBankXBalances;
mapping (address => uint256) public redeemCollateralBalances;
mapping (address => uint256) public vestingtimestamp;
uint256 public unclaimedPoolCollateral;
uint256 public unclaimedPoolBankX;
uint256 public collateral_equivalent_d18;
uint256 public bankx_minted_count;
mapping (address => uint256) public lastRedeemed;
uint256 public redemption_delay = 2;
modifier onlyByOwner() {
require(msg.sender == smartcontract_owner, "Not owner");
_;
}
constructor(
address _xsd_contract_address,
address _bankx_contract_address,
address _bankxweth_pool,
address _xsdweth_pool,
address _WETH,
address _smartcontract_owner
) {
require(
(_xsd_contract_address != address(0))
&& (_bankx_contract_address != address(0))
&& (_WETH != address(0))
&& (_bankxweth_pool != address(0))
&& (_xsdweth_pool != address(0))
, "Zero address detected");
XSD = XSDStablecoin(_xsd_contract_address);
BankX = BankXToken(_bankx_contract_address);
xsd_contract_address = _xsd_contract_address;
bankx_contract_address = _bankx_contract_address;
xsdweth_pool = _xsdweth_pool;
bankxweth_pool = _bankxweth_pool;
WETH = _WETH;
smartcontract_owner = _smartcontract_owner;
}
receive() external payable {
assert(msg.sender == WETH);
}
function collatDollarBalance() public view returns (uint256) {
return ((IWETH(WETH).balanceOf(address(this))*XSD.eth_usd_price())/(1e6));
}
function availableExcessCollatDV() public view returns (uint256) {
uint256 global_collateral_ratio = XSD.global_collateral_ratio();
uint256 global_collat_value = XSD.globalCollateralValue();
if (global_collateral_ratio > (1e6)) global_collateral_ratio = (1e6);
uint256 required_collat_dollar_value_d18 = ((collat_XSD)*global_collateral_ratio*(XSD.xag_usd_price()*(1e4))/(311035))/(1e12);
if ((global_collat_value-unclaimedPoolCollateral)>required_collat_dollar_value_d18) return (global_collat_value-unclaimedPoolCollateral-required_collat_dollar_value_d18);
else return 0;
}
function mintInterestCalc(uint xsd_amount,address sender) internal {
(mintMapping[sender].accum_interest, mintMapping[sender].interest_rate, mintMapping[sender].time, mintMapping[sender].amount) = CollateralPoolLibrary.calcMintInterest(xsd_amount,XSD.xag_usd_price(), XSD.interest_rate(), mintMapping[sender].accum_interest, mintMapping[sender].interest_rate, mintMapping[sender].time, mintMapping[sender].amount);
}
function redeemInterestCalc(uint xsd_amount,address sender) internal {
(mintMapping[sender].accum_interest, mintMapping[sender].interest_rate, mintMapping[sender].time, mintMapping[sender].amount)=CollateralPoolLibrary.calcRedemptionInterest(xsd_amount,XSD.xag_usd_price(), mintMapping[sender].accum_interest, mintMapping[sender].interest_rate, mintMapping[sender].time, mintMapping[sender].amount);
}
function mint1t1XSD(uint256 XSD_out_min) external payable nonReentrant {
require(!mint_paused, "Mint Paused");
require(msg.value>0, "Invalid collateral amount");
require(XSD.global_collateral_ratio() >= (1e6), "Collateral ratio must be >= 1");
(uint256 xsd_amount_d18) = CollateralPoolLibrary.calcMint1t1XSD(
XSD.eth_usd_price(),
XSD.xag_usd_price(),
msg.value
);
require(XSD_out_min <= xsd_amount_d18, "Slippage limit reached");
mintInterestCalc(xsd_amount_d18,msg.sender);
IWETH(WETH).deposit{value: msg.value}();
assert(IWETH(WETH).transfer(address(this), msg.value));
collat_XSD = collat_XSD + xsd_amount_d18;
XSD.pool_mint(msg.sender, xsd_amount_d18);
}
function mintAlgorithmicXSD(uint256 bankx_amount_d18, uint256 XSD_out_min) external nonReentrant {
require(!mint_paused, "Mint Paused");
uint256 bankx_price = XSD.bankx_price();
uint256 xag_usd_price = XSD.xag_usd_price();
(uint256 xsd_amount_d18) = CollateralPoolLibrary.calcMintAlgorithmicXSD(
bankx_price,
xag_usd_price,
bankx_amount_d18
);
require(XSD_out_min <= xsd_amount_d18, "Slippage limit reached");
mintInterestCalc(xsd_amount_d18,msg.sender);
collat_XSD = collat_XSD + xsd_amount_d18;
bankx_minted_count = bankx_minted_count + bankx_amount_d18;
BankX.pool_burn_from(msg.sender, bankx_amount_d18);
XSD.pool_mint(msg.sender, xsd_amount_d18);
}
function mintFractionalXSD(uint256 bankx_amount, uint256 XSD_out_min) external payable nonReentrant {
require(!mint_paused, "Mint Paused");
uint256 xag_usd_price = XSD.xag_usd_price();
uint256 global_collateral_ratio = XSD.global_collateral_ratio();
require(global_collateral_ratio < (1e6) && global_collateral_ratio > 0, "Collateral ratio needs to be between .000001 and .999999");
CollateralPoolLibrary.MintFF_Params memory input_params = CollateralPoolLibrary.MintFF_Params(
XSD.bankx_price(),
XSD.eth_usd_price(),
bankx_amount,
msg.value,
global_collateral_ratio
);
(uint256 mint_amount, uint256 bankx_needed) = CollateralPoolLibrary.calcMintFractionalXSD(input_params);
mint_amount = (mint_amount*31103477)/((xag_usd_price));
require(XSD_out_min <= mint_amount, "Slippage limit reached");
require(bankx_needed <= bankx_amount, "Not enough BankX inputted");
mintInterestCalc(mint_amount,msg.sender);
bankx_minted_count = bankx_minted_count + bankx_needed;
BankX.pool_burn_from(msg.sender, bankx_needed);
IWETH(WETH).deposit{value: msg.value}();
assert(IWETH(WETH).transfer(address(this), msg.value));
collat_XSD = collat_XSD + mint_amount;
XSD.pool_mint(msg.sender, mint_amount);
}
function redeem1t1XSD(uint256 XSD_amount, uint256 COLLATERAL_out_min) external nonReentrant {
require(!pid_controller.bucket3(), "Cannot withdraw in times of deficit");
require(!redeem_paused, "Redeem Paused");
require(XSD.global_collateral_ratio() == (1e6), "Collateral ratio must be == 1");
require(XSD_amount<=mintMapping[msg.sender].amount, "OVERREDEMPTION ERROR");
(uint256 XSD_dollar,uint256 collateral_needed) = CollateralPoolLibrary.calcRedeem1t1XSD(
XSD.eth_usd_price(),
XSD.xag_usd_price(),
XSD_amount
);
uint total_xsd_amount = mintMapping[msg.sender].amount;
require(collateral_needed <= (IWETH(WETH).balanceOf(address(this))-unclaimedPoolCollateral), "Not enough collateral in pool");
require(COLLATERAL_out_min <= collateral_needed, "Slippage limit reached");
redeemInterestCalc(XSD_amount, msg.sender);
uint current_accum_interest = (XSD_amount*mintMapping[msg.sender].accum_interest)/total_xsd_amount;
redeemBankXBalances[msg.sender] = (redeemBankXBalances[msg.sender]+current_accum_interest);
redeemCollateralBalances[msg.sender] = redeemCollateralBalances[msg.sender]+XSD_dollar;
unclaimedPoolCollateral = unclaimedPoolCollateral+XSD_dollar;
lastRedeemed[msg.sender] = block.number;
unclaimedPoolBankX = (unclaimedPoolBankX+current_accum_interest);
uint256 bankx_amount = (current_accum_interest*1e6)/XSD.bankx_price();
collat_XSD -= XSD_amount;
mintMapping[msg.sender].accum_interest = (mintMapping[msg.sender].accum_interest - current_accum_interest);
XSD.pool_burn_from(msg.sender, XSD_amount);
BankX.pool_mint(address(this), bankx_amount);
}
function redeemFractionalXSD(uint256 XSD_amount, uint256 BankX_out_min, uint256 COLLATERAL_out_min) external nonReentrant {
require(!pid_controller.bucket3(), "Cannot withdraw in times of deficit");
require(!redeem_paused, "Redeem Paused");
require(XSD_amount<=mintMapping[msg.sender].amount, "OVERREDEMPTION ERROR");
uint256 xag_usd_price = XSD.xag_usd_price();
uint256 global_collateral_ratio = XSD.global_collateral_ratio();
require(global_collateral_ratio < (1e6) && global_collateral_ratio > 0, "Collateral ratio needs to be between .000001 and .999999");
uint256 bankx_dollar_value_d18 = XSD_amount - ((XSD_amount*global_collateral_ratio)/(1e6));
bankx_dollar_value_d18 = (bankx_dollar_value_d18*xag_usd_price)/(31103477);
uint256 bankx_amount = (bankx_dollar_value_d18*1e6)/XSD.bankx_price();
uint256 collateral_dollar_value = (XSD_amount*global_collateral_ratio)/(1e6);
collateral_dollar_value = (collateral_dollar_value*xag_usd_price)/31103477;
uint256 collateral_amount = (collateral_dollar_value*1e6)/XSD.eth_usd_price();
require(collateral_amount <= (IWETH(WETH).balanceOf(address(this))-unclaimedPoolCollateral), "Not enough collateral in pool");
require(COLLATERAL_out_min <= collateral_amount, "Slippage limit reached [collateral]");
require(BankX_out_min <= bankx_amount, "Slippage limit reached [BankX]");
redeemCollateralBalances[msg.sender] = redeemCollateralBalances[msg.sender]+collateral_dollar_value;
unclaimedPoolCollateral = unclaimedPoolCollateral+collateral_dollar_value;
lastRedeemed[msg.sender] = block.number;
uint total_xsd_amount = mintMapping[msg.sender].amount;
redeemInterestCalc(XSD_amount, msg.sender);
uint current_accum_interest = (XSD_amount*mintMapping[msg.sender].accum_interest)/total_xsd_amount;
redeemBankXBalances[msg.sender] = redeemBankXBalances[msg.sender]+current_accum_interest;
bankx_amount = bankx_amount + ((current_accum_interest*1e6)/XSD.bankx_price());
mintMapping[msg.sender].accum_interest = mintMapping[msg.sender].accum_interest - current_accum_interest;
redeemBankXBalances[msg.sender] = redeemBankXBalances[msg.sender]+bankx_dollar_value_d18;
unclaimedPoolBankX = unclaimedPoolBankX+bankx_dollar_value_d18+current_accum_interest;
collat_XSD -= XSD_amount;
XSD.pool_burn_from(msg.sender, XSD_amount);
BankX.pool_mint(address(this), bankx_amount);
}
function redeemAlgorithmicXSD(uint256 XSD_amount, uint256 BankX_out_min) external nonReentrant {
require(!pid_controller.bucket3(), "Cannot withdraw in times of deficit");
require(!redeem_paused, "Redeem Paused");
require(XSD_amount<=mintMapping[msg.sender].amount, "OVERREDEMPTION ERROR");
uint256 bankx_price = XSD.bankx_price();
uint256 bankx_dollar_value_d18 = (XSD_amount*XSD.xag_usd_price())/(31103477);
uint256 bankx_amount = (bankx_dollar_value_d18*1e6)/bankx_price;
lastRedeemed[msg.sender] = block.number;
uint total_xsd_amount = mintMapping[msg.sender].amount;
require(BankX_out_min <= bankx_amount, "Slippage limit reached");
redeemInterestCalc(XSD_amount, msg.sender);
uint current_accum_interest = XSD_amount*mintMapping[msg.sender].accum_interest/total_xsd_amount;
redeemBankXBalances[msg.sender] = (redeemBankXBalances[msg.sender]+current_accum_interest);
bankx_amount = bankx_amount + ((current_accum_interest*1e6)/bankx_price);
mintMapping[msg.sender].accum_interest = (mintMapping[msg.sender].accum_interest - current_accum_interest);
redeemBankXBalances[msg.sender] = redeemBankXBalances[msg.sender]+bankx_dollar_value_d18;
unclaimedPoolBankX = unclaimedPoolBankX+bankx_dollar_value_d18+current_accum_interest;
collat_XSD -= XSD_amount;
XSD.pool_burn_from(msg.sender, XSD_amount);
BankX.pool_mint(address(this), bankx_amount);
}
function collectRedemption() external nonReentrant{
require(!pid_controller.bucket3(), "Cannot withdraw in times of deficit");
require(!redeem_paused, "Redeem Paused");
require((lastRedeemed[msg.sender]+(redemption_delay)) <= block.number, "Must wait for redemption_delay blocks before collecting redemption");
uint BankXDollarAmount;
uint CollateralDollarAmount;
uint BankXAmount;
uint CollateralAmount;
if(redeemBankXBalances[msg.sender] > 0){
BankXDollarAmount = redeemBankXBalances[msg.sender];
BankXAmount = (BankXDollarAmount*1e6)/XSD.bankx_price();
redeemBankXBalances[msg.sender] = 0;
unclaimedPoolBankX = unclaimedPoolBankX-BankXDollarAmount;
TransferHelper.safeTransfer(address(BankX), msg.sender, BankXAmount);
}
if(redeemCollateralBalances[msg.sender] > 0){
CollateralDollarAmount = redeemCollateralBalances[msg.sender];
CollateralAmount = (CollateralDollarAmount*1e6)/XSD.eth_usd_price();
redeemCollateralBalances[msg.sender] = 0;
unclaimedPoolCollateral = unclaimedPoolCollateral-CollateralDollarAmount;
IWETH(WETH).withdraw(CollateralAmount);
TransferHelper.safeTransferETH(msg.sender, CollateralAmount);
}
}
function buyBackBankX(uint256 BankX_amount,uint256 COLLATERAL_out_min) external{
require(!buyback_paused, "Buyback Paused");
CollateralPoolLibrary.BuybackBankX_Params memory input_params = CollateralPoolLibrary.BuybackBankX_Params(
availableExcessCollatDV(),
XSD.bankx_price(),
XSD.eth_usd_price(),
BankX_amount
);
(collateral_equivalent_d18) = (CollateralPoolLibrary.calcBuyBackBankX(input_params));
require(COLLATERAL_out_min <= collateral_equivalent_d18, "Slippage limit reached");
BankX.pool_burn_from(msg.sender, BankX_amount);
TransferHelper.safeTransfer(address(WETH), address(this), collateral_equivalent_d18);
IWETH(WETH).withdraw(collateral_equivalent_d18);
TransferHelper.safeTransferETH(msg.sender, collateral_equivalent_d18);
}
function buyBackXSD(uint256 XSD_amount, uint256 collateral_out_min) external {
require(!buyback_paused, "Buyback Paused");
if(XSD_amount != 0) require((XSD.totalSupply()+XSD_amount)>collat_XSD, "uXSD MUST BE POSITIVE");
CollateralPoolLibrary.BuybackXSD_Params memory input_params = CollateralPoolLibrary.BuybackXSD_Params(
availableExcessCollatDV(),
XSD.xsd_price(),
XSD.eth_usd_price(),
XSD_amount
);
(collateral_equivalent_d18) = (CollateralPoolLibrary.calcBuyBackXSD(input_params));
require(collateral_out_min <= collateral_equivalent_d18, "Slippage limit reached");
XSD.pool_burn_from(msg.sender, XSD_amount);
TransferHelper.safeTransfer(address(WETH), address(this), collateral_equivalent_d18);
IWETH(WETH).withdraw(collateral_equivalent_d18);
TransferHelper.safeTransferETH(msg.sender, collateral_equivalent_d18);
}
function setPoolParameters(uint256 new_redemption_delay, bool _mint_paused, bool _redeem_paused, bool _buyback_paused) external onlyByOwner {
redemption_delay = new_redemption_delay;
mint_paused = _mint_paused;
redeem_paused = _redeem_paused;
buyback_paused = _buyback_paused;
emit PoolParametersSet(new_redemption_delay);
}
function setPIDController(address new_pid_address) external onlyByOwner {
pid_controller = IPIDController(new_pid_address);
pid_address = new_pid_address;
}
function setSmartContractOwner(address _smartcontract_owner) external{
require(msg.sender == smartcontract_owner, "Only the smart contract owner can access this function");
require(msg.sender != address(0), "Zero address detected");
smartcontract_owner = _smartcontract_owner;
}
function renounceOwnership() external{
require(msg.sender == smartcontract_owner, "Only the smart contract owner can access this function");
smartcontract_owner = address(0);
}
function resetAddresses(address _xsd_contract_address,
address _bankx_contract_address,
address _bankxweth_pool,
address _xsdweth_pool,
address _WETH) external{
require(msg.sender == smartcontract_owner, "Only the smart contract owner can access this function");
require(
(_xsd_contract_address != address(0))
&& (_bankx_contract_address != address(0))
&& (_WETH != address(0))
&& (_bankxweth_pool != address(0))
&& (_xsdweth_pool != address(0))
, "Zero address detected");
XSD = XSDStablecoin(_xsd_contract_address);
BankX = BankXToken(_bankx_contract_address);
xsd_contract_address = _xsd_contract_address;
bankx_contract_address = _bankx_contract_address;
xsdweth_pool = _xsdweth_pool;
bankxweth_pool = _bankxweth_pool;
WETH = _WETH;
}
event PoolParametersSet(uint256 new_redemption_delay);
}
文件 6 的 19:CollateralPoolLibrary.sol
pragma solidity ^0.8.0;
library CollateralPoolLibrary {
struct MintFF_Params {
uint256 bankx_price_usd;
uint256 col_price_usd;
uint256 bankx_amount;
uint256 collateral_amount;
uint256 col_ratio;
}
struct BuybackBankX_Params {
uint256 excess_collateral_dollar_value_d18;
uint256 bankx_price_usd;
uint256 col_price_usd;
uint256 BankX_amount;
}
struct BuybackXSD_Params {
uint256 excess_collateral_dollar_value_d18;
uint256 xsd_price_usd;
uint256 col_price_usd;
uint256 XSD_amount;
}
function calcMint1t1XSD(uint256 col_price, uint256 silver_price, uint256 collateral_amount_d18) public pure returns (uint256) {
uint256 gram_price = (silver_price*(1e4))/(311035);
return (collateral_amount_d18*(col_price))/(gram_price);
}
function calcMintAlgorithmicXSD(uint256 bankx_price_usd, uint256 silver_price, uint256 bankx_amount_d18) public pure returns (uint256) {
uint256 gram_price = (silver_price*(1e4))/(311035);
return (bankx_amount_d18*bankx_price_usd)/(gram_price);
}
function calcMintInterest(uint256 XSD_amount,uint256 silver_price,uint256 rate, uint256 accum_interest, uint256 interest_rate, uint256 time, uint256 amount) internal view returns(uint256, uint256, uint256, uint256) {
uint256 gram_price = (silver_price*(1e4))/(311035);
if(time == 0){
interest_rate = rate;
amount = XSD_amount;
time = block.timestamp;
}
else{
uint delta_t = block.timestamp - time;
delta_t = delta_t/(86400);
accum_interest = accum_interest+((amount*gram_price*interest_rate*delta_t)/(365*(1e12)));
interest_rate = (amount*interest_rate) + (XSD_amount*rate);
amount = amount+XSD_amount;
interest_rate = interest_rate/amount;
time = block.timestamp;
}
return (
accum_interest,
interest_rate,
time,
amount
);
}
function calcRedemptionInterest(uint256 XSD_amount,uint256 silver_price, uint256 accum_interest, uint256 interest_rate, uint256 time, uint256 amount) internal view returns(uint256, uint256, uint256, uint256){
uint256 gram_price = (silver_price*(1e4))/(311035);
uint delta_t = block.timestamp - time;
delta_t = delta_t/(86400);
accum_interest = accum_interest+((amount*gram_price*interest_rate*delta_t)/(365*(1e12)));
amount = amount - XSD_amount;
time = block.timestamp;
return (
accum_interest,
interest_rate,
time,
amount
);
}
function calcMintFractionalXSD(MintFF_Params memory params) internal pure returns (uint256, uint256) {
uint256 bankx_dollar_value_d18;
uint256 c_dollar_value_d18;
{
bankx_dollar_value_d18 = params.bankx_amount*(params.bankx_price_usd)/(1e6);
c_dollar_value_d18 = params.collateral_amount*(params.col_price_usd)/(1e6);
}
uint calculated_bankx_dollar_value_d18 =
(c_dollar_value_d18*(1e6)/(params.col_ratio))
-(c_dollar_value_d18);
uint calculated_bankx_needed = calculated_bankx_dollar_value_d18*(1e6)/(params.bankx_price_usd);
return (
(c_dollar_value_d18+calculated_bankx_dollar_value_d18),
calculated_bankx_needed
);
}
function calcRedeem1t1XSD(uint256 col_price_usd,uint256 silver_price, uint256 XSD_amount) public pure returns (uint256,uint256) {
uint256 gram_price = (silver_price*(1e4))/(311035);
return ((XSD_amount*gram_price/1e6),((XSD_amount*gram_price)/col_price_usd));
}
function calcBuyBackBankX(BuybackBankX_Params memory params) internal pure returns (uint256) {
require(params.excess_collateral_dollar_value_d18 > 0, "No excess collateral to buy back!");
uint256 bankx_dollar_value_d18 = (params.BankX_amount*params.bankx_price_usd);
require((bankx_dollar_value_d18/1e6) <= params.excess_collateral_dollar_value_d18, "You are trying to buy back more than the excess!");
uint256 collateral_equivalent_d18 = (bankx_dollar_value_d18)/(params.col_price_usd);
return (
collateral_equivalent_d18
);
}
function calcBuyBackXSD(BuybackXSD_Params memory params) internal pure returns (uint256) {
require(params.excess_collateral_dollar_value_d18 > 0, "No excess collateral to buy back!");
uint256 xsd_dollar_value_d18 = params.XSD_amount*(params.xsd_price_usd);
require((xsd_dollar_value_d18/1e6) <= params.excess_collateral_dollar_value_d18, "You are trying to buy more than the excess!");
uint256 collateral_equivalent_d18 = (xsd_dollar_value_d18)/(params.col_price_usd);
return (
collateral_equivalent_d18
);
}
}
文件 7 的 19:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 8 的 19:ERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 9 的 19:ERC20Custom.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract ERC20Custom is Context, IERC20 {
using SafeMath for uint256;
mapping (address => uint256) internal _balances;
mapping (address => mapping (address => uint256)) internal _allowances;
uint256 private _totalSupply;
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
function burnFrom(address account, uint256 amount) public virtual {
uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");
_approve(account, _msgSender(), decreasedAllowance);
_burn(account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _burnFrom(address account, uint256 amount) internal virtual {
_burn(account, amount);
_approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 10 的 19:IBankXWETHpool.sol
pragma solidity ^0.8.0;
interface IBankXWETHpool {
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function collatDollarBalance() external returns(uint);
function swap(uint amount0Out, uint amount1Out, address to) external;
function skim(address to) external;
function sync() external;
}
文件 11 的 19:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 12 的 19:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 13 的 19:IPIDController.sol
pragma solidity ^0.8.0;
interface IPIDController{
function bucket1() external view returns (bool);
function bucket2() external view returns (bool);
function bucket3() external view returns (bool);
function diff1() external view returns (uint);
function diff2() external view returns (uint);
function diff3() external view returns (uint);
function amountpaid1() external view returns (uint);
function amountpaid2() external view returns (uint);
function amountpaid3() external view returns (uint);
function bankx_arbi_limit() external view returns (uint);
function xsd_arbi_limit() external view returns (uint);
function bankx_burnable_limit() external view returns (uint);
function xsd_burnable_limit() external view returns (uint);
function amountPaidBankXWETH(uint ethvalue) external;
function amountPaidXSDWETH(uint ethvalue) external;
function amountPaidCollateralPool(uint ethvalue) external;
}
文件 14 的 19:IWETH.sol
pragma solidity ^0.8.0;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function transferFrom(address src, address dst, uint wad) external returns (bool);
function balanceOf(address account) external view returns (uint256);
function withdraw(uint) external;
}
文件 15 的 19:IXSDWETHpool.sol
pragma solidity ^0.8.0;
interface IXSDWETHpool {
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function collatDollarBalance() external returns (uint);
function swap(uint amount0Out, uint amount1Out, address to) external;
function skim(address to) external;
function sync() external;
}
文件 16 的 19:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 17 的 19:SafeMath.sol
pragma solidity ^0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
文件 18 的 19:TransferHelper.sol
pragma solidity >=0.6.0;
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeApprove: approve failed'
);
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeTransfer: transfer failed'
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::transferFrom: transferFrom failed'
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
}
文件 19 的 19:XSDStablecoin.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../ERC20/ERC20Custom.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../BankX/BankXToken.sol";
import "./Pools/CollateralPool.sol";
import "./Pools/Interfaces/IBankXWETHpool.sol";
import "./Pools/Interfaces/IXSDWETHpool.sol";
import "../Oracle/ChainlinkETHUSDPriceConsumer.sol";
import "../Oracle/ChainlinkXAGUSDPriceConsumer.sol";
contract XSDStablecoin is ERC20Custom {
enum PriceChoice { XSD, BankX }
ChainlinkETHUSDPriceConsumer private eth_usd_pricer;
ChainlinkXAGUSDPriceConsumer private xag_usd_pricer;
uint8 private eth_usd_pricer_decimals;
uint8 private xag_usd_pricer_decimals;
string public symbol;
string public name;
uint8 public constant decimals = 18;
address public pid_address;
address public treasury;
address public collateral_pool_address;
address public router;
address public eth_usd_oracle_address;
address public xag_usd_oracle_address;
address public smartcontract_owner;
uint256 public interest_rate;
IBankXWETHpool private bankxEthPool;
IXSDWETHpool private xsdEthPool;
uint256 public cap_rate;
uint256 public genesis_supply;
address[] public xsd_pools_array;
mapping(address => bool) public xsd_pools;
uint256 private constant PRICE_PRECISION = 1e6;
uint256 public global_collateral_ratio;
uint256 public xsd_step;
uint256 public refresh_cooldown;
uint256 public price_target;
uint256 public price_band;
bool public collateral_ratio_paused = false;
modifier onlyPools() {
require(xsd_pools[msg.sender] == true, "Only xsd pools can call this function");
_;
}
modifier onlyByOwner(){
require(msg.sender == smartcontract_owner, "You are not the owner");
_;
}
modifier onlyByOwnerPID() {
require(msg.sender == smartcontract_owner || msg.sender == pid_address, "You are not the owner or the pid controller");
_;
}
modifier onlyByOwnerOrPool() {
require(
msg.sender == smartcontract_owner
|| xsd_pools[msg.sender] == true,
"You are not the owner or a pool");
_;
}
constructor(
string memory _name,
string memory _symbol,
uint256 _pool_amount,
uint256 _genesis_supply,
address _smartcontract_owner,
address _treasury,
uint256 _cap_rate
) {
require((_smartcontract_owner != address(0))
&& (_treasury != address(0)), "Zero address detected");
name = _name;
symbol = _symbol;
genesis_supply = _genesis_supply + _pool_amount;
treasury = _treasury;
_mint(_smartcontract_owner, _pool_amount);
_mint(treasury, _genesis_supply);
smartcontract_owner = _smartcontract_owner;
xsd_step = 2500;
global_collateral_ratio = 1000000;
interest_rate = 52800;
refresh_cooldown = 3600;
price_target = 800000;
price_band = 5000;
cap_rate = _cap_rate;
}
function pool_price(PriceChoice choice) internal view returns (uint256) {
uint256 _eth_usd_price = (uint256(eth_usd_pricer.getLatestPrice())*PRICE_PRECISION)/(uint256(10) ** eth_usd_pricer_decimals);
uint256 price_vs_eth = 0;
uint256 reserve0;
uint256 reserve1;
if (choice == PriceChoice.XSD) {
(reserve0, reserve1, ) = xsdEthPool.getReserves();
if(reserve0 == 0 || reserve1 == 0){
return 1;
}
price_vs_eth = reserve0/(reserve1);
}
else if (choice == PriceChoice.BankX) {
(reserve0, reserve1, ) = bankxEthPool.getReserves();
if(reserve0 == 0 || reserve1 == 0){
return 1;
}
price_vs_eth = reserve0/(reserve1);
}
else revert("INVALID PRICE CHOICE. Needs to be either 0 (XSD) or 1 (BankX)");
return _eth_usd_price/price_vs_eth;
}
function xsd_price() public view returns (uint256) {
return pool_price(PriceChoice.XSD);
}
function bankx_price() public view returns (uint256) {
return pool_price(PriceChoice.BankX);
}
function eth_usd_price() public view returns (uint256) {
return (uint256(eth_usd_pricer.getLatestPrice())*PRICE_PRECISION)/(uint256(10) ** eth_usd_pricer_decimals);
}
function xag_usd_price() public view returns (uint256) {
return (uint256(xag_usd_pricer.getLatestPrice())*PRICE_PRECISION)/(uint256(10) ** xag_usd_pricer_decimals);
}
function xsd_info() public view returns (uint256, uint256, uint256, uint256, uint256, uint256) {
return (
pool_price(PriceChoice.XSD),
pool_price(PriceChoice.BankX),
totalSupply(),
global_collateral_ratio,
globalCollateralValue(),
(uint256(eth_usd_pricer.getLatestPrice())*PRICE_PRECISION)/(uint256(10) ** eth_usd_pricer_decimals)
);
}
function globalCollateralValue() public view returns (uint256) {
uint256 collateral_amount = 0;
collateral_amount = CollateralPool(payable(collateral_pool_address)).collatDollarBalance();
return collateral_amount;
}
uint256 public last_call_time;
function refreshCollateralRatio() public {
require(collateral_ratio_paused == false, "Collateral Ratio has been paused");
uint256 xsd_price_cur = xsd_price();
require(block.timestamp - last_call_time >= refresh_cooldown, "Must wait for the refresh cooldown since last refresh");
if (xsd_price_cur > (price_target+price_band)) {
if(global_collateral_ratio <= xsd_step){
global_collateral_ratio = 0;
} else {
global_collateral_ratio = global_collateral_ratio-xsd_step;
}
} else if (xsd_price_cur < price_target-price_band) {
if(global_collateral_ratio+xsd_step >= 1000000){
global_collateral_ratio = 1000000;
} else {
global_collateral_ratio = global_collateral_ratio+xsd_step;
}
}
else
last_call_time = block.timestamp;
uint256 _interest_rate = (1000000-global_collateral_ratio)/(2);
if(_interest_rate>52800){
interest_rate = _interest_rate;
}
else{
interest_rate = 52800;
}
emit CollateralRatioRefreshed(global_collateral_ratio);
}
function creatorMint(uint256 amount) public onlyByOwner{
require(genesis_supply+amount<cap_rate,"cap limit reached");
super._mint(treasury,amount);
}
function pool_burn_from(address b_address, uint256 b_amount) public onlyPools {
super._burnFrom(b_address, b_amount);
emit XSDBurned(b_address, msg.sender, b_amount);
}
function pool_mint(address m_address, uint256 m_amount) public onlyPools {
super._mint(m_address, m_amount);
emit XSDMinted(msg.sender, m_address, m_amount);
}
function addPool(address pool_address) public onlyByOwner {
require(pool_address != address(0), "Zero address detected");
require(xsd_pools[pool_address] == false, "Address already exists");
xsd_pools[pool_address] = true;
xsd_pools_array.push(pool_address);
emit PoolAdded(pool_address);
}
function removePool(address pool_address) public onlyByOwner {
require(pool_address != address(0), "Zero address detected");
require(xsd_pools[pool_address] == true, "Address nonexistant");
delete xsd_pools[pool_address];
for (uint i = 0; i < xsd_pools_array.length; i++){
if (xsd_pools_array[i] == pool_address) {
xsd_pools_array[i] = address(0);
break;
}
}
emit PoolRemoved(pool_address);
}
function burnpoolXSD(uint _xsdamount) public {
require(msg.sender == router, "Only the router can access this function");
require(totalSupply()-CollateralPool(payable(collateral_pool_address)).collat_XSD()>_xsdamount, "uXSD has to be positive");
super._burn(address(xsdEthPool),_xsdamount);
xsdEthPool.sync();
emit XSDBurned(msg.sender, address(this), _xsdamount);
}
function burnUserXSD(uint _xsdamount) public {
require(totalSupply()-CollateralPool(payable(collateral_pool_address)).collat_XSD()>_xsdamount, "uXSD has to be positive");
super._burn(msg.sender, _xsdamount);
emit XSDBurned(msg.sender, address(this), _xsdamount);
}
function setXSDStep(uint256 _new_step) public onlyByOwnerPID {
xsd_step = _new_step;
emit XSDStepSet(_new_step);
}
function setPriceTarget (uint256 _new_price_target) public onlyByOwnerPID {
price_target = _new_price_target;
emit PriceTargetSet(_new_price_target);
}
function setRefreshCooldown(uint256 _new_cooldown) public onlyByOwnerPID {
refresh_cooldown = _new_cooldown;
emit RefreshCooldownSet(_new_cooldown);
}
function setTreasury(address _new_treasury) public onlyByOwner {
require(_new_treasury != address(0), "Zero address detected");
treasury = _new_treasury;
}
function setETHUSDOracle(address _eth_usd_oracle_address) public onlyByOwner {
require(_eth_usd_oracle_address != address(0), "Zero address detected");
eth_usd_oracle_address = _eth_usd_oracle_address;
eth_usd_pricer = ChainlinkETHUSDPriceConsumer(eth_usd_oracle_address);
eth_usd_pricer_decimals = eth_usd_pricer.getDecimals();
emit ETHUSDOracleSet(_eth_usd_oracle_address);
}
function setXAGUSDOracle(address _xag_usd_oracle_address) public onlyByOwner {
require(_xag_usd_oracle_address != address(0), "Zero address detected");
xag_usd_oracle_address = _xag_usd_oracle_address;
xag_usd_pricer = ChainlinkXAGUSDPriceConsumer(xag_usd_oracle_address);
xag_usd_pricer_decimals = xag_usd_pricer.getDecimals();
emit XAGUSDOracleSet(_xag_usd_oracle_address);
}
function setPIDController(address _pid_address) external onlyByOwner {
require(_pid_address != address(0), "Zero address detected");
pid_address = _pid_address;
emit PIDControllerSet(_pid_address);
}
function setRouterAddress(address _router) external onlyByOwner {
require(_router != address(0), "Zero address detected");
router = _router;
}
function setPriceBand(uint256 _price_band) external onlyByOwner {
price_band = _price_band;
emit PriceBandSet(_price_band);
}
function setXSDEthPool(address _xsd_pool_addr) public onlyByOwner {
require(_xsd_pool_addr != address(0), "Zero address detected");
xsdEthPool = IXSDWETHpool(_xsd_pool_addr);
emit XSDETHPoolSet(_xsd_pool_addr);
}
function setBankXEthPool(address _bankx_pool_addr) public onlyByOwner {
require(_bankx_pool_addr != address(0), "Zero address detected");
bankxEthPool = IBankXWETHpool(_bankx_pool_addr);
emit BankXEthPoolSet(_bankx_pool_addr);
}
function setCollateralEthPool(address _collateral_pool_address) public onlyByOwner {
require(_collateral_pool_address != address(0), "Zero address detected");
collateral_pool_address = payable(_collateral_pool_address);
}
function setSmartContractOwner(address _smartcontract_owner) external{
require(msg.sender == smartcontract_owner, "Only the smart contract owner can access this function");
require(msg.sender != address(0), "Zero address detected");
smartcontract_owner = _smartcontract_owner;
}
function renounceOwnership() external{
require(msg.sender == smartcontract_owner, "Only the smart contract owner can access this function");
smartcontract_owner = address(0);
}
event XSDBurned(address indexed from, address indexed to, uint256 amount);
event XSDMinted(address indexed from, address indexed to, uint256 amount);
event CollateralRatioRefreshed(uint256 global_collateral_ratio);
event PoolAdded(address pool_address);
event PoolRemoved(address pool_address);
event RedemptionFeeSet(uint256 red_fee);
event MintingFeeSet(uint256 min_fee);
event XSDStepSet(uint256 new_step);
event PriceTargetSet(uint256 new_price_target);
event RefreshCooldownSet(uint256 new_cooldown);
event ETHUSDOracleSet(address eth_usd_oracle_address);
event XAGUSDOracleSet(address xag_usd_oracle_address);
event PIDControllerSet(address _pid_controller);
event PriceBandSet(uint256 price_band);
event XSDETHPoolSet(address xsd_pool_addr);
event BankXEthPoolSet(address bankx_pool_addr);
event CollateralRatioToggled(bool collateral_ratio_paused);
}
{
"compilationTarget": {
"contracts/BankX/BankXToken.sol": "BankXToken"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_pool_amount","type":"uint256"},{"internalType":"uint256","name":"_genesis_supply","type":"uint256"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_smartcontract_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BankXBurned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BankXMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"XSDAddressSet","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bankx_amount","type":"uint256"}],"name":"burnpoolBankX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"genesisSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genesis_supply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool_address","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"b_address","type":"address"},{"internalType":"uint256","name":"b_amount","type":"uint256"}],"name":"pool_burn_from","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"m_address","type":"address"},{"internalType":"uint256","name":"m_amount","type":"uint256"}],"name":"pool_mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"new_pool","type":"address"}],"name":"setPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"}],"name":"setRouterAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_smartcontract_owner","type":"address"}],"name":"setSmartContractOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"new_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"xsd_contract_address","type":"address"}],"name":"setXSDAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"smartcontract_owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]