Skip to content

Commit

Permalink
Merge branch 'develop' into features/add-sushi-token
Browse files Browse the repository at this point in the history
  • Loading branch information
ggviana committed Jun 19, 2021
2 parents 6d16245 + 9439d65 commit 9ab4893
Show file tree
Hide file tree
Showing 14 changed files with 82 additions and 299 deletions.
52 changes: 0 additions & 52 deletions abi/BlackScholes.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,45 +10,6 @@
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "PRECISION_UNIT",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "UNIT",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "UNIT_TO_PRECISION_FACTOR",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
Expand Down Expand Up @@ -152,18 +113,5 @@
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "precisionDecimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
}
]
125 changes: 39 additions & 86 deletions contracts/amm/BlackScholes.sol
Original file line number Diff line number Diff line change
@@ -1,34 +1,26 @@
// SPDX-License-Identifier: agpl-3.0

// solhint-disable var-name-mixedcase
pragma solidity 0.6.12;
pragma solidity 0.8.4;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "../interfaces/INormalDistribution.sol";

import "../lib/FixidityLib.sol";
import "../lib/LogarithmLib.sol";
import "../interfaces/IBlackScholes.sol";

import "prb-math/contracts/PRBMathSD59x18.sol";
import "prb-math/contracts/PRBMathUD60x18.sol";

