Skip to content

Commit

Permalink
Merge branch 'dev' into feat/script
Browse files Browse the repository at this point in the history
  • Loading branch information
wei3erHase authored May 16, 2024
2 parents c382f96 + 8c76c6c commit 47daf48
Show file tree
Hide file tree
Showing 3 changed files with 346 additions and 69 deletions.
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ src = 'src/interfaces/'

[fuzz]
runs = 1000
max_test_rejects = 1000000
max_test_rejects = 1_000_000

[rpc_endpoints]
mainnet = "${MAINNET_RPC}"
Expand Down
154 changes: 87 additions & 67 deletions src/contracts/BNum.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,114 +17,134 @@ import './BConst.sol';

contract BNum is BConst {
function btoi(uint256 a) internal pure returns (uint256) {
return a / BONE;
unchecked {
return a / BONE;
}
}

function bfloor(uint256 a) internal pure returns (uint256) {
return btoi(a) * BONE;
unchecked {
return btoi(a) * BONE;
}
}

function badd(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, 'ERR_ADD_OVERFLOW');
return c;
unchecked {
uint256 c = a + b;
require(c >= a, 'ERR_ADD_OVERFLOW');
return c;
}
}

function bsub(uint256 a, uint256 b) internal pure returns (uint256) {
(uint256 c, bool flag) = bsubSign(a, b);
require(!flag, 'ERR_SUB_UNDERFLOW');
return c;
unchecked {
(uint256 c, bool flag) = bsubSign(a, b);
require(!flag, 'ERR_SUB_UNDERFLOW');
return c;
}
}

function bsubSign(uint256 a, uint256 b) internal pure returns (uint256, bool) {
if (a >= b) {
return (a - b, false);
} else {
return (b - a, true);
unchecked {
if (a >= b) {
return (a - b, false);
} else {
return (b - a, true);
}
}
}

function bmul(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c0 = a * b;
require(a == 0 || c0 / a == b, 'ERR_MUL_OVERFLOW');
uint256 c1 = c0 + (BONE / 2);
require(c1 >= c0, 'ERR_MUL_OVERFLOW');
uint256 c2 = c1 / BONE;
return c2;
unchecked {
uint256 c0 = a * b;
require(a == 0 || c0 / a == b, 'ERR_MUL_OVERFLOW');
uint256 c1 = c0 + (BONE / 2);
require(c1 >= c0, 'ERR_MUL_OVERFLOW');
uint256 c2 = c1 / BONE;
return c2;
}
}

function bdiv(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, 'ERR_DIV_ZERO');
uint256 c0 = a * BONE;
require(a == 0 || c0 / a == BONE, 'ERR_DIV_INTERNAL'); // bmul overflow
uint256 c1 = c0 + (b / 2);
require(c1 >= c0, 'ERR_DIV_INTERNAL'); // badd require
uint256 c2 = c1 / b;
return c2;
unchecked {
require(b != 0, 'ERR_DIV_ZERO');
uint256 c0 = a * BONE;
require(a == 0 || c0 / a == BONE, 'ERR_DIV_INTERNAL'); // bmul overflow
uint256 c1 = c0 + (b / 2);
require(c1 >= c0, 'ERR_DIV_INTERNAL'); // badd require
uint256 c2 = c1 / b;
return c2;
}
}

// DSMath.wpow
function bpowi(uint256 a, uint256 n) internal pure returns (uint256) {
uint256 z = n % 2 != 0 ? a : BONE;
unchecked {
uint256 z = n % 2 != 0 ? a : BONE;

for (n /= 2; n != 0; n /= 2) {
a = bmul(a, a);
for (n /= 2; n != 0; n /= 2) {
a = bmul(a, a);

if (n % 2 != 0) {
z = bmul(z, a);
if (n % 2 != 0) {
z = bmul(z, a);
}
}
return z;
}
return z;
}

// Compute b^(e.w) by splitting it into (b^e)*(b^0.w).
// Use `bpowi` for `b^e` and `bpowK` for k iterations
// of approximation of b^0.w
function bpow(uint256 base, uint256 exp) internal pure returns (uint256) {
require(base >= MIN_BPOW_BASE, 'ERR_BPOW_BASE_TOO_LOW');
require(base <= MAX_BPOW_BASE, 'ERR_BPOW_BASE_TOO_HIGH');
unchecked {
require(base >= MIN_BPOW_BASE, 'ERR_BPOW_BASE_TOO_LOW');
require(base <= MAX_BPOW_BASE, 'ERR_BPOW_BASE_TOO_HIGH');

uint256 whole = bfloor(exp);
uint256 remain = bsub(exp, whole);
uint256 whole = bfloor(exp);
uint256 remain = bsub(exp, whole);

uint256 wholePow = bpowi(base, btoi(whole));
uint256 wholePow = bpowi(base, btoi(whole));

if (remain == 0) {
return wholePow;
}
if (remain == 0) {
return wholePow;
}

uint256 partialResult = bpowApprox(base, remain, BPOW_PRECISION);
return bmul(wholePow, partialResult);
uint256 partialResult = bpowApprox(base, remain, BPOW_PRECISION);
return bmul(wholePow, partialResult);
}
}

function bpowApprox(uint256 base, uint256 exp, uint256 precision) internal pure returns (uint256) {
// term 0:
uint256 a = exp;
(uint256 x, bool xneg) = bsubSign(base, BONE);
uint256 term = BONE;
uint256 sum = term;
bool negative = false;

// term(k) = numer / denom
// = (product(a - i - 1, i=1-->k) * x^k) / (k!)
// each iteration, multiply previous term by (a-(k-1)) * x / k
// continue until term is less than precision
for (uint256 i = 1; term >= precision; i++) {
uint256 bigK = i * BONE;
(uint256 c, bool cneg) = bsubSign(a, bsub(bigK, BONE));
term = bmul(term, bmul(c, x));
term = bdiv(term, bigK);
if (term == 0) break;

if (xneg) negative = !negative;
if (cneg) negative = !negative;
if (negative) {
sum = bsub(sum, term);
} else {
sum = badd(sum, term);
unchecked {
// term 0:
uint256 a = exp;
(uint256 x, bool xneg) = bsubSign(base, BONE);
uint256 term = BONE;
uint256 sum = term;
bool negative = false;

// term(k) = numer / denom
// = (product(a - i - 1, i=1-->k) * x^k) / (k!)
// each iteration, multiply previous term by (a-(k-1)) * x / k
// continue until term is less than precision
for (uint256 i = 1; term >= precision; i++) {
uint256 bigK = i * BONE;
(uint256 c, bool cneg) = bsubSign(a, bsub(bigK, BONE));
term = bmul(term, bmul(c, x));
term = bdiv(term, bigK);
if (term == 0) break;

if (xneg) negative = !negative;
if (cneg) negative = !negative;
if (negative) {
sum = bsub(sum, term);
} else {
sum = badd(sum, term);
}
}
}

return sum;
return sum;
}
}
}
Loading

0 comments on commit 47daf48

Please sign in to comment.