Skip to content

Commit

Permalink
Back to old style account conversions
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielVF committed Nov 3, 2024
1 parent 8f44d6d commit 9d762b9
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 98 deletions.
67 changes: 2 additions & 65 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,3 @@
## Foundry
# YOLO Spike, OUSD Token

**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**

Foundry consists of:

- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.

## Documentation

https://book.getfoundry.sh/

## Usage

### Build

```shell
$ forge build
```

### Test

```shell
$ forge test
```

### Format

```shell
$ forge fmt
```

### Gas Snapshots

```shell
$ forge snapshot
```

### Anvil

```shell
$ anvil
```

### Deploy

```shell
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
```

### Cast

```shell
$ cast <subcommand>
```

### Help

```shell
$ forge --help
$ anvil --help
$ cast --help
```
In which I take a swing at a balance centric approach to see if it results in simpiler code.
69 changes: 43 additions & 26 deletions src/token/OUSD.sol
Original file line number Diff line number Diff line change
Expand Up @@ -259,21 +259,26 @@ contract OUSD is Governable {
}

function _adjustAccount(address account, int256 balanceChange) internal returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff) {
RebaseOptions state = rebaseState[account];
int256 currentBalance = int256(balanceOf(account));
int256 newBalance = currentBalance + balanceChange;
uint256 newBalance = uint256(int256(currentBalance) + int256(balanceChange));
if(newBalance < 0){
revert("Transfer amount exceeds balance"); // Should never trigger
}
if (state == RebaseOptions.YieldDelegationTarget) {
newBalance += aintMoney[account];
}

if(_isNonRebasingAccount(account)){
nonRebasingSupplyDiff = balanceChange;
if(nonRebasingCreditsPerToken[account]!=1e27){
nonRebasingCreditsPerToken[account] = 1e27;
}
_creditBalances[account] = uint256(newBalance) * 1e9;
_creditBalances[account] = newBalance * 1e9;
} else {
int256 newCredits = ((newBalance) * int256(_rebasingCreditsPerToken) + 1e18 - 1) / 1e18;
rebasingCreditsDiff = newCredits - int256(_creditBalances[account]);
_creditBalances[account] = uint256(newCredits);
uint256 newCredits = _balanceToRebasingCredits(newBalance);
rebasingCreditsDiff = int256(newCredits) - int256(_creditBalances[account]);
_creditBalances[account] = newCredits;
}
}

Expand Down Expand Up @@ -484,6 +489,12 @@ contract OUSD is Governable {
}
}

function _balanceToRebasingCredits(uint256 balance) internal view returns (uint256) {
// Rounds up, because we need to ensure that accounts allways have
// at least the balance that they should have.
return ((balance) * _rebasingCreditsPerToken + 1e18 - 1) / 1e18;
}

