Skip to content

Commit

Permalink
feat: double check calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenvaleri committed Nov 9, 2024
1 parent 8decaff commit ddebc26
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 23 deletions.
2 changes: 1 addition & 1 deletion contracts/script/PointTokenVault.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ contract PointTokenVaultScripts is BatchScript {

// Update merkle root
vm.startBroadcast(MAINNET_MERKLE_UPDATER);
vaultV0_1_0.updateRoot(0x8add61929f9038b9b001852126409672b6c4c12161be6caee4c4ce44fe59538c);
vaultV0_1_0.updateRoot(0xa1c76e2c6f7ac8300b288ff758b8a83c4a19e12780ca7ac5f61182f64ef8edf6);
vm.stopBroadcast();
}

Expand Down
188 changes: 166 additions & 22 deletions contracts/test/SetRedemptionENA4Nov24.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import {ERC20} from "solmate/test/utils/mocks/MockERC20.sol";

import {PointTokenVault} from "../PointTokenVault.sol";
import {PointTokenVaultScripts} from "../script/PointTokenVault.s.sol";
import {PToken} from "../PToken.sol";

contract SetRedemptionENA4Nov24Test is Test {
PointTokenVault vaultV0_1_0 = PointTokenVault(payable(0x1EeEBa76f211C4Dce994b9c5A74BDF25DB649Fa1));
PToken kpSats = PToken(0xdFa21ceC8A46386F5d36F4b07E18BcCcA59f425B);
bytes32 pointsId = LibString.packTwo("Rumpel kPoint: Ethena S2", "kpSATS");

mapping(address => bool) userAccountedFor; // pToken holder accounted for

function setUp() public {
string memory MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL");
uint256 forkId = vm.createFork(MAINNET_RPC_URL, 21_112_610); // Block mined at Nov-04-2024 06:51:59 AM +UTC
Expand All @@ -23,11 +27,11 @@ contract SetRedemptionENA4Nov24Test is Test {

function test_RedemptionRights1() public {
bytes32[] memory proof = new bytes32[](5);
proof[0] = 0x6258fb3ee01fe8edb76a1ee2cb317cd32b8464c63e31903826acd02863982f31;
proof[1] = 0xd9d5035f478e73b0e33ae1677a34fb215dd9f25d858d17265608acd57f066e48;
proof[2] = 0x65c2bc0496edc30a605d1618f867da252e88358e98d08d80ad0d485df4439055;
proof[3] = 0x9c4c736ac69fbbc0f510cbee646cfcb0a5186004dbb3c577d7c3ab658ddcf209;
proof[4] = 0x2129557061359b11c571b9a63f6363b144b6ae40058d9731d0e165463fc18438;
proof[0] = 0x4e0230e7a7546148f373efe52256490c04ea0019e199f2256a375e75cf2b6b96;
proof[1] = 0xfaca43636023a73bf06295aa693c262efe0bb3231357a68b8ad7eec7e901c8ef;
proof[2] = 0x03c4c7f992659d2c405eb95248d21dfd7f66c7bdef49d9d33cb97b0b5d35c37a;
proof[3] = 0x617d803c581341b5720c7932932ca45ebfb90e87a122f801b0d5fe53b747db51;
proof[4] = 0x620f05d3b25d35da47076de4dceb31f95567ff863138ae7d1fe416ea0bc2ff41;

address USER = 0x25E426b153e74Ab36b2685c3A464272De60888Ae;
uint256 AMOUNT = 26396311093240867247;
Expand All @@ -54,11 +58,11 @@ contract SetRedemptionENA4Nov24Test is Test {

function test_RedemptionRights1_ClaimTooMuch() public {
bytes32[] memory proof = new bytes32[](5);
proof[0] = 0x6258fb3ee01fe8edb76a1ee2cb317cd32b8464c63e31903826acd02863982f31;
proof[1] = 0xd9d5035f478e73b0e33ae1677a34fb215dd9f25d858d17265608acd57f066e48;
proof[2] = 0x65c2bc0496edc30a605d1618f867da252e88358e98d08d80ad0d485df4439055;
proof[3] = 0x9c4c736ac69fbbc0f510cbee646cfcb0a5186004dbb3c577d7c3ab658ddcf209;
proof[4] = 0x2129557061359b11c571b9a63f6363b144b6ae40058d9731d0e165463fc18438;
proof[0] = 0x4e0230e7a7546148f373efe52256490c04ea0019e199f2256a375e75cf2b6b96;
proof[1] = 0xfaca43636023a73bf06295aa693c262efe0bb3231357a68b8ad7eec7e901c8ef;
proof[2] = 0x03c4c7f992659d2c405eb95248d21dfd7f66c7bdef49d9d33cb97b0b5d35c37a;
proof[3] = 0x617d803c581341b5720c7932932ca45ebfb90e87a122f801b0d5fe53b747db51;
proof[4] = 0x620f05d3b25d35da47076de4dceb31f95567ff863138ae7d1fe416ea0bc2ff41;

address USER = 0x25E426b153e74Ab36b2685c3A464272De60888Ae;
uint256 TOTAL_CLAIMABLE = 26396311093240867247;
Expand All @@ -69,21 +73,161 @@ contract SetRedemptionENA4Nov24Test is Test {
vaultV0_1_0.redeemRewards(PointTokenVault.Claim(pointsId, TOTAL_CLAIMABLE, CLAIM_AMOUNT, proof), USER);
}

function test_NormalPTokenClaim() public {
bytes32[] memory proof = new bytes32[](5);
proof[0] = 0x6a69b863aea1e9a735f460a6fb449a28b7398f958c4792872d7764700936b79d;
proof[1] = 0xf88a43494a509c28f8321582f54b7964fc2232a7f109d49a44631cbcfa5d30a9;
proof[2] = 0x65c2bc0496edc30a605d1618f867da252e88358e98d08d80ad0d485df4439055;
proof[3] = 0x9c4c736ac69fbbc0f510cbee646cfcb0a5186004dbb3c577d7c3ab658ddcf209;
proof[4] = 0x2129557061359b11c571b9a63f6363b144b6ae40058d9731d0e165463fc18438;
struct RedemptionData {
uint256 pTokenBalance;
uint256 claimedPoints;
uint256 totalClaimablePoints;
uint256 unclaimedPoints;
uint256 totalRedeemableBalance;
uint256 currentRedeemableBalance;
}

address USER = 0x24C694d193B19119bcDea9D40a3b0bfaFb281E6D;
uint256 AMOUNT = 152407798291890457882;
struct RedemptionFiles {
string root;
string path;
string alphaDistribution;
string merged;
string balances;
}

vm.prank(USER);
OldVault(address(vaultV0_1_0)).claimPTokens(PointTokenVault.Claim(pointsId, AMOUNT, AMOUNT, proof), USER);
function test_RedemptionRightsCalculatedAmount() public {
uint256 rewardsPerPToken = 63381137368827226;

uint256 expectedRedemptionRights;
uint256 redemptionRightAmount;

RedemptionFiles memory rf;
rf.root = vm.projectRoot();
rf.path = string.concat(rf.root, "/js-scripts/generateRedemptionRights/last-alpha-distribution.json");
rf.alphaDistribution = vm.readFile(rf.path);
rf.path = string.concat(rf.root, "/js-scripts/generateRedemptionRights/out/merged-distribution.json");
rf.merged = vm.readFile(rf.path);
rf.path = string.concat(rf.root, "/js-scripts/generateRedemptionRights/out/ptoken-snapshot-kpsats.json");
rf.balances = vm.readFile(rf.path);

string[] memory users = vm.parseJsonKeys(rf.alphaDistribution,string.concat(".pTokens"));
for(uint256 i=0; i < users.length; i++) {
RedemptionData memory rd;
address user = stringToAddress(users[i]);
userAccountedFor[user] = true;

rd.pTokenBalance = kpSats.balanceOf(user);
rd.claimedPoints = vaultV0_1_0.claimedPTokens(user, pointsId);
rd.totalClaimablePoints = vm.parseJsonUint(
rf.alphaDistribution,
string.concat(".pTokens.", vm.toString(user), ".", vm.toString(pointsId), ".accumulatingPoints")
);

rd.unclaimedPoints = rd. totalClaimablePoints - rd.claimedPoints;
rd.totalRedeemableBalance = rd.pTokenBalance + rd.unclaimedPoints;

// uni overrides
if(user == 0x24C694d193B19119bcDea9D40a3b0bfaFb281E6D){
rd.totalRedeemableBalance += 6487631537430741114;
}
if(user == 0x44Cb2d713BDa3858001f038645fD05E23E5DE03D){
rd.totalRedeemableBalance += 27597767454066598826095;
}

expectedRedemptionRights = rd.totalRedeemableBalance * rewardsPerPToken / 2e18;
try vm.parseJsonUint(
rf.merged,
string.concat(".redemptionRights.", vm.toString(user), ".", vm.toString(pointsId), ".amount")
) returns (uint256 amount) {
redemptionRightAmount = amount;
}
catch {
redemptionRightAmount = 0;
}

assertLe(redemptionRightAmount, expectedRedemptionRights);
assertApproxEqAbs(redemptionRightAmount, expectedRedemptionRights, 1e10);

expectedRedemptionRights = 0;
redemptionRightAmount = 0;
}

// account for users with pToken balances, but no claimable tokens
string[] memory balanceUsers = vm.parseJsonKeys(rf.balances,string.concat(".balances"));
for(uint256 i=0; i < balanceUsers.length; i++) {
address user = stringToAddress(balanceUsers[i]);
if(!userAccountedFor[user]){
RedemptionData memory rd;
userAccountedFor[user] = true;

rd.pTokenBalance = kpSats.balanceOf(user);
rd.totalRedeemableBalance = rd.pTokenBalance;

// uni overrides
if(user == 0x24C694d193B19119bcDea9D40a3b0bfaFb281E6D){
rd.totalRedeemableBalance += 6487631537430741114;
}
if(user == 0x44Cb2d713BDa3858001f038645fD05E23E5DE03D){
rd.totalRedeemableBalance += 27597767454066598826095;
}

expectedRedemptionRights = rd.totalRedeemableBalance * rewardsPerPToken / 2e18;

redemptionRightAmount;
try vm.parseJsonUint(
rf.merged,
string.concat(".redemptionRights.", vm.toString(user), ".", vm.toString(pointsId), ".amount")
) returns (uint256 amount) {
redemptionRightAmount = amount;
}
catch {
redemptionRightAmount = 0;
}

assertLe(redemptionRightAmount, expectedRedemptionRights);
assertApproxEqAbs(redemptionRightAmount, expectedRedemptionRights, 1e10);

expectedRedemptionRights = 0;
redemptionRightAmount = 0;
}
}
}

assertEq(ERC20(address(vaultV0_1_0.pTokens(pointsId))).balanceOf(USER), AMOUNT);
function stringToAddress(string memory _address) internal returns (address) {
// Remove "0x" prefix if present
bytes memory _addressBytes = bytes(_address);
if (_addressBytes.length >= 2 && _addressBytes[0] == "0" && (_addressBytes[1] == "x" || _addressBytes[1] == "X")) {
string memory _cleanAddress = new string(_addressBytes.length - 2);
for(uint i = 0; i < _addressBytes.length - 2; i++) {
bytes(_cleanAddress)[i] = _addressBytes[i + 2];
}
_address = _cleanAddress;
}

// Check if the string length is correct (40 characters for address without 0x)
require(bytes(_address).length == 40, "Invalid address length");

// Convert string to bytes
bytes memory _hexBytes = bytes(_address);
uint160 _parsedAddress = 0;

// Convert each character to its hex value
for(uint i = 0; i < 40; i++) {
bytes1 char = _hexBytes[i];
uint8 digit;

if (uint8(char) >= 48 && uint8(char) <= 57) {
// 0-9
digit = uint8(char) - 48;
} else if (uint8(char) >= 65 && uint8(char) <= 70) {
// A-F
digit = uint8(char) - 55;
} else if (uint8(char) >= 97 && uint8(char) <= 102) {
// a-f
digit = uint8(char) - 87;
} else {
revert("Invalid character in address string");
}

_parsedAddress = _parsedAddress * 16 + digit;
}

return address(_parsedAddress);
}
}

Expand Down
4 changes: 4 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ ffi = true
ast = true
build_info = true
extra_output = ["storageLayout"]
fs_permissions = [{ access = "read", path = "./js-scripts/generateRedemptionRights/last-alpha-distribution.json" },
{ access = "read", path = "./js-scripts/generateRedemptionRights/out/merged-distribution.json" },
{ access = "read", path = "./js-scripts/generateRedemptionRights/out/ptoken-snapshot-kpsats.json" },
{ access = "read", path = "./out/PointTokenVault.sol/PointTokenVault.json" }]

[rpc_endpoints]
sepolia = "${SEPOLIA_RPC_URL}"
Expand Down
24 changes: 24 additions & 0 deletions js-scripts/generateRedemptionRights/countpoints.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { readFileSync } from "fs";

const rewards = 132431200000000000000000 / 1e18;

const data = JSON.parse(
readFileSync(
`${process.cwd()}/js-scripts/generateRedemptionRights/last-alpha-distribution.json`
)
);

const kpSatId =
"0x1852756d70656c206b506f696e743a20457468656e61205332066b7053415453";

const pTokens = data.pTokens;

let total = 0;
for (const user in pTokens) {
console.log(pTokens[user][kpSatId]);
total += pTokens[user][kpSatId].accumulatingPoints;
}
console.log(total);
const totalPTokens = total / 1e18;
const rewardsPerPToken = rewards / totalPTokens;
console.log(rewardsPerPToken * 2);

0 comments on commit ddebc26

Please sign in to comment.