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