/* Copyright: Ambrosus Inc. Email: tech@ambrosus.io This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0. */ pragma solidity ^0.5.0; import "@openzeppelin/contracts/math/SafeMath.sol"; import "./SafeMathExtensions.sol"; library DmpAlgorithm { using SafeMath for uint256; using SafeMath for uint32; using SafeMath for uint64; using SafeMathExtensions for uint256; uint256 public constant DMP_PRECISION = 10000; function qualifyShelterer( bytes32 dmpBaseHash, uint256 dmpLength, uint256 currentRound ) internal pure returns (uint32) { return uint32( uint256(keccak256(abi.encodePacked(dmpBaseHash, currentRound))) .mod(dmpLength) ); } function selectingAtlasTier( bytes32 dmpBaseHash, uint256[] memory atlasCount, uint256[] memory ATLAS_NUMERATOR ) internal pure returns (uint32) { require(atlasCount.length == ATLAS_NUMERATOR.length); uint256[] memory wcd = calculateWcd(atlasCount, ATLAS_NUMERATOR); uint32 tier = selectRandomlyFrom(dmpBaseHash, wcd); return tier; } function calculateDenominator( uint256[] memory atlasCount, uint256[] memory ATLAS_NUMERATOR ) private pure returns (uint256) { uint256 denominator = 0; for (uint256 tier = 0; tier < ATLAS_NUMERATOR.length; tier++) { uint256 elem = atlasCount[tier].mul(ATLAS_NUMERATOR[tier]); denominator = denominator.add(elem); } return denominator; } function calculateWcd(uint256[] memory atlasCount, uint256[] memory ATLAS_NUMERATOR) private pure returns (uint256[] memory) { uint256[] memory wcd = new uint256[](ATLAS_NUMERATOR.length); uint256 currentWCD = 0; uint256 denominator = calculateDenominator(atlasCount, ATLAS_NUMERATOR); for (uint256 tier = 0; tier < ATLAS_NUMERATOR.length; tier++) { uint256 currentNum = atlasCount[tier].mul(ATLAS_NUMERATOR[tier]); currentNum = currentNum.mul(DMP_PRECISION).div(denominator); currentWCD = currentWCD.add(currentNum); wcd[tier] = currentWCD; } for (uint256 tier = ATLAS_NUMERATOR.length - 1; tier >= 0; tier--) { if (wcd[tier] != 0) { wcd[tier] = DMP_PRECISION; break; } } return wcd; } function selectRandomlyFrom(bytes32 dmpBaseHash, uint256[] memory wcd) private pure returns (uint32) { uint256 randomNumber = uint256(dmpBaseHash).mod(DMP_PRECISION); uint32 tier = 0; for (tier = 0; tier < wcd.length; tier++) { if (wcd[tier] != 0 && randomNumber <= wcd[tier]) { break; } } return tier; } }