Compare commits
12 Commits
4193447068
...
a41cef0dfe
Author | SHA1 | Date | |
---|---|---|---|
a41cef0dfe | |||
07c752754b | |||
9e40d4ed4f | |||
15dfd49163 | |||
a8790cc452 | |||
4bea615f8b | |||
899b03ddde | |||
3bb6904f54 | |||
3f0d1fb02e | |||
34fdb21d82 | |||
941aba02fa | |||
5541eda138 |
@ -72,6 +72,18 @@ RESERVE_MINT_RATE=
|
|||||||
RESERVE_TOKEN_NAME=
|
RESERVE_TOKEN_NAME=
|
||||||
RESERVE_TOKEN_SYMBOL=
|
RESERVE_TOKEN_SYMBOL=
|
||||||
|
|
||||||
|
## Name and symbol for the base token of the ghostDAO protocol
|
||||||
|
FATSO_TOKEN_NAME=
|
||||||
|
FATSO_TOKEN_SYMBOL=
|
||||||
|
|
||||||
|
## Name and symbol for the staking token of the ghostDAO protocol
|
||||||
|
STINKY_TOKEN_NAME=
|
||||||
|
STINKY_TOKEN_SYMBOL=
|
||||||
|
|
||||||
|
## Name and symbol for the bridging token of the ghostDAO protocol
|
||||||
|
GHOST_TOKEN_NAME=
|
||||||
|
GHOST_TOKEN_SYMBOL=
|
||||||
|
|
||||||
SEPOLIA_TEST_RPC_URL=
|
SEPOLIA_TEST_RPC_URL=
|
||||||
SEPOLIA_TEST_API_KEY=
|
SEPOLIA_TEST_API_KEY=
|
||||||
SEPOLIA_TEST_ENDPOINT=
|
SEPOLIA_TEST_ENDPOINT=
|
||||||
|
35
deployer.sh
35
deployer.sh
@ -6,6 +6,30 @@ START=1
|
|||||||
END=12
|
END=12
|
||||||
VERIFY_NEEDED="--verify"
|
VERIFY_NEEDED="--verify"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Correct deployer script usage:"
|
||||||
|
echo -e "\t-s, --start - from which contract deployment should start."
|
||||||
|
echo -e "\t-e, --end - last contract deployment to be done."
|
||||||
|
echo -e "\t-n, --network - network name to be deployed on."
|
||||||
|
echo -e "\t-b, --blockscout - should try to use blockscout as verifier."
|
||||||
|
echo -e "\nAvailable network names: ${AVAILIABLE_NETWORKS[@]}"
|
||||||
|
echo -e "\nContract enumeration:"
|
||||||
|
echo "0) Reserve"
|
||||||
|
echo "1) Authority"
|
||||||
|
echo "2) Fatso"
|
||||||
|
echo "3) Stinky"
|
||||||
|
echo "4) Ghost"
|
||||||
|
echo "5) Staking"
|
||||||
|
echo "6) Treasury"
|
||||||
|
echo "7) BondDepository"
|
||||||
|
echo "8) StakingDistributor"
|
||||||
|
echo "9) BondingCalculator"
|
||||||
|
echo "10) AfterPartyFirst"
|
||||||
|
echo "11) AfterPartySecond"
|
||||||
|
echo "12) AfterPartyThird"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
while [[ $# -gt 0 ]];
|
while [[ $# -gt 0 ]];
|
||||||
do
|
do
|
||||||
case "${1}" in
|
case "${1}" in
|
||||||
@ -24,6 +48,17 @@ do
|
|||||||
shift
|
shift
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
-b|--blockscout)
|
||||||
|
VERIFY_NEEDED+=" --verifier blockscout"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "\nERROR: Unknown option provided\n"
|
||||||
|
usage
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -7,9 +7,9 @@ import "./interfaces/IFTSO.sol";
|
|||||||
import "./types/GhostAccessControlled.sol";
|
import "./types/GhostAccessControlled.sol";
|
||||||
|
|
||||||
contract Fatso is ERC20Permit, IFTSO, GhostAccessControlled {
|
contract Fatso is ERC20Permit, IFTSO, GhostAccessControlled {
|
||||||
constructor(address _authority)
|
constructor(address _authority, string memory name, string memory symbol)
|
||||||
ERC20("Fatso", "FTSO")
|
ERC20(name, symbol)
|
||||||
ERC20Permit("Fatso")
|
ERC20Permit(name)
|
||||||
GhostAccessControlled(IGhostAuthority(_authority))
|
GhostAccessControlled(IGhostAuthority(_authority))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -13,7 +13,10 @@ contract Ghost is IGHST, ERC20, ERC20Permit, ERC20Votes {
|
|||||||
address public override stnk;
|
address public override stnk;
|
||||||
address private _initializer;
|
address private _initializer;
|
||||||
|
|
||||||
constructor(address _stnk) ERC20("Ghost", "GHST") ERC20Permit("Ghost") {
|
constructor(address _stnk, string memory name, string memory symbol)
|
||||||
|
ERC20(name, symbol)
|
||||||
|
ERC20Permit(name)
|
||||||
|
{
|
||||||
stnk = _stnk;
|
stnk = _stnk;
|
||||||
_initializer = msg.sender;
|
_initializer = msg.sender;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,10 @@ contract Stinky is ISTNK, ERC20Permit {
|
|||||||
mapping(address => uint256) private _shares;
|
mapping(address => uint256) private _shares;
|
||||||
mapping(address => mapping(address => uint256)) private _allowedValue;
|
mapping(address => mapping(address => uint256)) private _allowedValue;
|
||||||
|
|
||||||
constructor(uint256 usedIndex) ERC20("Stinky", "STNK") ERC20Permit("Stinky") {
|
constructor(uint256 usedIndex, string memory name, string memory symbol)
|
||||||
|
ERC20(name, symbol)
|
||||||
|
ERC20Permit(name)
|
||||||
|
{
|
||||||
_initializer = msg.sender;
|
_initializer = msg.sender;
|
||||||
_internalIndex = usedIndex;
|
_internalIndex = usedIndex;
|
||||||
_totalSupply = INITIAL_SHARES_SUPPLY;
|
_totalSupply = INITIAL_SHARES_SUPPLY;
|
||||||
|
@ -5,7 +5,9 @@ import "@openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol";
|
|||||||
|
|
||||||
contract Reserve is ERC20Permit {
|
contract Reserve is ERC20Permit {
|
||||||
address private immutable _owner;
|
address private immutable _owner;
|
||||||
|
uint256 public accumulatedDonation;
|
||||||
uint256 public conversionRate;
|
uint256 public conversionRate;
|
||||||
|
uint256 public donationRate;
|
||||||
error OnlyOwner();
|
error OnlyOwner();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -18,11 +20,11 @@ contract Reserve is ERC20Permit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fallback() external payable {
|
fallback() external payable {
|
||||||
_innerMint(msg.sender, msg.value);
|
_mint(msg.sender, msg.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
receive() external payable {
|
receive() external payable {
|
||||||
_innerMint(msg.sender, msg.value);
|
_mint(msg.sender, msg.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeRate(uint256 rate) external {
|
function changeRate(uint256 rate) external {
|
||||||
@ -30,22 +32,42 @@ contract Reserve is ERC20Permit {
|
|||||||
conversionRate = rate;
|
conversionRate = rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeDonationRate(uint256 rate) external {
|
||||||
|
if (msg.sender != _owner) revert OnlyOwner();
|
||||||
|
donationRate = rate;
|
||||||
|
}
|
||||||
|
|
||||||
function withdraw(address payable receiver) external {
|
function withdraw(address payable receiver) external {
|
||||||
if (msg.sender != _owner) revert OnlyOwner();
|
if (msg.sender != _owner) revert OnlyOwner();
|
||||||
(bool sent,) = receiver.call{ value: address(this).balance }("");
|
uint256 accumulatedDonationCached = accumulatedDonation;
|
||||||
|
accumulatedDonation = 0;
|
||||||
|
|
||||||
|
(bool sent,) = receiver.call{ value: accumulatedDonationCached }("");
|
||||||
require(sent, "Failed to send Ether");
|
require(sent, "Failed to send Ether");
|
||||||
}
|
}
|
||||||
|
|
||||||
function superMint(address account, uint256 value) external {
|
function superMint(address account, uint256 value) external {
|
||||||
if (msg.sender != _owner) revert OnlyOwner();
|
if (msg.sender != _owner) revert OnlyOwner();
|
||||||
_innerMint(account, value);
|
_mint(account, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mint(address account) external payable {
|
function mint(address account) external payable {
|
||||||
_innerMint(account, msg.value);
|
uint256 donation = msg.value * donationRate / 1e5;
|
||||||
|
accumulatedDonation += donation;
|
||||||
|
_mint(account, msg.value * conversionRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _innerMint(address who, uint256 amount) internal {
|
function burn(uint256 amount) external {
|
||||||
_mint(who, amount * conversionRate);
|
_burn(msg.sender, amount);
|
||||||
|
uint256 valueDiff = address(this).balance - accumulatedDonation;
|
||||||
|
uint256 valueBack = amount * valueDiff / (amount + totalSupply());
|
||||||
|
|
||||||
|
(bool sent,) = msg.sender.call{ value: valueBack }("");
|
||||||
|
require(sent, "Failed to send Ether");
|
||||||
|
}
|
||||||
|
|
||||||
|
function estimateAmount(uint256 amount) external view returns (uint256) {
|
||||||
|
uint256 valueDiff = address(this).balance - accumulatedDonation;
|
||||||
|
return amount * valueDiff / totalSupply();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,9 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
uint256 public constant TOTAL_INITIAL_SUPPLY = 5000000000000000;
|
uint256 public constant TOTAL_INITIAL_SUPPLY = 5000000000000000;
|
||||||
uint256 public constant LARGE_APPROVAL = 100000000000000000000000000000000;
|
uint256 public constant LARGE_APPROVAL = 100000000000000000000000000000000;
|
||||||
uint256 public constant INITIAL_INDEX = 10819917194513808e56;
|
uint256 public constant INITIAL_INDEX = 10819917194513808e56;
|
||||||
uint48 public constant EPOCH_LENGTH = 2200;
|
uint48 public constant EPOCH_LENGTH = 2200;
|
||||||
uint48 public constant EPOCH_NUMBER = 1;
|
uint48 public constant EPOCH_NUMBER = 1;
|
||||||
uint48 public constant EPOCH_END_TIME = 1337;
|
uint48 public constant EPOCH_END_TIME = 1337;
|
||||||
|
|
||||||
uint256 public constant initialMint = 10000000000000000000000000;
|
uint256 public constant initialMint = 10000000000000000000000000;
|
||||||
uint256 public constant initialDeposit = 1000000000000000000000000;
|
uint256 public constant initialDeposit = 1000000000000000000000000;
|
||||||
@ -59,9 +59,9 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
vault
|
vault
|
||||||
);
|
);
|
||||||
reserve = new ERC20Mock("Reserve Token", "RET");
|
reserve = new ERC20Mock("Reserve Token", "RET");
|
||||||
ftso = new Fatso(address(authority));
|
ftso = new Fatso(address(authority), "Fatso", "FTSO");
|
||||||
stnk = new Stinky(INITIAL_INDEX);
|
stnk = new Stinky(INITIAL_INDEX, "Stinky", "STNK");
|
||||||
ghst = new Ghost(address(stnk));
|
ghst = new Ghost(address(stnk), "Ghost", "GHST");
|
||||||
staking = new GhostStaking(
|
staking = new GhostStaking(
|
||||||
address(ftso),
|
address(ftso),
|
||||||
address(stnk),
|
address(stnk),
|
||||||
|
@ -47,9 +47,9 @@ contract StakingTest is Test {
|
|||||||
policy,
|
policy,
|
||||||
vault
|
vault
|
||||||
);
|
);
|
||||||
ftso = new Fatso(address(authority));
|
ftso = new Fatso(address(authority), "Fatso", "FTSO");
|
||||||
stnk = new Stinky(INITIAL_INDEX);
|
stnk = new Stinky(INITIAL_INDEX, "Stinky", "STNK");
|
||||||
ghst = new Ghost(address(stnk));
|
ghst = new Ghost(address(stnk), "Ghost", "GHST");
|
||||||
staking = new GhostStaking(
|
staking = new GhostStaking(
|
||||||
address(ftso),
|
address(ftso),
|
||||||
address(stnk),
|
address(stnk),
|
||||||
|
@ -22,7 +22,7 @@ contract StakingDistributorTest is Test {
|
|||||||
uint48 public constant EPOCH_LENGTH = 2200;
|
uint48 public constant EPOCH_LENGTH = 2200;
|
||||||
uint48 public constant EPOCH_NUMBER = 1;
|
uint48 public constant EPOCH_NUMBER = 1;
|
||||||
uint48 public constant EPOCH_END_TIME = 1337;
|
uint48 public constant EPOCH_END_TIME = 1337;
|
||||||
|
|
||||||
uint256 public constant INITIAL_INDEX = 10819917194513808e56;
|
uint256 public constant INITIAL_INDEX = 10819917194513808e56;
|
||||||
uint256 public constant amount = 69 * 1e18;
|
uint256 public constant amount = 69 * 1e18;
|
||||||
|
|
||||||
@ -47,9 +47,9 @@ contract StakingDistributorTest is Test {
|
|||||||
owner
|
owner
|
||||||
);
|
);
|
||||||
reserve = new ERC20Mock("Reserve Token", "RET");
|
reserve = new ERC20Mock("Reserve Token", "RET");
|
||||||
ftso = new Fatso(address(authority));
|
ftso = new Fatso(address(authority), "Fatso", "FTSO");
|
||||||
stnk = new Stinky(INITIAL_INDEX);
|
stnk = new Stinky(INITIAL_INDEX, "Stinky", "STNK");
|
||||||
ghst = new Ghost(address(stnk));
|
ghst = new Ghost(address(stnk), "Ghost", "GHST");
|
||||||
staking = new GhostStaking(
|
staking = new GhostStaking(
|
||||||
address(ftso),
|
address(ftso),
|
||||||
address(stnk),
|
address(stnk),
|
||||||
|
@ -20,6 +20,9 @@ contract FatsoTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferTe
|
|||||||
uint256 constant amount = 69;
|
uint256 constant amount = 69;
|
||||||
uint256 constant maxAmount = type(uint256).max;
|
uint256 constant maxAmount = type(uint256).max;
|
||||||
|
|
||||||
|
string constant name = "Fatso Test Name";
|
||||||
|
string constant symbol = "FTSOTST";
|
||||||
|
|
||||||
function setUp() public {
|
function setUp() public {
|
||||||
authority = new GhostAuthority(
|
authority = new GhostAuthority(
|
||||||
deployer,
|
deployer,
|
||||||
@ -27,7 +30,7 @@ contract FatsoTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferTe
|
|||||||
deployer,
|
deployer,
|
||||||
vault
|
vault
|
||||||
);
|
);
|
||||||
token = new Fatso(address(authority));
|
token = new Fatso(address(authority), name, symbol);
|
||||||
initializePermit(address(token), amount, maxAmount);
|
initializePermit(address(token), amount, maxAmount);
|
||||||
initializeAllowance(alice, bob, address(token), amount, maxAmount, amount);
|
initializeAllowance(alice, bob, address(token), amount, maxAmount, amount);
|
||||||
initializeTransfer(alice, bob, address(token), amount, 0);
|
initializeTransfer(alice, bob, address(token), amount, 0);
|
||||||
@ -48,8 +51,8 @@ contract FatsoTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferTe
|
|||||||
}
|
}
|
||||||
|
|
||||||
function test_correctlyConstructsAnERC20() public view {
|
function test_correctlyConstructsAnERC20() public view {
|
||||||
assertEq(token.name(), "Fatso");
|
assertEq(token.name(), name);
|
||||||
assertEq(token.symbol(), "FTSO");
|
assertEq(token.symbol(), symbol);
|
||||||
assertEq(token.decimals(), 9);
|
assertEq(token.decimals(), 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,9 @@ contract GhostTest is
|
|||||||
uint256 constant amount = 69;
|
uint256 constant amount = 69;
|
||||||
uint256 constant maxAmount = type(uint256).max;
|
uint256 constant maxAmount = type(uint256).max;
|
||||||
|
|
||||||
|
string constant name = "Ghost Test Name";
|
||||||
|
string constant symbol = "GHSTTST";
|
||||||
|
|
||||||
Stinky stnk;
|
Stinky stnk;
|
||||||
Ghost ghst;
|
Ghost ghst;
|
||||||
GhostAuthority public authority;
|
GhostAuthority public authority;
|
||||||
@ -41,8 +44,8 @@ contract GhostTest is
|
|||||||
initializer,
|
initializer,
|
||||||
initializer
|
initializer
|
||||||
);
|
);
|
||||||
stnk = new Stinky(INITIAL_INDEX);
|
stnk = new Stinky(INITIAL_INDEX, "Stinky", "STNK");
|
||||||
ghst = new Ghost(address(stnk));
|
ghst = new Ghost(address(stnk), name, symbol);
|
||||||
staking = new GhostStaking(
|
staking = new GhostStaking(
|
||||||
address(0),
|
address(0),
|
||||||
address(stnk),
|
address(stnk),
|
||||||
@ -63,8 +66,8 @@ contract GhostTest is
|
|||||||
}
|
}
|
||||||
|
|
||||||
function test_isConstructedCorrectly() public view {
|
function test_isConstructedCorrectly() public view {
|
||||||
assertEq(ghst.name(), "Ghost");
|
assertEq(ghst.name(), name);
|
||||||
assertEq(ghst.symbol(), "GHST");
|
assertEq(ghst.symbol(), symbol);
|
||||||
assertEq(ghst.decimals(), 18);
|
assertEq(ghst.decimals(), 18);
|
||||||
assertEq(ghst.staking(), address(staking));
|
assertEq(ghst.staking(), address(staking));
|
||||||
assertEq(ghst.stnk(), address(stnk));
|
assertEq(ghst.stnk(), address(stnk));
|
||||||
|
@ -35,6 +35,9 @@ contract ReserveTest is Test {
|
|||||||
assertEq(reserve.symbol(), symbol);
|
assertEq(reserve.symbol(), symbol);
|
||||||
assertEq(reserve.decimals(), 18);
|
assertEq(reserve.decimals(), 18);
|
||||||
assertEq(reserve.totalSupply(), 0);
|
assertEq(reserve.totalSupply(), 0);
|
||||||
|
|
||||||
|
assertEq(reserve.donationRate(), 0);
|
||||||
|
assertEq(reserve.conversionRate(), conversionRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_mint_couldBeDoneWithValue() public {
|
function test_mint_couldBeDoneWithValue() public {
|
||||||
@ -72,7 +75,7 @@ contract ReserveTest is Test {
|
|||||||
assertEq(reserve.balanceOf(initializer), 0);
|
assertEq(reserve.balanceOf(initializer), 0);
|
||||||
vm.prank(initializer);
|
vm.prank(initializer);
|
||||||
reserve.superMint(initializer, 420 * 1e18);
|
reserve.superMint(initializer, 420 * 1e18);
|
||||||
assertEq(reserve.balanceOf(initializer), 420 * 1e18 * conversionRate);
|
assertEq(reserve.balanceOf(initializer), 420 * 1e18);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_mint_superMintCouldNotBeDoneFromArbitraryAddress() public {
|
function test_mint_superMintCouldNotBeDoneFromArbitraryAddress() public {
|
||||||
@ -83,6 +86,37 @@ contract ReserveTest is Test {
|
|||||||
assertEq(reserve.balanceOf(aliceAddress), 0);
|
assertEq(reserve.balanceOf(aliceAddress), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_mint_donationNotTakenIfRateNotSet() public {
|
||||||
|
assertEq(reserve.totalSupply(), 0);
|
||||||
|
assertEq(reserve.donationRate(), 0);
|
||||||
|
assertEq(reserve.accumulatedDonation(), 0);
|
||||||
|
|
||||||
|
deal(aliceAddress, sendAmount);
|
||||||
|
vm.prank(aliceAddress);
|
||||||
|
reserve.mint{ value: sendAmount }(aliceAddress);
|
||||||
|
|
||||||
|
assertEq(reserve.totalSupply(), sendAmount * conversionRate);
|
||||||
|
assertEq(reserve.donationRate(), 0);
|
||||||
|
assertEq(reserve.accumulatedDonation(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_mint_donationIsTakenIfRateExists() public {
|
||||||
|
assertEq(reserve.totalSupply(), 0);
|
||||||
|
assertEq(reserve.donationRate(), 0);
|
||||||
|
assertEq(reserve.accumulatedDonation(), 0);
|
||||||
|
|
||||||
|
vm.prank(initializer);
|
||||||
|
reserve.changeDonationRate(1e4); // 10%
|
||||||
|
|
||||||
|
deal(aliceAddress, sendAmount);
|
||||||
|
vm.prank(aliceAddress);
|
||||||
|
reserve.mint{ value: sendAmount }(aliceAddress);
|
||||||
|
|
||||||
|
assertEq(reserve.totalSupply(), sendAmount * conversionRate);
|
||||||
|
assertEq(reserve.donationRate(), 1e4);
|
||||||
|
assertEq(reserve.accumulatedDonation(), sendAmount * 1e4 / 1e5);
|
||||||
|
}
|
||||||
|
|
||||||
function test_rate_couldBeChangedByDeployer() public {
|
function test_rate_couldBeChangedByDeployer() public {
|
||||||
assertEq(reserve.conversionRate(), conversionRate);
|
assertEq(reserve.conversionRate(), conversionRate);
|
||||||
vm.prank(initializer);
|
vm.prank(initializer);
|
||||||
@ -100,6 +134,8 @@ contract ReserveTest is Test {
|
|||||||
|
|
||||||
function test_withdraw_couldBeDoneByDeployer() public {
|
function test_withdraw_couldBeDoneByDeployer() public {
|
||||||
assertEq(address(reserve).balance, 0);
|
assertEq(address(reserve).balance, 0);
|
||||||
|
vm.prank(initializer);
|
||||||
|
reserve.changeDonationRate(1e5);
|
||||||
|
|
||||||
deal(aliceAddress, sendAmount);
|
deal(aliceAddress, sendAmount);
|
||||||
vm.prank(aliceAddress);
|
vm.prank(aliceAddress);
|
||||||
@ -114,6 +150,28 @@ contract ReserveTest is Test {
|
|||||||
assertEq(faucetAddress.balance, sendAmount);
|
assertEq(faucetAddress.balance, sendAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_withdraw_onlyAccumulatedDonationsCouldBeWithdrawn() public {
|
||||||
|
assertEq(address(reserve).balance, 0);
|
||||||
|
vm.prank(initializer);
|
||||||
|
reserve.changeDonationRate(5 * 1e4); // 50%
|
||||||
|
|
||||||
|
deal(aliceAddress, sendAmount);
|
||||||
|
vm.prank(aliceAddress);
|
||||||
|
reserve.mint{ value: sendAmount }(aliceAddress);
|
||||||
|
|
||||||
|
assertEq(address(reserve).balance, sendAmount);
|
||||||
|
|
||||||
|
vm.prank(initializer);
|
||||||
|
reserve.withdraw(payable(faucetAddress));
|
||||||
|
assertEq(address(reserve).balance, sendAmount / 2);
|
||||||
|
assertEq(faucetAddress.balance, sendAmount / 2);
|
||||||
|
|
||||||
|
vm.prank(initializer);
|
||||||
|
reserve.withdraw(payable(faucetAddress));
|
||||||
|
assertEq(address(reserve).balance, sendAmount / 2);
|
||||||
|
assertEq(faucetAddress.balance, sendAmount / 2);
|
||||||
|
}
|
||||||
|
|
||||||
function test_withdraw_couldNotBeDoneByArbitraryAddress() public {
|
function test_withdraw_couldNotBeDoneByArbitraryAddress() public {
|
||||||
assertEq(address(reserve).balance, 0);
|
assertEq(address(reserve).balance, 0);
|
||||||
|
|
||||||
@ -130,4 +188,86 @@ contract ReserveTest is Test {
|
|||||||
assertEq(address(reserve).balance, sendAmount);
|
assertEq(address(reserve).balance, sendAmount);
|
||||||
assertEq(aliceAddress.balance, 0);
|
assertEq(aliceAddress.balance, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_burn_shouldReturnFullAmountIfRateNotSet() public {
|
||||||
|
deal(aliceAddress, sendAmount);
|
||||||
|
vm.prank(aliceAddress);
|
||||||
|
reserve.mint{ value: sendAmount }(aliceAddress);
|
||||||
|
|
||||||
|
uint256 balance = reserve.balanceOf(aliceAddress);
|
||||||
|
assertEq(reserve.totalSupply(), sendAmount * conversionRate);
|
||||||
|
assertEq(reserve.totalSupply(), balance);
|
||||||
|
assertEq(reserve.accumulatedDonation(), 0);
|
||||||
|
assertEq(aliceAddress.balance, 0);
|
||||||
|
|
||||||
|
vm.prank(aliceAddress);
|
||||||
|
reserve.burn(balance);
|
||||||
|
|
||||||
|
assertEq(reserve.totalSupply(), 0);
|
||||||
|
assertEq(reserve.balanceOf(aliceAddress), 0);
|
||||||
|
assertEq(reserve.accumulatedDonation(), 0);
|
||||||
|
assertEq(aliceAddress.balance, sendAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_burn_shouldTakeDonationInAccordanceToRate() public {
|
||||||
|
vm.prank(initializer);
|
||||||
|
reserve.changeDonationRate(5 * 1e4); // 50%
|
||||||
|
|
||||||
|
deal(aliceAddress, sendAmount);
|
||||||
|
vm.prank(aliceAddress);
|
||||||
|
reserve.mint{ value: sendAmount }(aliceAddress);
|
||||||
|
|
||||||
|
uint256 balance = reserve.balanceOf(aliceAddress);
|
||||||
|
assertEq(reserve.totalSupply(), sendAmount * conversionRate);
|
||||||
|
assertEq(reserve.totalSupply(), balance);
|
||||||
|
assertEq(reserve.accumulatedDonation(), sendAmount / 2);
|
||||||
|
assertEq(aliceAddress.balance, 0);
|
||||||
|
|
||||||
|
vm.prank(aliceAddress);
|
||||||
|
reserve.burn(balance);
|
||||||
|
|
||||||
|
assertEq(reserve.totalSupply(), 0);
|
||||||
|
assertEq(reserve.balanceOf(aliceAddress), 0);
|
||||||
|
assertEq(reserve.accumulatedDonation(), sendAmount / 2);
|
||||||
|
assertEq(aliceAddress.balance, sendAmount / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_burn_multipleUsersAccumulateInTotal() public {
|
||||||
|
vm.prank(initializer);
|
||||||
|
reserve.changeDonationRate(5 * 1e4); // 50%
|
||||||
|
|
||||||
|
deal(aliceAddress, sendAmount);
|
||||||
|
vm.prank(aliceAddress);
|
||||||
|
reserve.mint{ value: sendAmount }(aliceAddress);
|
||||||
|
|
||||||
|
vm.prank(initializer);
|
||||||
|
reserve.changeRate(conversionRate * 9);
|
||||||
|
|
||||||
|
deal(bobAddress, sendAmount);
|
||||||
|
vm.prank(bobAddress);
|
||||||
|
reserve.mint{ value: sendAmount }(bobAddress);
|
||||||
|
|
||||||
|
assertEq(aliceAddress.balance, 0);
|
||||||
|
assertEq(bobAddress.balance, 0);
|
||||||
|
uint256 aliceBalance = reserve.balanceOf(aliceAddress);
|
||||||
|
uint256 bobBalance = reserve.balanceOf(bobAddress);
|
||||||
|
|
||||||
|
uint256 bobEstimation = reserve.estimateAmount(bobBalance);
|
||||||
|
uint256 aliceEstimation = reserve.estimateAmount(aliceBalance);
|
||||||
|
|
||||||
|
vm.prank(bobAddress);
|
||||||
|
reserve.burn(bobBalance);
|
||||||
|
|
||||||
|
vm.prank(aliceAddress);
|
||||||
|
reserve.burn(aliceBalance);
|
||||||
|
|
||||||
|
assertEq(bobAddress.balance, sendAmount * 9 / 10);
|
||||||
|
assertEq(bobAddress.balance, bobEstimation);
|
||||||
|
assertEq(aliceAddress.balance, sendAmount / 10);
|
||||||
|
assertEq(aliceAddress.balance, aliceEstimation);
|
||||||
|
|
||||||
|
assertEq(reserve.totalSupply(), 0);
|
||||||
|
assertEq(reserve.accumulatedDonation(), sendAmount);
|
||||||
|
assertEq(address(reserve).balance, sendAmount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,9 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT
|
|||||||
uint256 constant amount = 69;
|
uint256 constant amount = 69;
|
||||||
uint256 constant maxAmount = type(uint256).max;
|
uint256 constant maxAmount = type(uint256).max;
|
||||||
|
|
||||||
|
string constant name = "Stinky Test Name";
|
||||||
|
string constant symbol = "STNKTST";
|
||||||
|
|
||||||
event Transfer(address indexed from, address indexed to, uint256 value);
|
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||||
event LogStakingContractUpdated(address stakingContract);
|
event LogStakingContractUpdated(address stakingContract);
|
||||||
|
|
||||||
@ -46,9 +49,9 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT
|
|||||||
initializer,
|
initializer,
|
||||||
initializer
|
initializer
|
||||||
);
|
);
|
||||||
ftso = new Fatso(address(authority));
|
ftso = new Fatso(address(authority), "Fatso", "FTSO");
|
||||||
stnk = new Stinky(INITIAL_INDEX);
|
stnk = new Stinky(INITIAL_INDEX, name, symbol);
|
||||||
ghst = new Ghost(address(stnk));
|
ghst = new Ghost(address(stnk), "Ghost", "GHST");
|
||||||
staking = new GhostStaking(
|
staking = new GhostStaking(
|
||||||
address(ftso),
|
address(ftso),
|
||||||
address(stnk),
|
address(stnk),
|
||||||
@ -67,8 +70,8 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT
|
|||||||
}
|
}
|
||||||
|
|
||||||
function test_isConstructedCorrectly() public view {
|
function test_isConstructedCorrectly() public view {
|
||||||
assertEq(stnk.name(), "Stinky");
|
assertEq(stnk.name(), name);
|
||||||
assertEq(stnk.symbol(), "STNK");
|
assertEq(stnk.symbol(), symbol);
|
||||||
assertEq(stnk.decimals(), 9);
|
assertEq(stnk.decimals(), 9);
|
||||||
assertEq(stnk.totalSupply(), TOTAL_INITIAL_SUPPLY);
|
assertEq(stnk.totalSupply(), TOTAL_INITIAL_SUPPLY);
|
||||||
assertEq(stnk.index(), INITIAL_INDEX / (TOTAL_SHARES / INITIAL_SHARES_SUPPLY));
|
assertEq(stnk.index(), INITIAL_INDEX / (TOTAL_SHARES / INITIAL_SHARES_SUPPLY));
|
||||||
@ -246,7 +249,7 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT
|
|||||||
uint256 prevIndex = stnk.index();
|
uint256 prevIndex = stnk.index();
|
||||||
_mintTokens(alice, amount);
|
_mintTokens(alice, amount);
|
||||||
assertEq(stnk.balanceOf(alice), amount);
|
assertEq(stnk.balanceOf(alice), amount);
|
||||||
|
|
||||||
vm.prank(address(staking));
|
vm.prank(address(staking));
|
||||||
stnk.rebase(0, epoch);
|
stnk.rebase(0, epoch);
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ contract GhostTreasuryTest is Test {
|
|||||||
);
|
);
|
||||||
reserve = new ERC20Mock("Reserve Token", "RET");
|
reserve = new ERC20Mock("Reserve Token", "RET");
|
||||||
liquidity = new ERC20Mock("Liquidity Token", "LDT");
|
liquidity = new ERC20Mock("Liquidity Token", "LDT");
|
||||||
ftso = new Fatso(address(authority));
|
ftso = new Fatso(address(authority), "Fatso", "FTSO");
|
||||||
treasury = new GhostTreasury(address(ftso), 69, address(authority));
|
treasury = new GhostTreasury(address(ftso), 69, address(authority));
|
||||||
calculator = new GhostBondingCalculator(address(ftso));
|
calculator = new GhostBondingCalculator(address(ftso));
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
Loading…
Reference in New Issue
Block a user