/**
* @title BlackScholes
* @author Pods Finance
* @notice Black-Scholes calculus
*/
contract BlackScholes is IBlackScholes {
using SafeMath for uint256;
using FixidityLib for int256;
using LogarithmLib for int256;
using PRBMathSD59x18 for int256;
using PRBMathUD60x18 for uint256;

INormalDistribution public immutable normalDistribution;

uint8 public constant decimals = 18; // solhint-disable-line const-name-snakecase
uint8 public constant precisionDecimals = 24; // solhint-disable-line const-name-snakecase

uint256 public constant UNIT = 10**uint256(decimals);
uint256 public constant PRECISION_UNIT = 10**uint256(precisionDecimals);

uint256 public constant UNIT_TO_PRECISION_FACTOR = 10**uint256(precisionDecimals - decimals);

constructor(address _normalDistribution) public {
require(_normalDistribution != address(0), "BlackScholes: Invalid normalDistribution");
Expand All @@ -52,20 +44,26 @@ contract BlackScholes is IBlackScholes {
uint256 time,
int256 riskFree
) public override view returns (uint256) {
(int256 d1, int256 d2) = _getZScores(_uintToInt(spotPrice), _uintToInt(strikePrice), iv, time, riskFree);
(int256 d1, int256 d2) = _getZScores(
_uintToInt(spotPrice),
_uintToInt(strikePrice),
_uintToInt(iv),
_uintToInt(time),
riskFree
);

uint256 Nd1 = normalDistribution.getProbability(d1, precisionDecimals);
uint256 Nd2 = normalDistribution.getProbability(d2, precisionDecimals);
uint256 Nd1 = normalDistribution.getProbability(d1, decimals);
uint256 Nd2 = normalDistribution.getProbability(d2, decimals);

uint256 get = spotPrice.mul(Nd1).div(PRECISION_UNIT);
uint256 pay = strikePrice.mul(Nd2).div(PRECISION_UNIT);
uint256 get = spotPrice.mul(Nd1);
uint256 pay = strikePrice.mul(Nd2);

if (pay > get) {
// Negative numbers not allowed
return 0;
}

return get.sub(pay);
return get - pay;
}

/**
Expand All @@ -85,20 +83,26 @@ contract BlackScholes is IBlackScholes {
uint256 time,
int256 riskFree
) public override view returns (uint256) {
(int256 d1, int256 d2) = _getZScores(_uintToInt(spotPrice), _uintToInt(strikePrice), iv, time, riskFree);
(int256 d1, int256 d2) = _getZScores(
_uintToInt(spotPrice),
_uintToInt(strikePrice),
_uintToInt(iv),
_uintToInt(time),
riskFree
);

uint256 Nd1 = normalDistribution.getProbability(_additiveInverse(d1), precisionDecimals);
uint256 Nd2 = normalDistribution.getProbability(_additiveInverse(d2), precisionDecimals);
uint256 Nd1 = normalDistribution.getProbability(_additiveInverse(d1), decimals);
uint256 Nd2 = normalDistribution.getProbability(_additiveInverse(d2), decimals);

uint256 get = strikePrice.mul(Nd2).div(PRECISION_UNIT);
uint256 pay = spotPrice.mul(Nd1).div(PRECISION_UNIT);
uint256 get = strikePrice.mul(Nd2);
uint256 pay = spotPrice.mul(Nd1);

if (pay > get) {
// Negative numbers not allowed
return 0;
}

return get.sub(pay);
return get - pay;
}

/**
Expand All @@ -122,75 +126,24 @@ contract BlackScholes is IBlackScholes {
function _getZScores(
int256 spotPrice,
int256 strikePrice,
uint256 iv,
uint256 time,
int256 iv,
int256 time,
int256 riskFree
) internal pure returns (int256 d1, int256 d2) {
uint256 iv2 = _normalized(iv).mul(_normalized(iv)) / PRECISION_UNIT;
int256 iv2 = iv.mul(iv);

int256 A = _cachedLn(spotPrice.divide(strikePrice));
int256 B = (_uintToInt(iv2 / 2)).add(_normalized(riskFree)).multiply(_normalized(_uintToInt(time)));
int256 A = spotPrice.div(strikePrice).ln();
int256 B = (iv2 / 2 + riskFree).mul(time);

int256 n = A.add(B);
int256 n = A + B;
int256 d = iv.mul(time.sqrt());

uint256 sqrtTime = _sqrt(_normalized(time));
uint256 d = iv.mul(sqrtTime) / UNIT_TO_PRECISION_FACTOR;

d1 = n.divide(_uintToInt(d));
d2 = d1.subtract(_uintToInt(d));
d1 = n.div(d);
d2 = d1 - d;

return (d1, d2);
}

/**
* @dev Square root
* @dev See the following for reference https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
*
* @param x The value
* @return y The square root of x
*/
function _sqrt(uint256 x) internal pure returns (uint256 y) {
uint256 z = (x.add(1)) / 2;
y = x;
while (z < y) {
y = z;
z = (x / z).add(z) / 2;
}
}

/**
* @dev Same as natural logarithm but hard-coded for known x values
* @param x The value to be ln
* @return ln of x
*/
function _cachedLn(int256 x) internal pure returns (int256) {
return LogarithmLib.ln(x);
}

/**
* Normalizes uint numbers to precision uint
*/
function _normalized(uint256 x) internal pure returns (uint256) {
return x.mul(UNIT_TO_PRECISION_FACTOR);
}

/**
* Normalizes int numbers to precision int
*/
function _normalized(int256 x) internal pure returns (int256) {
return _mulInt(x, int256(UNIT_TO_PRECISION_FACTOR));
}

/**
* Safe math multiplications for Int.
*/

function _mulInt(int256 a, int256 b) internal pure returns (int256) {
int256 c = a * b;
require(a == 0 || c / a == b, "BlackScholes: multInt overflow");
return c;
}

/**
* Convert uint256 to int256 taking in account overflow.
*/
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IBlackScholes.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: agpl-3.0

pragma solidity 0.6.12;
pragma solidity >=0.6.12;

interface IBlackScholes {
function getCallPrice(
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/INormalDistribution.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: agpl-3.0

pragma solidity 0.6.12;
pragma solidity >=0.6.12;

interface INormalDistribution {
function getProbability(int256 z, uint256 decimals) external view returns (uint256);
Expand Down
17 changes: 12 additions & 5 deletions hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,19 @@ module.exports = {
}
},
solidity: {
version: '0.6.12',
settings: {
optimizer: {
enabled: true
compilers: [
{
version: '0.6.12',
settings: {
optimizer: {
enabled: true
}
}
},
{
version: '0.8.4'
}
}
]
},
mocha: {
timeout: 20000000001
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
},
"dependencies": {
"@openzeppelin/contracts": "3.0.1",
"bignumber.js": "9.0.0"
"bignumber.js": "9.0.0",
"prb-math": "2.0.1"
},
"husky": {
"hooks": {
Expand Down
46 changes: 10 additions & 36 deletions tasks/amm/deployBS.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,17 @@

const saveJSON = require('../utils/saveJSON')
const verifyContract = require('../utils/verify')
const validateAddress = require('../utils/validateAddress')

internalTask('deployBS', 'Deploy Black Scholes')
.addFlag('verify', 'if true, it should verify the contract after the deployment')
.addParam('normaldist', 'Normal Distribution Address')
.addOptionalParam('fixidity', 'fixidity address to use')
.addOptionalParam('logarithm', 'logarithm address to use')
.addOptionalParam('exponent', 'exponent address to use')
.addFlag('deploylibs', 'Activate this parameter if you want to deploy libs')
.setAction(async ({ normaldist, fixidity, logarithm, deploylibs, verify }, hre) => {
const path = `../../deployments/${hre.network.name}.json`
let libs = {
fixidity,
logarithm
}

if (deploylibs) {
libs = await run('deployLibs')
}

console.log('libs', libs)

const libObj = {
FixidityLib: libs.fixidity,
LogarithmLib: libs.logarithm
}

const BlackScholes = await hre.ethers.getContractFactory('BlackScholes', {
libraries: libObj
.setAction(async ({ normaldist, verify }, hre) => {
validateAddress(normaldist, 'normaldist')

const bsAddress = await hre.run('deploy', {
name: 'BlackScholes',
args: [normaldist],
save: true,
verify
})

const bs = await BlackScholes.deploy(normaldist)
await bs.deployed()
await saveJSON(path, { BlackScholes: bs.address })

if (verify) {
await verifyContract(hre, bs.address, [normaldist], libObj)
}
console.log('BlackScholes Address', bs.address)
return bs.address
return bsAddress
})
22 changes: 0 additions & 22 deletions tasks/amm/deployLibs.js

This file was deleted.

Loading

0 comments on commit 9ab4893

Please sign in to comment.