Function to compute nth root
This commit is contained in:
75
contracts/staking/contracts/src/libs/LibMath.sol
Normal file
75
contracts/staking/contracts/src/libs/LibMath.sol
Normal file
@@ -0,0 +1,75 @@
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
|
||||
|
||||
|
||||
library LibMath {
|
||||
|
||||
function _nthRoot(uint256 base, uint256 n) internal pure returns (uint256 root) {
|
||||
assembly {
|
||||
///// Implements Newton's Approximation, derived from Newton's nth Root Algorithm /////
|
||||
// See https://en.wikipedia.org/wiki/Nth_root#nth_root_algorithm
|
||||
// 1. Find greatest power-of-2 <= `value`
|
||||
let m := 0
|
||||
for {let v := base}
|
||||
gt(v, 0)
|
||||
{v := shr(1, v)}
|
||||
{
|
||||
m := add(m, 1)
|
||||
}
|
||||
m := sub(m, 1)
|
||||
|
||||
// 2. Find greatest power-of-2 that, when raised to the power of `n`,
|
||||
// is <= `value`
|
||||
let x := exp(2, div(m, n))
|
||||
|
||||
// 3. Find y such that `x` + `y` = `value`
|
||||
let y := xor(base, exp(2, mul(div(m, n), n)))
|
||||
|
||||
// 4. Run Newton's Approximation to find the root
|
||||
root := add(x, div(y, mul(n, exp(2, mul(div(m, n), sub(n, 1))))))
|
||||
|
||||
/**
|
||||
* Note 1:
|
||||
* On some clients (like ganache), execution freezes when running exponentiation
|
||||
* with a dynamically generated base. Because of this, all exponentiation above
|
||||
* is done base-2.
|
||||
* Example:
|
||||
* Call the solidity function below with `n >= 1` and execution will timeout.
|
||||
*
|
||||
* function repro(uint256 n) public pure returns (uint256) {
|
||||
* uint256 m = 2**n;
|
||||
* return m**n;
|
||||
* }
|
||||
*
|
||||
* Call a similar function with the same input _does not_ timeout:
|
||||
*
|
||||
* function fix(uint256 n) public pure returns (uint256) {
|
||||
* uint256 m = 2**(n*n);
|
||||
* return m;
|
||||
* }
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
33
contracts/staking/contracts/test/LibMathTest.sol
Normal file
33
contracts/staking/contracts/test/LibMathTest.sol
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
|
||||
import "../src/libs/LibMath.sol";
|
||||
|
||||
|
||||
contract LibMathTest {
|
||||
|
||||
function nthRoot(uint256 base, uint256 n) public pure returns (uint256 root) {
|
||||
return LibMath._nthRoot(base, n);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -35,7 +35,7 @@
|
||||
"compile:truffle": "truffle compile"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./generated-artifacts/@(LibZrxToken|MixinStake|MixinVaultCore|Staking|ZrxVault).json",
|
||||
"abis": "./generated-artifacts/@(LibMathTest|LibZrxToken|MixinStake|MixinVaultCore|Staking|ZrxVault).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as LibMathTest from '../generated-artifacts/LibMathTest.json';
|
||||
import * as LibZrxToken from '../generated-artifacts/LibZrxToken.json';
|
||||
import * as MixinStake from '../generated-artifacts/MixinStake.json';
|
||||
import * as MixinVaultCore from '../generated-artifacts/MixinVaultCore.json';
|
||||
@@ -16,4 +17,5 @@ export const artifacts = {
|
||||
LibZrxToken: LibZrxToken as ContractArtifact,
|
||||
MixinVaultCore: MixinVaultCore as ContractArtifact,
|
||||
ZrxVault: ZrxVault as ContractArtifact,
|
||||
LibMathTest: LibMathTest as ContractArtifact,
|
||||
};
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/lib_math_test';
|
||||
export * from '../generated-wrappers/lib_zrx_token';
|
||||
export * from '../generated-wrappers/mixin_stake';
|
||||
export * from '../generated-wrappers/mixin_vault_core';
|
||||
|
@@ -108,6 +108,13 @@ describe('Staking Core', () => {
|
||||
expect(zrxTokenBalanceOfStakerAfterStaking).to.be.bignumber.equal(zrxTokenBalanceOfStakerBeforeStaking.minus(amountToStake).plus(amountToUnstake));
|
||||
}
|
||||
});
|
||||
|
||||
it('nth root', async () => {
|
||||
const base = new BigNumber(1419857);
|
||||
const n = new BigNumber(5);
|
||||
const root = await stakingWrapper.nthRoot(base, n);
|
||||
expect(root).to.be.bignumber.equal(17);
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
|
@@ -8,7 +8,7 @@ import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { ERC20ProxyContract } from '@0x/contracts-asset-proxy';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, StakingContract, ZrxVaultContract } from '../../src';
|
||||
import { artifacts, StakingContract, ZrxVaultContract, LibMathTestContract } from '../../src';
|
||||
|
||||
const expect = chai.expect;
|
||||
|
||||
@@ -21,6 +21,7 @@ export class StakingWrapper {
|
||||
private readonly _zrxTokenContract: DummyERC20TokenContract;
|
||||
private _stakingContractIfExists?: StakingContract;
|
||||
private _zrxVaultContractIfExists?: ZrxVaultContract;
|
||||
private _libMathTestContractIfExists?: LibMathTestContract;
|
||||
|
||||
constructor(provider: Provider, ownerAddres: string, erc20ProxyContract: ERC20ProxyContract, zrxTokenContract: DummyERC20TokenContract) {
|
||||
this._web3Wrapper = new Web3Wrapper(provider);
|
||||
@@ -38,6 +39,10 @@ export class StakingWrapper {
|
||||
this._validateDeployedOrThrow();
|
||||
return this._zrxVaultContractIfExists as ZrxVaultContract;
|
||||
}
|
||||
public getLibMathTestContract(): LibMathTestContract {
|
||||
this._validateDeployedOrThrow();
|
||||
return this._libMathTestContractIfExists as LibMathTestContract;
|
||||
}
|
||||
public async deployAndConfigureContracts(): Promise<void> {
|
||||
// deploy zrx vault
|
||||
const zrxAssetData = assetDataUtils.encodeERC20AssetData(this._zrxTokenContract.address);
|
||||
@@ -59,7 +64,13 @@ export class StakingWrapper {
|
||||
(this._zrxVaultContractIfExists as ZrxVaultContract).address
|
||||
);
|
||||
// set staking contract in zrx vault
|
||||
await this.getZrxVaultContract().setStakingContractAddrsess.awaitTransactionSuccessAsync((this._stakingContractIfExists as StakingContract).address);
|
||||
await (this._zrxVaultContractIfExists as ZrxVaultContract).setStakingContractAddrsess.awaitTransactionSuccessAsync((this._stakingContractIfExists as StakingContract).address);
|
||||
// deploy libmath test
|
||||
this._libMathTestContractIfExists = await LibMathTestContract.deployFrom0xArtifactAsync(
|
||||
artifacts.LibMathTest,
|
||||
this._provider,
|
||||
txDefaults,
|
||||
);
|
||||
}
|
||||
public async stake(holder: string, amount: BigNumber): Promise<BigNumber> {
|
||||
const stakeMinted = await this.getStakingContract().stake.callAsync(amount, {from: holder});
|
||||
@@ -87,6 +98,10 @@ export class StakingWrapper {
|
||||
const balance = await this._zrxTokenContract.balanceOf.callAsync(this.getZrxVaultContract().address);
|
||||
return balance;
|
||||
}
|
||||
public async nthRoot(value: BigNumber, n: BigNumber): Promise<BigNumber> {
|
||||
const output = await this.getLibMathTestContract().nthRoot.callAsync(value, n);
|
||||
return output;
|
||||
}
|
||||
public toBaseUnitAmount(amount: BigNumber | number): BigNumber {
|
||||
const decimals = 18;
|
||||
const amountAsBigNumber = typeof(amount) === 'number' ? new BigNumber(amount) : amount;
|
||||
@@ -97,6 +112,8 @@ export class StakingWrapper {
|
||||
throw new Error('Staking contract not deployed. Call `deployStakingContracts`');
|
||||
} else if (this._zrxVaultContractIfExists === undefined) {
|
||||
throw new Error('ZRX Vault contract not deployed. Call `deployStakingContracts`');
|
||||
} else if (this._libMathTestContractIfExists === undefined) {
|
||||
throw new Error('LibMathTest contract not deployed. Call `deployStakingContracts`');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@
|
||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/LibMathTest.json",
|
||||
"generated-artifacts/LibZrxToken.json",
|
||||
"generated-artifacts/MixinStake.json",
|
||||
"generated-artifacts/MixinVaultCore.json",
|
||||
|
Reference in New Issue
Block a user