/**
* @notice Enable rebasing for an account.
* @dev Add a contract address to the non-rebasing exception list. The
Expand All @@ -510,37 +521,36 @@ contract OUSD is Governable {

function _rebaseOptIn(address _account) internal {
require(_isNonRebasingAccount(_account), "Account has not opted out");
uint256 balance = balanceOf(msg.sender);
(int256 beforeRebasingCreditsDiff, int256 beforeNonRebasingSupplyDiff)
= _adjustAccount(msg.sender, -int256(balance));

nonRebasingCreditsPerToken[msg.sender] = 0;
uint256 balance = balanceOf(msg.sender);

// Acount
rebaseState[msg.sender] = RebaseOptions.OptIn;
nonRebasingCreditsPerToken[msg.sender] = 0;
_creditBalances[msg.sender] = _balanceToRebasingCredits(balance);

// Globals
nonRebasingSupply -= balance;
_rebasingCredits += _creditBalances[msg.sender];

(int256 afterRebasingCreditsDiff, int256 afterNonRebasingSupplyDiff)
= _adjustAccount(msg.sender, int256(balance));
_adjustGlobals(
beforeRebasingCreditsDiff - afterRebasingCreditsDiff,
beforeNonRebasingSupplyDiff - afterNonRebasingSupplyDiff
);
emit AccountRebasingEnabled(_account);
}

function rebaseOptOut() public nonReentrant {
require(!_isNonRebasingAccount(msg.sender), "Account has not opted in");

uint256 oldCredits = _creditBalances[msg.sender];
uint256 balance = balanceOf(msg.sender);
(int256 beforeRebasingCreditsDiff, int256 beforeNonRebasingSupplyDiff)
= _adjustAccount(msg.sender, -int256(balance));

nonRebasingCreditsPerToken[msg.sender] = 1e27;

// Acount
rebaseState[msg.sender] = RebaseOptions.OptOut;
nonRebasingCreditsPerToken[msg.sender] = 1e27;
_creditBalances[msg.sender] = balance * 1e9;

// Globals
nonRebasingSupply += balance;
_rebasingCredits -= oldCredits;

(int256 afterRebasingCreditsDiff, int256 afterNonRebasingSupplyDiff)
= _adjustAccount(msg.sender, int256(balance));
_adjustGlobals(
afterRebasingCreditsDiff - beforeRebasingCreditsDiff,
afterNonRebasingSupplyDiff - beforeNonRebasingSupplyDiff
);
emit AccountRebasingDisabled(msg.sender);
}

Expand Down Expand Up @@ -599,7 +609,14 @@ contract OUSD is Governable {
yieldFrom[to] = from;
rebaseState[from] = RebaseOptions.YieldDelegationSource;
rebaseState[to] = RebaseOptions.YieldDelegationTarget;
// Todo: accounting changes

uint256 fromAmount = balanceOf(from);
nonRebasingSupply -= fromAmount;
aintMoney[to] = fromAmount;
(int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)
= _adjustAccount(to, int256(fromAmount));
_adjustGlobals(rebasingCreditsDiff, nonRebasingSupplyDiff);

}

function undelegateYield(address from) external onlyGovernor() {
Expand Down
58 changes: 51 additions & 7 deletions test/OUSD.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ contract CounterTest is Test {
OUSD public ousd;

address public matt = makeAddr("Matt");
address public labs = makeAddr("NonRebasing");
address public nonrebasing = makeAddr("NonRebasing");
address public pool = makeAddr("Pool");
address public collector = makeAddr("Collector");
address public attacker = makeAddr("Attacker");
address[] accounts = [matt, attacker, labs, pool, collector];
address[] accounts = [matt, attacker, nonrebasing, pool, collector];

function setUp() public {
ousd = new OUSD();
ousd.initialize("", "", address(this), 314159265358979323846264333);

ousd.mint(matt, 1000 ether);
assertEq(ousd.totalSupply(), 1000 ether);
ousd.mint(labs, 1000 ether);
ousd.mint(nonrebasing, 1000 ether);
ousd.mint(pool, 1000 ether);
ousd.mint(collector, 1000 ether);
ousd.mint(attacker, 1000 ether);
assertEq(ousd.totalSupply(), 5000 ether);

vm.prank(labs);
vm.prank(nonrebasing);
ousd.rebaseOptOut();

vm.prank(pool);
Expand All @@ -36,21 +36,61 @@ contract CounterTest is Test {
ousd.rebaseOptOut();
vm.prank(collector);
ousd.rebaseOptIn();


assertEq(ousd.nonRebasingSupply(), 2000 ether);
ousd.delegateYield(pool, collector);
assertEq(ousd.nonRebasingSupply(), 1000 ether, "delegate should decrease rebasing");
assertEq(ousd.nonRebasingSupply(), 1000 ether, "delegate should decrease nonrebasing");
assertEq(ousd.totalSupply(), 5000 ether);
assertEq(ousd.balanceOf(pool), 1000 ether);
assertEq(ousd.balanceOf(collector), 1000 ether);
}

function _show() internal {
console.log(" ..totalSupply: ", ousd.totalSupply());
console.log(" ..nonRebasingSupply: ", ousd.nonRebasingSupply());
console.log(" ..rebasingCredits: ", ousd.rebasingCreditsHighres());
console.log(" ..rebasingCreditsPerToken: ", ousd.rebasingCreditsPerTokenHighres());
}

function test_ChangeSupply() public {
assertEq(ousd.totalSupply(), 6000 ether);
assertEq(ousd.totalSupply(), 5000 ether);
assertEq(ousd.nonRebasingSupply(), 1000 ether);
ousd.changeSupply(7000 ether);
assertEq(ousd.totalSupply(), 7000 ether);
assertEq(ousd.nonRebasingSupply(), 1000 ether);
}

function test_SimpleRebasingCredits() public {
// Create an OUSD with a very simple credits to token ratio.
// This doesn't test rouding, but does make for nice human readable numbers
// to check the directions of things

ousd = new OUSD();
ousd.initialize("", "", address(this), 1e27 / 2);

ousd.mint(matt, 1000 ether);
assertEq(ousd.rebasingCredits(), 500 ether);

ousd.mint(nonrebasing, 1000 ether);
assertEq(ousd.rebasingCredits(), 1000 ether);

vm.prank(nonrebasing);
ousd.rebaseOptOut();
assertEq(ousd.rebasingCredits(), 500 ether, "rebaseOptOut should reducing total rebasing credits");

ousd.burn(matt, 500 ether);
assertEq(ousd.rebasingCredits(), 250 ether, "rebasing burn should reduce rebasing credits");

ousd.burn(nonrebasing, 500 ether);
assertEq(ousd.rebasingCredits(), 250 ether);

// Add yield
assertEq(ousd.balanceOf(matt), 500 ether, "matt should have 500 OUSD");
ousd.changeSupply(2000 ether);
assertEq(ousd.balanceOf(matt), 1500 ether, "all yield should go to matt");
}

function test_CanDelegateYield() public {
vm.prank(matt);
ousd.rebaseOptOut();
Expand Down Expand Up @@ -80,8 +120,12 @@ contract CounterTest is Test {

function testDelegateYield() public {

console.log(ousd.totalSupply()/1e18);
console.log(ousd.balanceOf(matt)*1/1e18);

ousd.changeSupply(ousd.totalSupply() + 1000 ether);
assertEq(ousd.balanceOf(matt), 100);
assertEq(ousd.balanceOf(matt), 1250 ether);
assertEq(ousd.balanceOf(collector), 1500 ether, "Collecter should have earned both yields");

}

Expand Down

0 comments on commit 9d762b9

Please sign in to comment.