Skip to content
This repository has been archived by the owner on Dec 5, 2021. It is now read-only.

Commit

Permalink
fix fee-test.ts and add sqrt off-chain for stable-test.ts (#330)
Browse files Browse the repository at this point in the history
Co-authored-by: Mehul Agarwal <[email protected]>
  • Loading branch information
agarwalml and Mehul Agarwal authored Sep 6, 2021
1 parent f391f1f commit 9328880
Show file tree
Hide file tree
Showing 28 changed files with 2,683 additions and 28 deletions.
6 changes: 3 additions & 3 deletions packages/omgx/offchain-prototype/contracts/HelloTuring.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.7.0;
pragma solidity 0.6.12;

import "hardhat/console.sol";

Expand All @@ -15,7 +15,7 @@ contract HelloTuring {
mapping (address => string) locales;
mapping (address => string) cachedGreetings;

constructor(address _helper) {
constructor(address _helper) public {
console.log("Deploying a contract with helper address:", _helper);
helperAddr = _helper;
myHelper = Helper(helperAddr);
Expand Down Expand Up @@ -59,7 +59,7 @@ contract HelloTuring {

return greeting;
}

/* Example of performing off-chain calculations on numeric data types */
function AddNumbers(uint112 a, uint112 b) public view returns (uint256) {
uint256 c;
Expand Down
239 changes: 239 additions & 0 deletions packages/omgx/offchain-prototype/contracts/StableSwap.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.6.12;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/math/SignedSafeMath.sol";
import "hardhat/console.sol";


interface Helper {
function TuringCall(uint32 method_idx, bytes memory) view external returns (bytes memory);
}

/**
* @title Storage
* @dev Store & retrieve value in a variable
*/


contract StableSwap {

using SafeMath for uint256;
using SignedSafeMath for int256;

uint256 public x;
uint256 public y;
uint256 public k;
uint256 public A;
address helperAddr;
Helper myHelper;

mapping (address => string) locales;
mapping (address => string) cachedGreetings;

/**
* @dev initialize x tokens, y tokens to form invariant with A = 0
* @param _x, _y balances such that val(_x) = val(_y)
*/
constructor(
address _helper,
uint256 _x,
uint256 _y
)
public
{
console.log("Deploying a contract with helper address:", _helper);
helperAddr = _helper;
myHelper = Helper(helperAddr);

x = _x;
y = _y;
k = x.mul(y);
A = 0;
}


// /**
// * @dev initialize x tokens, y tokens to form invariant with A = 0
// * @param _x, _y balances such that val(_x) = val(_y)
// */
// function initializeLiquidity(uint256 _x, uint256 _y) public {
// require(_x > 0 && _y > 0);
// x = _x;
// y = _y;
// k = x*y;
// A = 0;
// }


/**
* @dev add x tokens, y tokens to update invariant k with same A
* @param x_in, y_in balances such that val(x_in) = val(y_in)
*/
function addLiquidity(uint256 x_in, uint256 y_in) public {
require(x_in > 0 && y_in > 0);
x = x.add(x_in);
y = y.add(y_in);
k = x.mul(y);
}

/**
* @dev remove x tokens, y tokens to update invariant k with same A
* @param percOut such that percentage of liquidity removed
*/
function removeLiquidity(uint256 percOut) public returns (uint256 x_back, uint256 y_back) {
require(percOut > 0 && percOut <= 100);
x_back = (x.mul(percOut)).div(100);
y_back = (y.mul(percOut)).div(100);
x = x.sub(x_back);
y = y.sub(y_back);
k = x.mul(y);
}

/**
* @dev Change A for Stable Swap equation
* @param _A dictating shape of stable swap curve
*/
function changeA(uint256 _A) public {
require(A >= 0);
A = _A;
}

/**
* @dev Square root function
* @param a number to find the square root of (rounded down?)
* Adapted from https://github.com/ethereum/dapp-bin/pull/50/files (an open PR for solidity)
*/
function sqrt(uint a) public returns (uint b) {
require(a >= 0);
// if (a == 0) return 0;
// else if (a <= 3) return 1;
// uint c = (a.add(1)).div(2);
// b = a;
// while (c < b)
// {
// b = c;
// c = (a.div(c).add(c)).div(2);
// }
uint256 c;
bytes memory encRequest = abi.encode(a);
bytes memory encResponse = myHelper.TuringCall(1, encRequest);
c = abi.decode(encResponse,(uint256));
return c;
}

/**
* @dev Absolute value function
* @param d number to find the square root of (rounded down?)
* Adapted from https://ethereum.stackexchange.com/questions/84390/absolute-value-in-solidity/
*/
function abs(int256 d) private pure returns (int256 val) {
val = ((d >= 0)? d : -d);
}

/**
* @dev Safe Power function
* @param base, exponent to find base^(exponent)
* Adapted from https://forum.openzeppelin.com/t/does-safemath-library-need-a-safe-power-function/871/8
*/
function pow(int256 base, int256 exponent) public pure returns (int256) {
if (exponent == 0) {
return 1;
}
else if (exponent == 1) {
return base;
}
else if (base == 0 && exponent != 0) {
return 0;
}
else {
int256 z = base;
for (int256 i = 1; i < exponent; i++)
z = z.mul(base);
return z;
}
}

/**
* @dev Boolean function enforcing stable swap invariant
*/
function invariant() public returns (bool pass){
require(x > 0 && x <= k);
require(y > 0 && y <= k);
uint256 rootK = sqrt(k);
uint256 LHS = ((A.mul(4)).mul(x.add(y))).add(rootK.mul(2));
uint256 RHS = ((A.mul(4)).mul(rootK.mul(2))).add((uint256(pow(int256(rootK.mul(2)),3))).div((x.mul(4)).mul(y)));
pass = (abs(int256(LHS) - int256(RHS)) < 50);
}

/**
* @dev Swap x for y according to stable swap invariant
* @param x_in to return y_out
*/
function swap_x(uint256 x_in) public returns (uint256 y_out){
uint256 newX = x.add(x_in);
uint256 a = A.mul(4);
uint256 K = (sqrt(k)).mul(2);
uint256 newY;

int256 alpha = int256((a.mul(4)).mul(newX));
int256 beta = (int256((a.mul(4)).mul(uint256(pow(int256(newX),2))))).add(int256((newX.mul(4)).mul(K))).sub(int256(((a.mul(4)).mul(K).mul(newX))));
int256 gamma = -(pow(int256(K),3));

// Solving quadratic

int256 d = (beta.mul(beta)).sub((alpha.mul(4)).mul(gamma));
int256 sqrtD = int256(sqrt(uint256(abs(d))));

if(d >= 0){
int256 root1 = ((-beta).add(sqrtD)).div(alpha.mul(2));
int256 root2 = ((-beta).sub(sqrtD)).div(alpha.mul(2));
newY = uint256((root1 > 0 && root1 <= int256(k))? root1 : root2);
//Changing variables for future
x = newX;
y = newY;
assert(invariant());
y_out = y.sub(newY);
}
else{
revert("Wrong swap amount provided");
}
}

/**
* @dev Swap y for x according to stable swap invariant
* @param y_in to return x_out
*/
function swap_y(uint256 y_in) public returns (uint256 x_out){
uint256 newY = y.add(y_in);
uint256 a = (A.mul(4));
uint256 K = sqrt(k).mul(2);
uint256 newX;

int256 alpha = int256((a.mul(4)).mul(newY));
int256 beta = (int256((a.mul(4)).mul(uint256(pow(int256(newY),2))))).add(int256((newY.mul(4)).mul(K))).sub(int256(((a.mul(4)).mul(K).mul(newY))));
int256 gamma = -(pow(int256(K),3));

// Solving quadratic

int256 d = (beta.mul(beta)).sub((alpha.mul(4)).mul(gamma));
int256 sqrtD = int256(sqrt(uint256(abs(d))));

if(d >= 0){
int256 root1 = ((-beta).add(sqrtD)).div(alpha.mul(2));
int256 root2 = ((-beta).sub(sqrtD)).div(alpha.mul(2));
newX = uint256((root1 > 0 && root1 <= int256(k))? root1 : root2);

//Changing variables for future
x = newX;
y = newY;
assert(invariant());
x_out = x.sub(newX);
}
else{
revert("Wrong swap amount provided");
}
}
}

32 changes: 16 additions & 16 deletions packages/omgx/offchain-prototype/contracts/TuringHelper.sol
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
//SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.7.0;
pragma solidity 0.6.12;

import "hardhat/console.sol";

contract TuringHelper {
bytes data_URL;
TuringHelper Self;
bytes[] methods;
constructor(string memory _url) {
bytes[] methods;

constructor(string memory _url) public {
console.log("Deploying a helper contract with data source:", _url);
data_URL = bytes(_url);
Self = TuringHelper(address(this));
Expand Down Expand Up @@ -60,23 +60,23 @@ contract TuringHelper {
// Constrain these to simplify the RLP encoding logic.
require (data_URL.length < 65536, "data_URL is too long");
require (payload.length < 65536, "payload is too long");

uint32 l1 = uint32(data_URL.length);
uint32 l2 = uint32(method.length);
uint32 l3 = uint32(payload.length);

uint32 pLen = 1 + l1 + l2 + l3; // Payload length + inner headers
uint32 hLen = 1; // Extra length of list header

uint8[4] memory pre;

(pre[1], pLen) = _lenCalc1(data_URL, pLen);
(pre[2], pLen) = _lenCalc1(method, pLen);
(pre[3], pLen) = _lenCalc1(payload, pLen);

// We now have the total length of the three items which will be in the list.
// This determines the encoding required for the list header

if (pLen > 65535) {
hLen += 3;
pre[0] = 0xfa;
Expand All @@ -89,13 +89,13 @@ contract TuringHelper {
} else {
pre[0] = 0xc0 + uint8(pLen);
}

bytes memory result = new bytes(hLen + pLen + prefix.length);

for (i=0; i < prefix.length; i++) result[j++] = prefix[i];

result[j++] = bytes1(pre[0]);

if (pre[0] > 0xf9) {
result[j++] = bytes1(uint8(pLen / 65536));
pLen = pLen % 65536;
Expand All @@ -107,9 +107,9 @@ contract TuringHelper {
if (pre[0] > 0xf7) {
result[j++] = bytes1(uint8(pLen));
}

result[j++] = request_version;

result[j++] = bytes1(pre[1]);
if (pre[1] > 0xb8) {
result[j++] = bytes1(uint8(l1 / 256));
Expand All @@ -119,7 +119,7 @@ contract TuringHelper {
result[j++] = bytes1(uint8(l1));
}
for (i=0; i<data_URL.length; i++) result[j++] = data_URL[i];

result[j++] = bytes1(pre[2]);
if (pre[2] > 0xb8) {
result[j++] = bytes1(uint8(l2 / 256));
Expand Down
Loading

0 comments on commit 9328880

Please sign in to comment.