Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 118 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Settle Null | 14971821 | 897 days ago | IN | 0 ETH | 0.01354596 | ||||
Settle Null | 14931164 | 904 days ago | IN | 0 ETH | 0.00174618 | ||||
Settle Null | 14931164 | 904 days ago | IN | 0 ETH | 0.00174618 | ||||
Settle Null | 14931119 | 904 days ago | IN | 0 ETH | 0.01093899 | ||||
Settle Null | 14807846 | 925 days ago | IN | 0 ETH | 0.01354596 | ||||
Settle Null | 14771654 | 931 days ago | IN | 0 ETH | 0.01042599 | ||||
Settle Null | 14596037 | 958 days ago | IN | 0 ETH | 0.01042599 | ||||
Settle Null | 14422289 | 985 days ago | IN | 0 ETH | 0.00550595 | ||||
Settle Null | 14242547 | 1013 days ago | IN | 0 ETH | 0.01597038 | ||||
Settle Null | 14190692 | 1021 days ago | IN | 0 ETH | 0.01385605 | ||||
Settle Null | 14190673 | 1021 days ago | IN | 0 ETH | 0.01349142 | ||||
Settle Null | 13802509 | 1081 days ago | IN | 0 ETH | 0.01896091 | ||||
Settle Null | 13780184 | 1085 days ago | IN | 0 ETH | 0.03973481 | ||||
Settle Null | 13717347 | 1095 days ago | IN | 0 ETH | 0.06727826 | ||||
Settle Null | 13591048 | 1115 days ago | IN | 0 ETH | 0.08787655 | ||||
Settle Null | 13490642 | 1131 days ago | IN | 0 ETH | 0.0431632 | ||||
Settle Null | 13428535 | 1140 days ago | IN | 0 ETH | 0.03064587 | ||||
Settle Null | 13352740 | 1152 days ago | IN | 0 ETH | 0.02224261 | ||||
Settle Null | 13284275 | 1163 days ago | IN | 0 ETH | 0.02370114 | ||||
Settle Null | 13216545 | 1173 days ago | IN | 0 ETH | 0.02432819 | ||||
Settle Null | 13058768 | 1198 days ago | IN | 0 ETH | 0.01381222 | ||||
Settle Null | 12974078 | 1211 days ago | IN | 0 ETH | 0.00419083 | ||||
Settle Null | 12973851 | 1211 days ago | IN | 0 ETH | 0.02085198 | ||||
Settle Null | 12973758 | 1211 days ago | IN | 0 ETH | 0.01691406 | ||||
Settle Null | 12933975 | 1217 days ago | IN | 0 ETH | 0.00799211 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
NullSettlement
Compiler Version
v0.5.11+commit.c082d0b4
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2019-08-16 */ pragma solidity >=0.4.25 <0.6.0; pragma experimental ABIEncoderV2; contract Modifiable { modifier notNullAddress(address _address) { require(_address != address(0)); _; } modifier notThisAddress(address _address) { require(_address != address(this)); _; } modifier notNullOrThisAddress(address _address) { require(_address != address(0)); require(_address != address(this)); _; } modifier notSameAddresses(address _address1, address _address2) { if (_address1 != _address2) _; } } contract SelfDestructible { bool public selfDestructionDisabled; event SelfDestructionDisabledEvent(address wallet); event TriggerSelfDestructionEvent(address wallet); function destructor() public view returns (address); function disableSelfDestruction() public { require(destructor() == msg.sender); selfDestructionDisabled = true; emit SelfDestructionDisabledEvent(msg.sender); } function triggerSelfDestruction() public { require(destructor() == msg.sender); require(!selfDestructionDisabled); emit TriggerSelfDestructionEvent(msg.sender); selfdestruct(msg.sender); } } contract Ownable is Modifiable, SelfDestructible { address public deployer; address public operator; event SetDeployerEvent(address oldDeployer, address newDeployer); event SetOperatorEvent(address oldOperator, address newOperator); constructor(address _deployer) internal notNullOrThisAddress(_deployer) { deployer = _deployer; operator = _deployer; } function destructor() public view returns (address) { return deployer; } function setDeployer(address newDeployer) public onlyDeployer notNullOrThisAddress(newDeployer) { if (newDeployer != deployer) { address oldDeployer = deployer; deployer = newDeployer; emit SetDeployerEvent(oldDeployer, newDeployer); } } function setOperator(address newOperator) public onlyOperator notNullOrThisAddress(newOperator) { if (newOperator != operator) { address oldOperator = operator; operator = newOperator; emit SetOperatorEvent(oldOperator, newOperator); } } function isDeployer() internal view returns (bool) { return msg.sender == deployer; } function isOperator() internal view returns (bool) { return msg.sender == operator; } function isDeployerOrOperator() internal view returns (bool) { return isDeployer() || isOperator(); } modifier onlyDeployer() { require(isDeployer()); _; } modifier notDeployer() { require(!isDeployer()); _; } modifier onlyOperator() { require(isOperator()); _; } modifier notOperator() { require(!isOperator()); _; } modifier onlyDeployerOrOperator() { require(isDeployerOrOperator()); _; } modifier notDeployerOrOperator() { require(!isDeployerOrOperator()); _; } } contract Servable is Ownable { struct ServiceInfo { bool registered; uint256 activationTimestamp; mapping(bytes32 => bool) actionsEnabledMap; bytes32[] actionsList; } mapping(address => ServiceInfo) internal registeredServicesMap; uint256 public serviceActivationTimeout; event ServiceActivationTimeoutEvent(uint256 timeoutInSeconds); event RegisterServiceEvent(address service); event RegisterServiceDeferredEvent(address service, uint256 timeout); event DeregisterServiceEvent(address service); event EnableServiceActionEvent(address service, string action); event DisableServiceActionEvent(address service, string action); function setServiceActivationTimeout(uint256 timeoutInSeconds) public onlyDeployer { serviceActivationTimeout = timeoutInSeconds; emit ServiceActivationTimeoutEvent(timeoutInSeconds); } function registerService(address service) public onlyDeployer notNullOrThisAddress(service) { _registerService(service, 0); emit RegisterServiceEvent(service); } function registerServiceDeferred(address service) public onlyDeployer notNullOrThisAddress(service) { _registerService(service, serviceActivationTimeout); emit RegisterServiceDeferredEvent(service, serviceActivationTimeout); } function deregisterService(address service) public onlyDeployer notNullOrThisAddress(service) { require(registeredServicesMap[service].registered); registeredServicesMap[service].registered = false; emit DeregisterServiceEvent(service); } function enableServiceAction(address service, string memory action) public onlyDeployer notNullOrThisAddress(service) { require(registeredServicesMap[service].registered); bytes32 actionHash = hashString(action); require(!registeredServicesMap[service].actionsEnabledMap[actionHash]); registeredServicesMap[service].actionsEnabledMap[actionHash] = true; registeredServicesMap[service].actionsList.push(actionHash); emit EnableServiceActionEvent(service, action); } function disableServiceAction(address service, string memory action) public onlyDeployer notNullOrThisAddress(service) { bytes32 actionHash = hashString(action); require(registeredServicesMap[service].actionsEnabledMap[actionHash]); registeredServicesMap[service].actionsEnabledMap[actionHash] = false; emit DisableServiceActionEvent(service, action); } function isRegisteredService(address service) public view returns (bool) { return registeredServicesMap[service].registered; } function isRegisteredActiveService(address service) public view returns (bool) { return isRegisteredService(service) && block.timestamp >= registeredServicesMap[service].activationTimestamp; } function isEnabledServiceAction(address service, string memory action) public view returns (bool) { bytes32 actionHash = hashString(action); return isRegisteredActiveService(service) && registeredServicesMap[service].actionsEnabledMap[actionHash]; } function hashString(string memory _string) internal pure returns (bytes32) { return keccak256(abi.encodePacked(_string)); } function _registerService(address service, uint256 timeout) private { if (!registeredServicesMap[service].registered) { registeredServicesMap[service].registered = true; registeredServicesMap[service].activationTimestamp = block.timestamp + timeout; } } modifier onlyActiveService() { require(isRegisteredActiveService(msg.sender)); _; } modifier onlyEnabledServiceAction(string memory action) { require(isEnabledServiceAction(msg.sender, action)); _; } } library SafeMathIntLib { int256 constant INT256_MIN = int256((uint256(1) << 255)); int256 constant INT256_MAX = int256(~((uint256(1) << 255))); function div(int256 a, int256 b) internal pure returns (int256) { require(a != INT256_MIN || b != - 1); return a / b; } function mul(int256 a, int256 b) internal pure returns (int256) { require(a != - 1 || b != INT256_MIN); require(b != - 1 || a != INT256_MIN); int256 c = a * b; require((b == 0) || (c / b == a)); return c; } function sub(int256 a, int256 b) internal pure returns (int256) { require((b >= 0 && a - b <= a) || (b < 0 && a - b > a)); return a - b; } function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; require((b >= 0 && c >= a) || (b < 0 && c < a)); return c; } function div_nn(int256 a, int256 b) internal pure returns (int256) { require(a >= 0 && b > 0); return a / b; } function mul_nn(int256 a, int256 b) internal pure returns (int256) { require(a >= 0 && b >= 0); int256 c = a * b; require(a == 0 || c / a == b); require(c >= 0); return c; } function sub_nn(int256 a, int256 b) internal pure returns (int256) { require(a >= 0 && b >= 0 && b <= a); return a - b; } function add_nn(int256 a, int256 b) internal pure returns (int256) { require(a >= 0 && b >= 0); int256 c = a + b; require(c >= a); return c; } function abs(int256 a) public pure returns (int256) { return a < 0 ? neg(a) : a; } function neg(int256 a) public pure returns (int256) { return mul(a, - 1); } function toNonZeroInt256(uint256 a) public pure returns (int256) { require(a > 0 && a < (uint256(1) << 255)); return int256(a); } function toInt256(uint256 a) public pure returns (int256) { require(a >= 0 && a < (uint256(1) << 255)); return int256(a); } function toUInt256(int256 a) public pure returns (uint256) { require(a >= 0); return uint256(a); } function isNonZeroPositiveInt256(int256 a) public pure returns (bool) { return (a > 0); } function isPositiveInt256(int256 a) public pure returns (bool) { return (a >= 0); } function isNonZeroNegativeInt256(int256 a) public pure returns (bool) { return (a < 0); } function isNegativeInt256(int256 a) public pure returns (bool) { return (a <= 0); } function clamp(int256 a, int256 min, int256 max) public pure returns (int256) { if (a < min) return min; return (a > max) ? max : a; } function clampMin(int256 a, int256 min) public pure returns (int256) { return (a < min) ? min : a; } function clampMax(int256 a, int256 max) public pure returns (int256) { return (a > max) ? max : a; } } library BlockNumbUintsLib { struct Entry { uint256 blockNumber; uint256 value; } struct BlockNumbUints { Entry[] entries; } function currentValue(BlockNumbUints storage self) internal view returns (uint256) { return valueAt(self, block.number); } function currentEntry(BlockNumbUints storage self) internal view returns (Entry memory) { return entryAt(self, block.number); } function valueAt(BlockNumbUints storage self, uint256 _blockNumber) internal view returns (uint256) { return entryAt(self, _blockNumber).value; } function entryAt(BlockNumbUints storage self, uint256 _blockNumber) internal view returns (Entry memory) { return self.entries[indexByBlockNumber(self, _blockNumber)]; } function addEntry(BlockNumbUints storage self, uint256 blockNumber, uint256 value) internal { require( 0 == self.entries.length || blockNumber > self.entries[self.entries.length - 1].blockNumber, "Later entry found [BlockNumbUintsLib.sol:62]" ); self.entries.push(Entry(blockNumber, value)); } function count(BlockNumbUints storage self) internal view returns (uint256) { return self.entries.length; } function entries(BlockNumbUints storage self) internal view returns (Entry[] memory) { return self.entries; } function indexByBlockNumber(BlockNumbUints storage self, uint256 blockNumber) internal view returns (uint256) { require(0 < self.entries.length, "No entries found [BlockNumbUintsLib.sol:92]"); for (uint256 i = self.entries.length - 1; i >= 0; i--) if (blockNumber >= self.entries[i].blockNumber) return i; revert(); } } library BlockNumbIntsLib { struct Entry { uint256 blockNumber; int256 value; } struct BlockNumbInts { Entry[] entries; } function currentValue(BlockNumbInts storage self) internal view returns (int256) { return valueAt(self, block.number); } function currentEntry(BlockNumbInts storage self) internal view returns (Entry memory) { return entryAt(self, block.number); } function valueAt(BlockNumbInts storage self, uint256 _blockNumber) internal view returns (int256) { return entryAt(self, _blockNumber).value; } function entryAt(BlockNumbInts storage self, uint256 _blockNumber) internal view returns (Entry memory) { return self.entries[indexByBlockNumber(self, _blockNumber)]; } function addEntry(BlockNumbInts storage self, uint256 blockNumber, int256 value) internal { require( 0 == self.entries.length || blockNumber > self.entries[self.entries.length - 1].blockNumber, "Later entry found [BlockNumbIntsLib.sol:62]" ); self.entries.push(Entry(blockNumber, value)); } function count(BlockNumbInts storage self) internal view returns (uint256) { return self.entries.length; } function entries(BlockNumbInts storage self) internal view returns (Entry[] memory) { return self.entries; } function indexByBlockNumber(BlockNumbInts storage self, uint256 blockNumber) internal view returns (uint256) { require(0 < self.entries.length, "No entries found [BlockNumbIntsLib.sol:92]"); for (uint256 i = self.entries.length - 1; i >= 0; i--) if (blockNumber >= self.entries[i].blockNumber) return i; revert(); } } library ConstantsLib { function PARTS_PER() public pure returns (int256) { return 1e18; } } library BlockNumbDisdIntsLib { using SafeMathIntLib for int256; struct Discount { int256 tier; int256 value; } struct Entry { uint256 blockNumber; int256 nominal; Discount[] discounts; } struct BlockNumbDisdInts { Entry[] entries; } function currentNominalValue(BlockNumbDisdInts storage self) internal view returns (int256) { return nominalValueAt(self, block.number); } function currentDiscountedValue(BlockNumbDisdInts storage self, int256 tier) internal view returns (int256) { return discountedValueAt(self, block.number, tier); } function currentEntry(BlockNumbDisdInts storage self) internal view returns (Entry memory) { return entryAt(self, block.number); } function nominalValueAt(BlockNumbDisdInts storage self, uint256 _blockNumber) internal view returns (int256) { return entryAt(self, _blockNumber).nominal; } function discountedValueAt(BlockNumbDisdInts storage self, uint256 _blockNumber, int256 tier) internal view returns (int256) { Entry memory entry = entryAt(self, _blockNumber); if (0 < entry.discounts.length) { uint256 index = indexByTier(entry.discounts, tier); if (0 < index) return entry.nominal.mul( ConstantsLib.PARTS_PER().sub(entry.discounts[index - 1].value) ).div( ConstantsLib.PARTS_PER() ); else return entry.nominal; } else return entry.nominal; } function entryAt(BlockNumbDisdInts storage self, uint256 _blockNumber) internal view returns (Entry memory) { return self.entries[indexByBlockNumber(self, _blockNumber)]; } function addNominalEntry(BlockNumbDisdInts storage self, uint256 blockNumber, int256 nominal) internal { require( 0 == self.entries.length || blockNumber > self.entries[self.entries.length - 1].blockNumber, "Later entry found [BlockNumbDisdIntsLib.sol:101]" ); self.entries.length++; Entry storage entry = self.entries[self.entries.length - 1]; entry.blockNumber = blockNumber; entry.nominal = nominal; } function addDiscountedEntry(BlockNumbDisdInts storage self, uint256 blockNumber, int256 nominal, int256[] memory discountTiers, int256[] memory discountValues) internal { require(discountTiers.length == discountValues.length, "Parameter array lengths mismatch [BlockNumbDisdIntsLib.sol:118]"); addNominalEntry(self, blockNumber, nominal); Entry storage entry = self.entries[self.entries.length - 1]; for (uint256 i = 0; i < discountTiers.length; i++) entry.discounts.push(Discount(discountTiers[i], discountValues[i])); } function count(BlockNumbDisdInts storage self) internal view returns (uint256) { return self.entries.length; } function entries(BlockNumbDisdInts storage self) internal view returns (Entry[] memory) { return self.entries; } function indexByBlockNumber(BlockNumbDisdInts storage self, uint256 blockNumber) internal view returns (uint256) { require(0 < self.entries.length, "No entries found [BlockNumbDisdIntsLib.sol:148]"); for (uint256 i = self.entries.length - 1; i >= 0; i--) if (blockNumber >= self.entries[i].blockNumber) return i; revert(); } function indexByTier(Discount[] memory discounts, int256 tier) internal pure returns (uint256) { require(0 < discounts.length, "No discounts found [BlockNumbDisdIntsLib.sol:161]"); for (uint256 i = discounts.length; i > 0; i--) if (tier >= discounts[i - 1].tier) return i; return 0; } } library MonetaryTypesLib { struct Currency { address ct; uint256 id; } struct Figure { int256 amount; Currency currency; } struct NoncedAmount { uint256 nonce; int256 amount; } } library BlockNumbReferenceCurrenciesLib { struct Entry { uint256 blockNumber; MonetaryTypesLib.Currency currency; } struct BlockNumbReferenceCurrencies { mapping(address => mapping(uint256 => Entry[])) entriesByCurrency; } function currentCurrency(BlockNumbReferenceCurrencies storage self, MonetaryTypesLib.Currency memory referenceCurrency) internal view returns (MonetaryTypesLib.Currency storage) { return currencyAt(self, referenceCurrency, block.number); } function currentEntry(BlockNumbReferenceCurrencies storage self, MonetaryTypesLib.Currency memory referenceCurrency) internal view returns (Entry storage) { return entryAt(self, referenceCurrency, block.number); } function currencyAt(BlockNumbReferenceCurrencies storage self, MonetaryTypesLib.Currency memory referenceCurrency, uint256 _blockNumber) internal view returns (MonetaryTypesLib.Currency storage) { return entryAt(self, referenceCurrency, _blockNumber).currency; } function entryAt(BlockNumbReferenceCurrencies storage self, MonetaryTypesLib.Currency memory referenceCurrency, uint256 _blockNumber) internal view returns (Entry storage) { return self.entriesByCurrency[referenceCurrency.ct][referenceCurrency.id][indexByBlockNumber(self, referenceCurrency, _blockNumber)]; } function addEntry(BlockNumbReferenceCurrencies storage self, uint256 blockNumber, MonetaryTypesLib.Currency memory referenceCurrency, MonetaryTypesLib.Currency memory currency) internal { require( 0 == self.entriesByCurrency[referenceCurrency.ct][referenceCurrency.id].length || blockNumber > self.entriesByCurrency[referenceCurrency.ct][referenceCurrency.id][self.entriesByCurrency[referenceCurrency.ct][referenceCurrency.id].length - 1].blockNumber, "Later entry found for currency [BlockNumbReferenceCurrenciesLib.sol:67]" ); self.entriesByCurrency[referenceCurrency.ct][referenceCurrency.id].push(Entry(blockNumber, currency)); } function count(BlockNumbReferenceCurrencies storage self, MonetaryTypesLib.Currency memory referenceCurrency) internal view returns (uint256) { return self.entriesByCurrency[referenceCurrency.ct][referenceCurrency.id].length; } function entriesByCurrency(BlockNumbReferenceCurrencies storage self, MonetaryTypesLib.Currency memory referenceCurrency) internal view returns (Entry[] storage) { return self.entriesByCurrency[referenceCurrency.ct][referenceCurrency.id]; } function indexByBlockNumber(BlockNumbReferenceCurrencies storage self, MonetaryTypesLib.Currency memory referenceCurrency, uint256 blockNumber) internal view returns (uint256) { require(0 < self.entriesByCurrency[referenceCurrency.ct][referenceCurrency.id].length, "No entries found for currency [BlockNumbReferenceCurrenciesLib.sol:97]"); for (uint256 i = self.entriesByCurrency[referenceCurrency.ct][referenceCurrency.id].length - 1; i >= 0; i--) if (blockNumber >= self.entriesByCurrency[referenceCurrency.ct][referenceCurrency.id][i].blockNumber) return i; revert(); } } library BlockNumbFiguresLib { struct Entry { uint256 blockNumber; MonetaryTypesLib.Figure value; } struct BlockNumbFigures { Entry[] entries; } function currentValue(BlockNumbFigures storage self) internal view returns (MonetaryTypesLib.Figure storage) { return valueAt(self, block.number); } function currentEntry(BlockNumbFigures storage self) internal view returns (Entry storage) { return entryAt(self, block.number); } function valueAt(BlockNumbFigures storage self, uint256 _blockNumber) internal view returns (MonetaryTypesLib.Figure storage) { return entryAt(self, _blockNumber).value; } function entryAt(BlockNumbFigures storage self, uint256 _blockNumber) internal view returns (Entry storage) { return self.entries[indexByBlockNumber(self, _blockNumber)]; } function addEntry(BlockNumbFigures storage self, uint256 blockNumber, MonetaryTypesLib.Figure memory value) internal { require( 0 == self.entries.length || blockNumber > self.entries[self.entries.length - 1].blockNumber, "Later entry found [BlockNumbFiguresLib.sol:65]" ); self.entries.push(Entry(blockNumber, value)); } function count(BlockNumbFigures storage self) internal view returns (uint256) { return self.entries.length; } function entries(BlockNumbFigures storage self) internal view returns (Entry[] storage) { return self.entries; } function indexByBlockNumber(BlockNumbFigures storage self, uint256 blockNumber) internal view returns (uint256) { require(0 < self.entries.length, "No entries found [BlockNumbFiguresLib.sol:95]"); for (uint256 i = self.entries.length - 1; i >= 0; i--) if (blockNumber >= self.entries[i].blockNumber) return i; revert(); } } contract Configuration is Modifiable, Ownable, Servable { using SafeMathIntLib for int256; using BlockNumbUintsLib for BlockNumbUintsLib.BlockNumbUints; using BlockNumbIntsLib for BlockNumbIntsLib.BlockNumbInts; using BlockNumbDisdIntsLib for BlockNumbDisdIntsLib.BlockNumbDisdInts; using BlockNumbReferenceCurrenciesLib for BlockNumbReferenceCurrenciesLib.BlockNumbReferenceCurrencies; using BlockNumbFiguresLib for BlockNumbFiguresLib.BlockNumbFigures; string constant public OPERATIONAL_MODE_ACTION = "operational_mode"; enum OperationalMode {Normal, Exit} OperationalMode public operationalMode = OperationalMode.Normal; BlockNumbUintsLib.BlockNumbUints private updateDelayBlocksByBlockNumber; BlockNumbUintsLib.BlockNumbUints private confirmationBlocksByBlockNumber; BlockNumbDisdIntsLib.BlockNumbDisdInts private tradeMakerFeeByBlockNumber; BlockNumbDisdIntsLib.BlockNumbDisdInts private tradeTakerFeeByBlockNumber; BlockNumbDisdIntsLib.BlockNumbDisdInts private paymentFeeByBlockNumber; mapping(address => mapping(uint256 => BlockNumbDisdIntsLib.BlockNumbDisdInts)) private currencyPaymentFeeByBlockNumber; BlockNumbIntsLib.BlockNumbInts private tradeMakerMinimumFeeByBlockNumber; BlockNumbIntsLib.BlockNumbInts private tradeTakerMinimumFeeByBlockNumber; BlockNumbIntsLib.BlockNumbInts private paymentMinimumFeeByBlockNumber; mapping(address => mapping(uint256 => BlockNumbIntsLib.BlockNumbInts)) private currencyPaymentMinimumFeeByBlockNumber; BlockNumbReferenceCurrenciesLib.BlockNumbReferenceCurrencies private feeCurrencyByCurrencyBlockNumber; BlockNumbUintsLib.BlockNumbUints private walletLockTimeoutByBlockNumber; BlockNumbUintsLib.BlockNumbUints private cancelOrderChallengeTimeoutByBlockNumber; BlockNumbUintsLib.BlockNumbUints private settlementChallengeTimeoutByBlockNumber; BlockNumbUintsLib.BlockNumbUints private fraudStakeFractionByBlockNumber; BlockNumbUintsLib.BlockNumbUints private walletSettlementStakeFractionByBlockNumber; BlockNumbUintsLib.BlockNumbUints private operatorSettlementStakeFractionByBlockNumber; BlockNumbFiguresLib.BlockNumbFigures private operatorSettlementStakeByBlockNumber; uint256 public earliestSettlementBlockNumber; bool public earliestSettlementBlockNumberUpdateDisabled; event SetOperationalModeExitEvent(); event SetUpdateDelayBlocksEvent(uint256 fromBlockNumber, uint256 newBlocks); event SetConfirmationBlocksEvent(uint256 fromBlockNumber, uint256 newBlocks); event SetTradeMakerFeeEvent(uint256 fromBlockNumber, int256 nominal, int256[] discountTiers, int256[] discountValues); event SetTradeTakerFeeEvent(uint256 fromBlockNumber, int256 nominal, int256[] discountTiers, int256[] discountValues); event SetPaymentFeeEvent(uint256 fromBlockNumber, int256 nominal, int256[] discountTiers, int256[] discountValues); event SetCurrencyPaymentFeeEvent(uint256 fromBlockNumber, address currencyCt, uint256 currencyId, int256 nominal, int256[] discountTiers, int256[] discountValues); event SetTradeMakerMinimumFeeEvent(uint256 fromBlockNumber, int256 nominal); event SetTradeTakerMinimumFeeEvent(uint256 fromBlockNumber, int256 nominal); event SetPaymentMinimumFeeEvent(uint256 fromBlockNumber, int256 nominal); event SetCurrencyPaymentMinimumFeeEvent(uint256 fromBlockNumber, address currencyCt, uint256 currencyId, int256 nominal); event SetFeeCurrencyEvent(uint256 fromBlockNumber, address referenceCurrencyCt, uint256 referenceCurrencyId, address feeCurrencyCt, uint256 feeCurrencyId); event SetWalletLockTimeoutEvent(uint256 fromBlockNumber, uint256 timeoutInSeconds); event SetCancelOrderChallengeTimeoutEvent(uint256 fromBlockNumber, uint256 timeoutInSeconds); event SetSettlementChallengeTimeoutEvent(uint256 fromBlockNumber, uint256 timeoutInSeconds); event SetWalletSettlementStakeFractionEvent(uint256 fromBlockNumber, uint256 stakeFraction); event SetOperatorSettlementStakeFractionEvent(uint256 fromBlockNumber, uint256 stakeFraction); event SetOperatorSettlementStakeEvent(uint256 fromBlockNumber, int256 stakeAmount, address stakeCurrencyCt, uint256 stakeCurrencyId); event SetFraudStakeFractionEvent(uint256 fromBlockNumber, uint256 stakeFraction); event SetEarliestSettlementBlockNumberEvent(uint256 earliestSettlementBlockNumber); event DisableEarliestSettlementBlockNumberUpdateEvent(); constructor(address deployer) Ownable(deployer) public { updateDelayBlocksByBlockNumber.addEntry(block.number, 0); } function setOperationalModeExit() public onlyEnabledServiceAction(OPERATIONAL_MODE_ACTION) { operationalMode = OperationalMode.Exit; emit SetOperationalModeExitEvent(); } function isOperationalModeNormal() public view returns (bool) { return OperationalMode.Normal == operationalMode; } function isOperationalModeExit() public view returns (bool) { return OperationalMode.Exit == operationalMode; } function updateDelayBlocks() public view returns (uint256) { return updateDelayBlocksByBlockNumber.currentValue(); } function updateDelayBlocksCount() public view returns (uint256) { return updateDelayBlocksByBlockNumber.count(); } function setUpdateDelayBlocks(uint256 fromBlockNumber, uint256 newUpdateDelayBlocks) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { updateDelayBlocksByBlockNumber.addEntry(fromBlockNumber, newUpdateDelayBlocks); emit SetUpdateDelayBlocksEvent(fromBlockNumber, newUpdateDelayBlocks); } function confirmationBlocks() public view returns (uint256) { return confirmationBlocksByBlockNumber.currentValue(); } function confirmationBlocksCount() public view returns (uint256) { return confirmationBlocksByBlockNumber.count(); } function setConfirmationBlocks(uint256 fromBlockNumber, uint256 newConfirmationBlocks) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { confirmationBlocksByBlockNumber.addEntry(fromBlockNumber, newConfirmationBlocks); emit SetConfirmationBlocksEvent(fromBlockNumber, newConfirmationBlocks); } function tradeMakerFeesCount() public view returns (uint256) { return tradeMakerFeeByBlockNumber.count(); } function tradeMakerFee(uint256 blockNumber, int256 discountTier) public view returns (int256) { return tradeMakerFeeByBlockNumber.discountedValueAt(blockNumber, discountTier); } function setTradeMakerFee(uint256 fromBlockNumber, int256 nominal, int256[] memory discountTiers, int256[] memory discountValues) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { tradeMakerFeeByBlockNumber.addDiscountedEntry(fromBlockNumber, nominal, discountTiers, discountValues); emit SetTradeMakerFeeEvent(fromBlockNumber, nominal, discountTiers, discountValues); } function tradeTakerFeesCount() public view returns (uint256) { return tradeTakerFeeByBlockNumber.count(); } function tradeTakerFee(uint256 blockNumber, int256 discountTier) public view returns (int256) { return tradeTakerFeeByBlockNumber.discountedValueAt(blockNumber, discountTier); } function setTradeTakerFee(uint256 fromBlockNumber, int256 nominal, int256[] memory discountTiers, int256[] memory discountValues) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { tradeTakerFeeByBlockNumber.addDiscountedEntry(fromBlockNumber, nominal, discountTiers, discountValues); emit SetTradeTakerFeeEvent(fromBlockNumber, nominal, discountTiers, discountValues); } function paymentFeesCount() public view returns (uint256) { return paymentFeeByBlockNumber.count(); } function paymentFee(uint256 blockNumber, int256 discountTier) public view returns (int256) { return paymentFeeByBlockNumber.discountedValueAt(blockNumber, discountTier); } function setPaymentFee(uint256 fromBlockNumber, int256 nominal, int256[] memory discountTiers, int256[] memory discountValues) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { paymentFeeByBlockNumber.addDiscountedEntry(fromBlockNumber, nominal, discountTiers, discountValues); emit SetPaymentFeeEvent(fromBlockNumber, nominal, discountTiers, discountValues); } function currencyPaymentFeesCount(address currencyCt, uint256 currencyId) public view returns (uint256) { return currencyPaymentFeeByBlockNumber[currencyCt][currencyId].count(); } function currencyPaymentFee(uint256 blockNumber, address currencyCt, uint256 currencyId, int256 discountTier) public view returns (int256) { if (0 < currencyPaymentFeeByBlockNumber[currencyCt][currencyId].count()) return currencyPaymentFeeByBlockNumber[currencyCt][currencyId].discountedValueAt( blockNumber, discountTier ); else return paymentFee(blockNumber, discountTier); } function setCurrencyPaymentFee(uint256 fromBlockNumber, address currencyCt, uint256 currencyId, int256 nominal, int256[] memory discountTiers, int256[] memory discountValues) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { currencyPaymentFeeByBlockNumber[currencyCt][currencyId].addDiscountedEntry( fromBlockNumber, nominal, discountTiers, discountValues ); emit SetCurrencyPaymentFeeEvent( fromBlockNumber, currencyCt, currencyId, nominal, discountTiers, discountValues ); } function tradeMakerMinimumFeesCount() public view returns (uint256) { return tradeMakerMinimumFeeByBlockNumber.count(); } function tradeMakerMinimumFee(uint256 blockNumber) public view returns (int256) { return tradeMakerMinimumFeeByBlockNumber.valueAt(blockNumber); } function setTradeMakerMinimumFee(uint256 fromBlockNumber, int256 nominal) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { tradeMakerMinimumFeeByBlockNumber.addEntry(fromBlockNumber, nominal); emit SetTradeMakerMinimumFeeEvent(fromBlockNumber, nominal); } function tradeTakerMinimumFeesCount() public view returns (uint256) { return tradeTakerMinimumFeeByBlockNumber.count(); } function tradeTakerMinimumFee(uint256 blockNumber) public view returns (int256) { return tradeTakerMinimumFeeByBlockNumber.valueAt(blockNumber); } function setTradeTakerMinimumFee(uint256 fromBlockNumber, int256 nominal) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { tradeTakerMinimumFeeByBlockNumber.addEntry(fromBlockNumber, nominal); emit SetTradeTakerMinimumFeeEvent(fromBlockNumber, nominal); } function paymentMinimumFeesCount() public view returns (uint256) { return paymentMinimumFeeByBlockNumber.count(); } function paymentMinimumFee(uint256 blockNumber) public view returns (int256) { return paymentMinimumFeeByBlockNumber.valueAt(blockNumber); } function setPaymentMinimumFee(uint256 fromBlockNumber, int256 nominal) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { paymentMinimumFeeByBlockNumber.addEntry(fromBlockNumber, nominal); emit SetPaymentMinimumFeeEvent(fromBlockNumber, nominal); } function currencyPaymentMinimumFeesCount(address currencyCt, uint256 currencyId) public view returns (uint256) { return currencyPaymentMinimumFeeByBlockNumber[currencyCt][currencyId].count(); } function currencyPaymentMinimumFee(uint256 blockNumber, address currencyCt, uint256 currencyId) public view returns (int256) { if (0 < currencyPaymentMinimumFeeByBlockNumber[currencyCt][currencyId].count()) return currencyPaymentMinimumFeeByBlockNumber[currencyCt][currencyId].valueAt(blockNumber); else return paymentMinimumFee(blockNumber); } function setCurrencyPaymentMinimumFee(uint256 fromBlockNumber, address currencyCt, uint256 currencyId, int256 nominal) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { currencyPaymentMinimumFeeByBlockNumber[currencyCt][currencyId].addEntry(fromBlockNumber, nominal); emit SetCurrencyPaymentMinimumFeeEvent(fromBlockNumber, currencyCt, currencyId, nominal); } function feeCurrenciesCount(address currencyCt, uint256 currencyId) public view returns (uint256) { return feeCurrencyByCurrencyBlockNumber.count(MonetaryTypesLib.Currency(currencyCt, currencyId)); } function feeCurrency(uint256 blockNumber, address currencyCt, uint256 currencyId) public view returns (address ct, uint256 id) { MonetaryTypesLib.Currency storage _feeCurrency = feeCurrencyByCurrencyBlockNumber.currencyAt( MonetaryTypesLib.Currency(currencyCt, currencyId), blockNumber ); ct = _feeCurrency.ct; id = _feeCurrency.id; } function setFeeCurrency(uint256 fromBlockNumber, address referenceCurrencyCt, uint256 referenceCurrencyId, address feeCurrencyCt, uint256 feeCurrencyId) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { feeCurrencyByCurrencyBlockNumber.addEntry( fromBlockNumber, MonetaryTypesLib.Currency(referenceCurrencyCt, referenceCurrencyId), MonetaryTypesLib.Currency(feeCurrencyCt, feeCurrencyId) ); emit SetFeeCurrencyEvent(fromBlockNumber, referenceCurrencyCt, referenceCurrencyId, feeCurrencyCt, feeCurrencyId); } function walletLockTimeout() public view returns (uint256) { return walletLockTimeoutByBlockNumber.currentValue(); } function setWalletLockTimeout(uint256 fromBlockNumber, uint256 timeoutInSeconds) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { walletLockTimeoutByBlockNumber.addEntry(fromBlockNumber, timeoutInSeconds); emit SetWalletLockTimeoutEvent(fromBlockNumber, timeoutInSeconds); } function cancelOrderChallengeTimeout() public view returns (uint256) { return cancelOrderChallengeTimeoutByBlockNumber.currentValue(); } function setCancelOrderChallengeTimeout(uint256 fromBlockNumber, uint256 timeoutInSeconds) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { cancelOrderChallengeTimeoutByBlockNumber.addEntry(fromBlockNumber, timeoutInSeconds); emit SetCancelOrderChallengeTimeoutEvent(fromBlockNumber, timeoutInSeconds); } function settlementChallengeTimeout() public view returns (uint256) { return settlementChallengeTimeoutByBlockNumber.currentValue(); } function setSettlementChallengeTimeout(uint256 fromBlockNumber, uint256 timeoutInSeconds) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { settlementChallengeTimeoutByBlockNumber.addEntry(fromBlockNumber, timeoutInSeconds); emit SetSettlementChallengeTimeoutEvent(fromBlockNumber, timeoutInSeconds); } function fraudStakeFraction() public view returns (uint256) { return fraudStakeFractionByBlockNumber.currentValue(); } function setFraudStakeFraction(uint256 fromBlockNumber, uint256 stakeFraction) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { fraudStakeFractionByBlockNumber.addEntry(fromBlockNumber, stakeFraction); emit SetFraudStakeFractionEvent(fromBlockNumber, stakeFraction); } function walletSettlementStakeFraction() public view returns (uint256) { return walletSettlementStakeFractionByBlockNumber.currentValue(); } function setWalletSettlementStakeFraction(uint256 fromBlockNumber, uint256 stakeFraction) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { walletSettlementStakeFractionByBlockNumber.addEntry(fromBlockNumber, stakeFraction); emit SetWalletSettlementStakeFractionEvent(fromBlockNumber, stakeFraction); } function operatorSettlementStakeFraction() public view returns (uint256) { return operatorSettlementStakeFractionByBlockNumber.currentValue(); } function setOperatorSettlementStakeFraction(uint256 fromBlockNumber, uint256 stakeFraction) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { operatorSettlementStakeFractionByBlockNumber.addEntry(fromBlockNumber, stakeFraction); emit SetOperatorSettlementStakeFractionEvent(fromBlockNumber, stakeFraction); } function operatorSettlementStake() public view returns (int256 amount, address currencyCt, uint256 currencyId) { MonetaryTypesLib.Figure storage stake = operatorSettlementStakeByBlockNumber.currentValue(); amount = stake.amount; currencyCt = stake.currency.ct; currencyId = stake.currency.id; } function setOperatorSettlementStake(uint256 fromBlockNumber, int256 stakeAmount, address stakeCurrencyCt, uint256 stakeCurrencyId) public onlyOperator onlyDelayedBlockNumber(fromBlockNumber) { MonetaryTypesLib.Figure memory stake = MonetaryTypesLib.Figure(stakeAmount, MonetaryTypesLib.Currency(stakeCurrencyCt, stakeCurrencyId)); operatorSettlementStakeByBlockNumber.addEntry(fromBlockNumber, stake); emit SetOperatorSettlementStakeEvent(fromBlockNumber, stakeAmount, stakeCurrencyCt, stakeCurrencyId); } function setEarliestSettlementBlockNumber(uint256 _earliestSettlementBlockNumber) public onlyOperator { require(!earliestSettlementBlockNumberUpdateDisabled, "Earliest settlement block number update disabled [Configuration.sol:715]"); earliestSettlementBlockNumber = _earliestSettlementBlockNumber; emit SetEarliestSettlementBlockNumberEvent(earliestSettlementBlockNumber); } function disableEarliestSettlementBlockNumberUpdate() public onlyOperator { earliestSettlementBlockNumberUpdateDisabled = true; emit DisableEarliestSettlementBlockNumberUpdateEvent(); } modifier onlyDelayedBlockNumber(uint256 blockNumber) { require( 0 == updateDelayBlocksByBlockNumber.count() || blockNumber >= block.number + updateDelayBlocksByBlockNumber.currentValue(), "Block number not sufficiently delayed [Configuration.sol:735]" ); _; } } contract Configurable is Ownable { Configuration public configuration; event SetConfigurationEvent(Configuration oldConfiguration, Configuration newConfiguration); function setConfiguration(Configuration newConfiguration) public onlyDeployer notNullAddress(address(newConfiguration)) notSameAddresses(address(newConfiguration), address(configuration)) { Configuration oldConfiguration = configuration; configuration = newConfiguration; emit SetConfigurationEvent(oldConfiguration, newConfiguration); } modifier configurationInitialized() { require(address(configuration) != address(0), "Configuration not initialized [Configurable.sol:52]"); _; } } contract Beneficiary { function receiveEthersTo(address wallet, string memory balanceType) public payable; function receiveTokensTo(address wallet, string memory balanceType, int256 amount, address currencyCt, uint256 currencyId, string memory standard) public; } contract Benefactor is Ownable { Beneficiary[] public beneficiaries; mapping(address => uint256) public beneficiaryIndexByAddress; event RegisterBeneficiaryEvent(Beneficiary beneficiary); event DeregisterBeneficiaryEvent(Beneficiary beneficiary); function registerBeneficiary(Beneficiary beneficiary) public onlyDeployer notNullAddress(address(beneficiary)) returns (bool) { address _beneficiary = address(beneficiary); if (beneficiaryIndexByAddress[_beneficiary] > 0) return false; beneficiaries.push(beneficiary); beneficiaryIndexByAddress[_beneficiary] = beneficiaries.length; emit RegisterBeneficiaryEvent(beneficiary); return true; } function deregisterBeneficiary(Beneficiary beneficiary) public onlyDeployer notNullAddress(address(beneficiary)) returns (bool) { address _beneficiary = address(beneficiary); if (beneficiaryIndexByAddress[_beneficiary] == 0) return false; uint256 idx = beneficiaryIndexByAddress[_beneficiary] - 1; if (idx < beneficiaries.length - 1) { beneficiaries[idx] = beneficiaries[beneficiaries.length - 1]; beneficiaryIndexByAddress[address(beneficiaries[idx])] = idx + 1; } beneficiaries.length--; beneficiaryIndexByAddress[_beneficiary] = 0; emit DeregisterBeneficiaryEvent(beneficiary); return true; } function isRegisteredBeneficiary(Beneficiary beneficiary) public view returns (bool) { return beneficiaryIndexByAddress[address(beneficiary)] > 0; } function registeredBeneficiariesCount() public view returns (uint256) { return beneficiaries.length; } } contract AuthorizableServable is Servable { bool public initialServiceAuthorizationDisabled; mapping(address => bool) public initialServiceAuthorizedMap; mapping(address => mapping(address => bool)) public initialServiceWalletUnauthorizedMap; mapping(address => mapping(address => bool)) public serviceWalletAuthorizedMap; mapping(address => mapping(bytes32 => mapping(address => bool))) public serviceActionWalletAuthorizedMap; mapping(address => mapping(bytes32 => mapping(address => bool))) public serviceActionWalletTouchedMap; mapping(address => mapping(address => bytes32[])) public serviceWalletActionList; event AuthorizeInitialServiceEvent(address wallet, address service); event AuthorizeRegisteredServiceEvent(address wallet, address service); event AuthorizeRegisteredServiceActionEvent(address wallet, address service, string action); event UnauthorizeRegisteredServiceEvent(address wallet, address service); event UnauthorizeRegisteredServiceActionEvent(address wallet, address service, string action); function authorizeInitialService(address service) public onlyDeployer notNullOrThisAddress(service) { require(!initialServiceAuthorizationDisabled); require(msg.sender != service); require(registeredServicesMap[service].registered); initialServiceAuthorizedMap[service] = true; emit AuthorizeInitialServiceEvent(msg.sender, service); } function disableInitialServiceAuthorization() public onlyDeployer { initialServiceAuthorizationDisabled = true; } function authorizeRegisteredService(address service) public notNullOrThisAddress(service) { require(msg.sender != service); require(registeredServicesMap[service].registered); require(!initialServiceAuthorizedMap[service]); serviceWalletAuthorizedMap[service][msg.sender] = true; emit AuthorizeRegisteredServiceEvent(msg.sender, service); } function unauthorizeRegisteredService(address service) public notNullOrThisAddress(service) { require(msg.sender != service); require(registeredServicesMap[service].registered); if (initialServiceAuthorizedMap[service]) initialServiceWalletUnauthorizedMap[service][msg.sender] = true; else { serviceWalletAuthorizedMap[service][msg.sender] = false; for (uint256 i = 0; i < serviceWalletActionList[service][msg.sender].length; i++) serviceActionWalletAuthorizedMap[service][serviceWalletActionList[service][msg.sender][i]][msg.sender] = true; } emit UnauthorizeRegisteredServiceEvent(msg.sender, service); } function isAuthorizedRegisteredService(address service, address wallet) public view returns (bool) { return isRegisteredActiveService(service) && (isInitialServiceAuthorizedForWallet(service, wallet) || serviceWalletAuthorizedMap[service][wallet]); } function authorizeRegisteredServiceAction(address service, string memory action) public notNullOrThisAddress(service) { require(msg.sender != service); bytes32 actionHash = hashString(action); require(registeredServicesMap[service].registered && registeredServicesMap[service].actionsEnabledMap[actionHash]); require(!initialServiceAuthorizedMap[service]); serviceWalletAuthorizedMap[service][msg.sender] = false; serviceActionWalletAuthorizedMap[service][actionHash][msg.sender] = true; if (!serviceActionWalletTouchedMap[service][actionHash][msg.sender]) { serviceActionWalletTouchedMap[service][actionHash][msg.sender] = true; serviceWalletActionList[service][msg.sender].push(actionHash); } emit AuthorizeRegisteredServiceActionEvent(msg.sender, service, action); } function unauthorizeRegisteredServiceAction(address service, string memory action) public notNullOrThisAddress(service) { require(msg.sender != service); bytes32 actionHash = hashString(action); require(registeredServicesMap[service].registered && registeredServicesMap[service].actionsEnabledMap[actionHash]); require(!initialServiceAuthorizedMap[service]); serviceActionWalletAuthorizedMap[service][actionHash][msg.sender] = false; emit UnauthorizeRegisteredServiceActionEvent(msg.sender, service, action); } function isAuthorizedRegisteredServiceAction(address service, string memory action, address wallet) public view returns (bool) { bytes32 actionHash = hashString(action); return isEnabledServiceAction(service, action) && ( isInitialServiceAuthorizedForWallet(service, wallet) || serviceWalletAuthorizedMap[service][wallet] || serviceActionWalletAuthorizedMap[service][actionHash][wallet] ); } function isInitialServiceAuthorizedForWallet(address service, address wallet) private view returns (bool) { return initialServiceAuthorizedMap[service] ? !initialServiceWalletUnauthorizedMap[service][wallet] : false; } modifier onlyAuthorizedService(address wallet) { require(isAuthorizedRegisteredService(msg.sender, wallet)); _; } modifier onlyAuthorizedServiceAction(string memory action, address wallet) { require(isAuthorizedRegisteredServiceAction(msg.sender, action, wallet)); _; } } contract TransferController { event CurrencyTransferred(address from, address to, uint256 value, address currencyCt, uint256 currencyId); function isFungible() public view returns (bool); function standard() public view returns (string memory); function receive(address from, address to, uint256 value, address currencyCt, uint256 currencyId) public; function approve(address to, uint256 value, address currencyCt, uint256 currencyId) public; function dispatch(address from, address to, uint256 value, address currencyCt, uint256 currencyId) public; function getReceiveSignature() public pure returns (bytes4) { return bytes4(keccak256("receive(address,address,uint256,address,uint256)")); } function getApproveSignature() public pure returns (bytes4) { return bytes4(keccak256("approve(address,uint256,address,uint256)")); } function getDispatchSignature() public pure returns (bytes4) { return bytes4(keccak256("dispatch(address,address,uint256,address,uint256)")); } } contract TransferControllerManager is Ownable { struct CurrencyInfo { bytes32 standard; bool blacklisted; } mapping(bytes32 => address) public registeredTransferControllers; mapping(address => CurrencyInfo) public registeredCurrencies; event RegisterTransferControllerEvent(string standard, address controller); event ReassociateTransferControllerEvent(string oldStandard, string newStandard, address controller); event RegisterCurrencyEvent(address currencyCt, string standard); event DeregisterCurrencyEvent(address currencyCt); event BlacklistCurrencyEvent(address currencyCt); event WhitelistCurrencyEvent(address currencyCt); constructor(address deployer) Ownable(deployer) public { } function registerTransferController(string calldata standard, address controller) external onlyDeployer notNullAddress(controller) { require(bytes(standard).length > 0, "Empty standard not supported [TransferControllerManager.sol:58]"); bytes32 standardHash = keccak256(abi.encodePacked(standard)); registeredTransferControllers[standardHash] = controller; emit RegisterTransferControllerEvent(standard, controller); } function reassociateTransferController(string calldata oldStandard, string calldata newStandard, address controller) external onlyDeployer notNullAddress(controller) { require(bytes(newStandard).length > 0, "Empty new standard not supported [TransferControllerManager.sol:72]"); bytes32 oldStandardHash = keccak256(abi.encodePacked(oldStandard)); bytes32 newStandardHash = keccak256(abi.encodePacked(newStandard)); require(registeredTransferControllers[oldStandardHash] != address(0), "Old standard not registered [TransferControllerManager.sol:76]"); require(registeredTransferControllers[newStandardHash] == address(0), "New standard previously registered [TransferControllerManager.sol:77]"); registeredTransferControllers[newStandardHash] = registeredTransferControllers[oldStandardHash]; registeredTransferControllers[oldStandardHash] = address(0); emit ReassociateTransferControllerEvent(oldStandard, newStandard, controller); } function registerCurrency(address currencyCt, string calldata standard) external onlyOperator notNullAddress(currencyCt) { require(bytes(standard).length > 0, "Empty standard not supported [TransferControllerManager.sol:91]"); bytes32 standardHash = keccak256(abi.encodePacked(standard)); require(registeredCurrencies[currencyCt].standard == bytes32(0), "Currency previously registered [TransferControllerManager.sol:94]"); registeredCurrencies[currencyCt].standard = standardHash; emit RegisterCurrencyEvent(currencyCt, standard); } function deregisterCurrency(address currencyCt) external onlyOperator { require(registeredCurrencies[currencyCt].standard != 0, "Currency not registered [TransferControllerManager.sol:106]"); registeredCurrencies[currencyCt].standard = bytes32(0); registeredCurrencies[currencyCt].blacklisted = false; emit DeregisterCurrencyEvent(currencyCt); } function blacklistCurrency(address currencyCt) external onlyOperator { require(registeredCurrencies[currencyCt].standard != bytes32(0), "Currency not registered [TransferControllerManager.sol:119]"); registeredCurrencies[currencyCt].blacklisted = true; emit BlacklistCurrencyEvent(currencyCt); } function whitelistCurrency(address currencyCt) external onlyOperator { require(registeredCurrencies[currencyCt].standard != bytes32(0), "Currency not registered [TransferControllerManager.sol:131]"); registeredCurrencies[currencyCt].blacklisted = false; emit WhitelistCurrencyEvent(currencyCt); } function transferController(address currencyCt, string memory standard) public view returns (TransferController) { if (bytes(standard).length > 0) { bytes32 standardHash = keccak256(abi.encodePacked(standard)); require(registeredTransferControllers[standardHash] != address(0), "Standard not registered [TransferControllerManager.sol:150]"); return TransferController(registeredTransferControllers[standardHash]); } require(registeredCurrencies[currencyCt].standard != bytes32(0), "Currency not registered [TransferControllerManager.sol:154]"); require(!registeredCurrencies[currencyCt].blacklisted, "Currency blacklisted [TransferControllerManager.sol:155]"); address controllerAddress = registeredTransferControllers[registeredCurrencies[currencyCt].standard]; require(controllerAddress != address(0), "No matching transfer controller [TransferControllerManager.sol:158]"); return TransferController(controllerAddress); } } contract TransferControllerManageable is Ownable { TransferControllerManager public transferControllerManager; event SetTransferControllerManagerEvent(TransferControllerManager oldTransferControllerManager, TransferControllerManager newTransferControllerManager); function setTransferControllerManager(TransferControllerManager newTransferControllerManager) public onlyDeployer notNullAddress(address(newTransferControllerManager)) notSameAddresses(address(newTransferControllerManager), address(transferControllerManager)) { TransferControllerManager oldTransferControllerManager = transferControllerManager; transferControllerManager = newTransferControllerManager; emit SetTransferControllerManagerEvent(oldTransferControllerManager, newTransferControllerManager); } function transferController(address currencyCt, string memory standard) internal view returns (TransferController) { return transferControllerManager.transferController(currencyCt, standard); } modifier transferControllerManagerInitialized() { require(address(transferControllerManager) != address(0), "Transfer controller manager not initialized [TransferControllerManageable.sol:63]"); _; } } library SafeMathUintLib { function mul(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a * b; assert(a == 0 || c / a == b); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a / b; return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a - b; } function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } function clamp(uint256 a, uint256 min, uint256 max) public pure returns (uint256) { return (a > max) ? max : ((a < min) ? min : a); } function clampMin(uint256 a, uint256 min) public pure returns (uint256) { return (a < min) ? min : a; } function clampMax(uint256 a, uint256 max) public pure returns (uint256) { return (a > max) ? max : a; } } library CurrenciesLib { using SafeMathUintLib for uint256; struct Currencies { MonetaryTypesLib.Currency[] currencies; mapping(address => mapping(uint256 => uint256)) indexByCurrency; } function add(Currencies storage self, address currencyCt, uint256 currencyId) internal { if (0 == self.indexByCurrency[currencyCt][currencyId]) { self.currencies.push(MonetaryTypesLib.Currency(currencyCt, currencyId)); self.indexByCurrency[currencyCt][currencyId] = self.currencies.length; } } function removeByCurrency(Currencies storage self, address currencyCt, uint256 currencyId) internal { uint256 index = self.indexByCurrency[currencyCt][currencyId]; if (0 < index) removeByIndex(self, index - 1); } function removeByIndex(Currencies storage self, uint256 index) internal { require(index < self.currencies.length, "Index out of bounds [CurrenciesLib.sol:51]"); address currencyCt = self.currencies[index].ct; uint256 currencyId = self.currencies[index].id; if (index < self.currencies.length - 1) { self.currencies[index] = self.currencies[self.currencies.length - 1]; self.indexByCurrency[self.currencies[index].ct][self.currencies[index].id] = index + 1; } self.currencies.length--; self.indexByCurrency[currencyCt][currencyId] = 0; } function count(Currencies storage self) internal view returns (uint256) { return self.currencies.length; } function has(Currencies storage self, address currencyCt, uint256 currencyId) internal view returns (bool) { return 0 != self.indexByCurrency[currencyCt][currencyId]; } function getByIndex(Currencies storage self, uint256 index) internal view returns (MonetaryTypesLib.Currency memory) { require(index < self.currencies.length, "Index out of bounds [CurrenciesLib.sol:85]"); return self.currencies[index]; } function getByIndices(Currencies storage self, uint256 low, uint256 up) internal view returns (MonetaryTypesLib.Currency[] memory) { require(0 < self.currencies.length, "No currencies found [CurrenciesLib.sol:94]"); require(low <= up, "Bounds parameters mismatch [CurrenciesLib.sol:95]"); up = up.clampMax(self.currencies.length - 1); MonetaryTypesLib.Currency[] memory _currencies = new MonetaryTypesLib.Currency[](up - low + 1); for (uint256 i = low; i <= up; i++) _currencies[i - low] = self.currencies[i]; return _currencies; } } library FungibleBalanceLib { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; using CurrenciesLib for CurrenciesLib.Currencies; struct Record { int256 amount; uint256 blockNumber; } struct Balance { mapping(address => mapping(uint256 => int256)) amountByCurrency; mapping(address => mapping(uint256 => Record[])) recordsByCurrency; CurrenciesLib.Currencies inUseCurrencies; CurrenciesLib.Currencies everUsedCurrencies; } function get(Balance storage self, address currencyCt, uint256 currencyId) internal view returns (int256) { return self.amountByCurrency[currencyCt][currencyId]; } function getByBlockNumber(Balance storage self, address currencyCt, uint256 currencyId, uint256 blockNumber) internal view returns (int256) { (int256 amount,) = recordByBlockNumber(self, currencyCt, currencyId, blockNumber); return amount; } function set(Balance storage self, int256 amount, address currencyCt, uint256 currencyId) internal { self.amountByCurrency[currencyCt][currencyId] = amount; self.recordsByCurrency[currencyCt][currencyId].push( Record(self.amountByCurrency[currencyCt][currencyId], block.number) ); updateCurrencies(self, currencyCt, currencyId); } function setByBlockNumber(Balance storage self, int256 amount, address currencyCt, uint256 currencyId, uint256 blockNumber) internal { self.amountByCurrency[currencyCt][currencyId] = amount; self.recordsByCurrency[currencyCt][currencyId].push( Record(self.amountByCurrency[currencyCt][currencyId], blockNumber) ); updateCurrencies(self, currencyCt, currencyId); } function add(Balance storage self, int256 amount, address currencyCt, uint256 currencyId) internal { self.amountByCurrency[currencyCt][currencyId] = self.amountByCurrency[currencyCt][currencyId].add(amount); self.recordsByCurrency[currencyCt][currencyId].push( Record(self.amountByCurrency[currencyCt][currencyId], block.number) ); updateCurrencies(self, currencyCt, currencyId); } function addByBlockNumber(Balance storage self, int256 amount, address currencyCt, uint256 currencyId, uint256 blockNumber) internal { self.amountByCurrency[currencyCt][currencyId] = self.amountByCurrency[currencyCt][currencyId].add(amount); self.recordsByCurrency[currencyCt][currencyId].push( Record(self.amountByCurrency[currencyCt][currencyId], blockNumber) ); updateCurrencies(self, currencyCt, currencyId); } function sub(Balance storage self, int256 amount, address currencyCt, uint256 currencyId) internal { self.amountByCurrency[currencyCt][currencyId] = self.amountByCurrency[currencyCt][currencyId].sub(amount); self.recordsByCurrency[currencyCt][currencyId].push( Record(self.amountByCurrency[currencyCt][currencyId], block.number) ); updateCurrencies(self, currencyCt, currencyId); } function subByBlockNumber(Balance storage self, int256 amount, address currencyCt, uint256 currencyId, uint256 blockNumber) internal { self.amountByCurrency[currencyCt][currencyId] = self.amountByCurrency[currencyCt][currencyId].sub(amount); self.recordsByCurrency[currencyCt][currencyId].push( Record(self.amountByCurrency[currencyCt][currencyId], blockNumber) ); updateCurrencies(self, currencyCt, currencyId); } function transfer(Balance storage _from, Balance storage _to, int256 amount, address currencyCt, uint256 currencyId) internal { sub(_from, amount, currencyCt, currencyId); add(_to, amount, currencyCt, currencyId); } function add_nn(Balance storage self, int256 amount, address currencyCt, uint256 currencyId) internal { self.amountByCurrency[currencyCt][currencyId] = self.amountByCurrency[currencyCt][currencyId].add_nn(amount); self.recordsByCurrency[currencyCt][currencyId].push( Record(self.amountByCurrency[currencyCt][currencyId], block.number) ); updateCurrencies(self, currencyCt, currencyId); } function sub_nn(Balance storage self, int256 amount, address currencyCt, uint256 currencyId) internal { self.amountByCurrency[currencyCt][currencyId] = self.amountByCurrency[currencyCt][currencyId].sub_nn(amount); self.recordsByCurrency[currencyCt][currencyId].push( Record(self.amountByCurrency[currencyCt][currencyId], block.number) ); updateCurrencies(self, currencyCt, currencyId); } function transfer_nn(Balance storage _from, Balance storage _to, int256 amount, address currencyCt, uint256 currencyId) internal { sub_nn(_from, amount, currencyCt, currencyId); add_nn(_to, amount, currencyCt, currencyId); } function recordsCount(Balance storage self, address currencyCt, uint256 currencyId) internal view returns (uint256) { return self.recordsByCurrency[currencyCt][currencyId].length; } function recordByBlockNumber(Balance storage self, address currencyCt, uint256 currencyId, uint256 blockNumber) internal view returns (int256, uint256) { uint256 index = indexByBlockNumber(self, currencyCt, currencyId, blockNumber); return 0 < index ? recordByIndex(self, currencyCt, currencyId, index - 1) : (0, 0); } function recordByIndex(Balance storage self, address currencyCt, uint256 currencyId, uint256 index) internal view returns (int256, uint256) { if (0 == self.recordsByCurrency[currencyCt][currencyId].length) return (0, 0); index = index.clampMax(self.recordsByCurrency[currencyCt][currencyId].length - 1); Record storage record = self.recordsByCurrency[currencyCt][currencyId][index]; return (record.amount, record.blockNumber); } function lastRecord(Balance storage self, address currencyCt, uint256 currencyId) internal view returns (int256, uint256) { if (0 == self.recordsByCurrency[currencyCt][currencyId].length) return (0, 0); Record storage record = self.recordsByCurrency[currencyCt][currencyId][self.recordsByCurrency[currencyCt][currencyId].length - 1]; return (record.amount, record.blockNumber); } function hasInUseCurrency(Balance storage self, address currencyCt, uint256 currencyId) internal view returns (bool) { return self.inUseCurrencies.has(currencyCt, currencyId); } function hasEverUsedCurrency(Balance storage self, address currencyCt, uint256 currencyId) internal view returns (bool) { return self.everUsedCurrencies.has(currencyCt, currencyId); } function updateCurrencies(Balance storage self, address currencyCt, uint256 currencyId) internal { if (0 == self.amountByCurrency[currencyCt][currencyId] && self.inUseCurrencies.has(currencyCt, currencyId)) self.inUseCurrencies.removeByCurrency(currencyCt, currencyId); else if (!self.inUseCurrencies.has(currencyCt, currencyId)) { self.inUseCurrencies.add(currencyCt, currencyId); self.everUsedCurrencies.add(currencyCt, currencyId); } } function indexByBlockNumber(Balance storage self, address currencyCt, uint256 currencyId, uint256 blockNumber) internal view returns (uint256) { if (0 == self.recordsByCurrency[currencyCt][currencyId].length) return 0; for (uint256 i = self.recordsByCurrency[currencyCt][currencyId].length; i > 0; i--) if (self.recordsByCurrency[currencyCt][currencyId][i - 1].blockNumber <= blockNumber) return i; return 0; } } library NonFungibleBalanceLib { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; using CurrenciesLib for CurrenciesLib.Currencies; struct Record { int256[] ids; uint256 blockNumber; } struct Balance { mapping(address => mapping(uint256 => int256[])) idsByCurrency; mapping(address => mapping(uint256 => mapping(int256 => uint256))) idIndexById; mapping(address => mapping(uint256 => Record[])) recordsByCurrency; CurrenciesLib.Currencies inUseCurrencies; CurrenciesLib.Currencies everUsedCurrencies; } function get(Balance storage self, address currencyCt, uint256 currencyId) internal view returns (int256[] memory) { return self.idsByCurrency[currencyCt][currencyId]; } function getByIndices(Balance storage self, address currencyCt, uint256 currencyId, uint256 indexLow, uint256 indexUp) internal view returns (int256[] memory) { if (0 == self.idsByCurrency[currencyCt][currencyId].length) return new int256[](0); indexUp = indexUp.clampMax(self.idsByCurrency[currencyCt][currencyId].length - 1); int256[] memory idsByCurrency = new int256[](indexUp - indexLow + 1); for (uint256 i = indexLow; i < indexUp; i++) idsByCurrency[i - indexLow] = self.idsByCurrency[currencyCt][currencyId][i]; return idsByCurrency; } function idsCount(Balance storage self, address currencyCt, uint256 currencyId) internal view returns (uint256) { return self.idsByCurrency[currencyCt][currencyId].length; } function hasId(Balance storage self, int256 id, address currencyCt, uint256 currencyId) internal view returns (bool) { return 0 < self.idIndexById[currencyCt][currencyId][id]; } function recordByBlockNumber(Balance storage self, address currencyCt, uint256 currencyId, uint256 blockNumber) internal view returns (int256[] memory, uint256) { uint256 index = indexByBlockNumber(self, currencyCt, currencyId, blockNumber); return 0 < index ? recordByIndex(self, currencyCt, currencyId, index - 1) : (new int256[](0), 0); } function recordByIndex(Balance storage self, address currencyCt, uint256 currencyId, uint256 index) internal view returns (int256[] memory, uint256) { if (0 == self.recordsByCurrency[currencyCt][currencyId].length) return (new int256[](0), 0); index = index.clampMax(self.recordsByCurrency[currencyCt][currencyId].length - 1); Record storage record = self.recordsByCurrency[currencyCt][currencyId][index]; return (record.ids, record.blockNumber); } function lastRecord(Balance storage self, address currencyCt, uint256 currencyId) internal view returns (int256[] memory, uint256) { if (0 == self.recordsByCurrency[currencyCt][currencyId].length) return (new int256[](0), 0); Record storage record = self.recordsByCurrency[currencyCt][currencyId][self.recordsByCurrency[currencyCt][currencyId].length - 1]; return (record.ids, record.blockNumber); } function recordsCount(Balance storage self, address currencyCt, uint256 currencyId) internal view returns (uint256) { return self.recordsByCurrency[currencyCt][currencyId].length; } function set(Balance storage self, int256 id, address currencyCt, uint256 currencyId) internal { int256[] memory ids = new int256[](1); ids[0] = id; set(self, ids, currencyCt, currencyId); } function set(Balance storage self, int256[] memory ids, address currencyCt, uint256 currencyId) internal { uint256 i; for (i = 0; i < self.idsByCurrency[currencyCt][currencyId].length; i++) self.idIndexById[currencyCt][currencyId][self.idsByCurrency[currencyCt][currencyId][i]] = 0; self.idsByCurrency[currencyCt][currencyId] = ids; for (i = 0; i < self.idsByCurrency[currencyCt][currencyId].length; i++) self.idIndexById[currencyCt][currencyId][self.idsByCurrency[currencyCt][currencyId][i]] = i + 1; self.recordsByCurrency[currencyCt][currencyId].push( Record(self.idsByCurrency[currencyCt][currencyId], block.number) ); updateInUseCurrencies(self, currencyCt, currencyId); } function reset(Balance storage self, address currencyCt, uint256 currencyId) internal { for (uint256 i = 0; i < self.idsByCurrency[currencyCt][currencyId].length; i++) self.idIndexById[currencyCt][currencyId][self.idsByCurrency[currencyCt][currencyId][i]] = 0; self.idsByCurrency[currencyCt][currencyId].length = 0; self.recordsByCurrency[currencyCt][currencyId].push( Record(self.idsByCurrency[currencyCt][currencyId], block.number) ); updateInUseCurrencies(self, currencyCt, currencyId); } function add(Balance storage self, int256 id, address currencyCt, uint256 currencyId) internal returns (bool) { if (0 < self.idIndexById[currencyCt][currencyId][id]) return false; self.idsByCurrency[currencyCt][currencyId].push(id); self.idIndexById[currencyCt][currencyId][id] = self.idsByCurrency[currencyCt][currencyId].length; self.recordsByCurrency[currencyCt][currencyId].push( Record(self.idsByCurrency[currencyCt][currencyId], block.number) ); updateInUseCurrencies(self, currencyCt, currencyId); return true; } function sub(Balance storage self, int256 id, address currencyCt, uint256 currencyId) internal returns (bool) { uint256 index = self.idIndexById[currencyCt][currencyId][id]; if (0 == index) return false; if (index < self.idsByCurrency[currencyCt][currencyId].length) { self.idsByCurrency[currencyCt][currencyId][index - 1] = self.idsByCurrency[currencyCt][currencyId][self.idsByCurrency[currencyCt][currencyId].length - 1]; self.idIndexById[currencyCt][currencyId][self.idsByCurrency[currencyCt][currencyId][index - 1]] = index; } self.idsByCurrency[currencyCt][currencyId].length--; self.idIndexById[currencyCt][currencyId][id] = 0; self.recordsByCurrency[currencyCt][currencyId].push( Record(self.idsByCurrency[currencyCt][currencyId], block.number) ); updateInUseCurrencies(self, currencyCt, currencyId); return true; } function transfer(Balance storage _from, Balance storage _to, int256 id, address currencyCt, uint256 currencyId) internal returns (bool) { return sub(_from, id, currencyCt, currencyId) && add(_to, id, currencyCt, currencyId); } function hasInUseCurrency(Balance storage self, address currencyCt, uint256 currencyId) internal view returns (bool) { return self.inUseCurrencies.has(currencyCt, currencyId); } function hasEverUsedCurrency(Balance storage self, address currencyCt, uint256 currencyId) internal view returns (bool) { return self.everUsedCurrencies.has(currencyCt, currencyId); } function updateInUseCurrencies(Balance storage self, address currencyCt, uint256 currencyId) internal { if (0 == self.idsByCurrency[currencyCt][currencyId].length && self.inUseCurrencies.has(currencyCt, currencyId)) self.inUseCurrencies.removeByCurrency(currencyCt, currencyId); else if (!self.inUseCurrencies.has(currencyCt, currencyId)) { self.inUseCurrencies.add(currencyCt, currencyId); self.everUsedCurrencies.add(currencyCt, currencyId); } } function indexByBlockNumber(Balance storage self, address currencyCt, uint256 currencyId, uint256 blockNumber) internal view returns (uint256) { if (0 == self.recordsByCurrency[currencyCt][currencyId].length) return 0; for (uint256 i = self.recordsByCurrency[currencyCt][currencyId].length; i > 0; i--) if (self.recordsByCurrency[currencyCt][currencyId][i - 1].blockNumber <= blockNumber) return i; return 0; } } contract BalanceTracker is Ownable, Servable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; using FungibleBalanceLib for FungibleBalanceLib.Balance; using NonFungibleBalanceLib for NonFungibleBalanceLib.Balance; string constant public DEPOSITED_BALANCE_TYPE = "deposited"; string constant public SETTLED_BALANCE_TYPE = "settled"; string constant public STAGED_BALANCE_TYPE = "staged"; struct Wallet { mapping(bytes32 => FungibleBalanceLib.Balance) fungibleBalanceByType; mapping(bytes32 => NonFungibleBalanceLib.Balance) nonFungibleBalanceByType; } bytes32 public depositedBalanceType; bytes32 public settledBalanceType; bytes32 public stagedBalanceType; bytes32[] public _allBalanceTypes; bytes32[] public _activeBalanceTypes; bytes32[] public trackedBalanceTypes; mapping(bytes32 => bool) public trackedBalanceTypeMap; mapping(address => Wallet) private walletMap; address[] public trackedWallets; mapping(address => uint256) public trackedWalletIndexByWallet; constructor(address deployer) Ownable(deployer) public { depositedBalanceType = keccak256(abi.encodePacked(DEPOSITED_BALANCE_TYPE)); settledBalanceType = keccak256(abi.encodePacked(SETTLED_BALANCE_TYPE)); stagedBalanceType = keccak256(abi.encodePacked(STAGED_BALANCE_TYPE)); _allBalanceTypes.push(settledBalanceType); _allBalanceTypes.push(depositedBalanceType); _allBalanceTypes.push(stagedBalanceType); _activeBalanceTypes.push(settledBalanceType); _activeBalanceTypes.push(depositedBalanceType); } function get(address wallet, bytes32 _type, address currencyCt, uint256 currencyId) public view returns (int256) { return walletMap[wallet].fungibleBalanceByType[_type].get(currencyCt, currencyId); } function getByIndices(address wallet, bytes32 _type, address currencyCt, uint256 currencyId, uint256 indexLow, uint256 indexUp) public view returns (int256[] memory) { return walletMap[wallet].nonFungibleBalanceByType[_type].getByIndices( currencyCt, currencyId, indexLow, indexUp ); } function getAll(address wallet, bytes32 _type, address currencyCt, uint256 currencyId) public view returns (int256[] memory) { return walletMap[wallet].nonFungibleBalanceByType[_type].get( currencyCt, currencyId ); } function idsCount(address wallet, bytes32 _type, address currencyCt, uint256 currencyId) public view returns (uint256) { return walletMap[wallet].nonFungibleBalanceByType[_type].idsCount( currencyCt, currencyId ); } function hasId(address wallet, bytes32 _type, int256 id, address currencyCt, uint256 currencyId) public view returns (bool) { return walletMap[wallet].nonFungibleBalanceByType[_type].hasId( id, currencyCt, currencyId ); } function set(address wallet, bytes32 _type, int256 value, address currencyCt, uint256 currencyId, bool fungible) public onlyActiveService { if (fungible) walletMap[wallet].fungibleBalanceByType[_type].set( value, currencyCt, currencyId ); else walletMap[wallet].nonFungibleBalanceByType[_type].set( value, currencyCt, currencyId ); _updateTrackedBalanceTypes(_type); _updateTrackedWallets(wallet); } function setIds(address wallet, bytes32 _type, int256[] memory ids, address currencyCt, uint256 currencyId) public onlyActiveService { walletMap[wallet].nonFungibleBalanceByType[_type].set( ids, currencyCt, currencyId ); _updateTrackedBalanceTypes(_type); _updateTrackedWallets(wallet); } function add(address wallet, bytes32 _type, int256 value, address currencyCt, uint256 currencyId, bool fungible) public onlyActiveService { if (fungible) walletMap[wallet].fungibleBalanceByType[_type].add( value, currencyCt, currencyId ); else walletMap[wallet].nonFungibleBalanceByType[_type].add( value, currencyCt, currencyId ); _updateTrackedBalanceTypes(_type); _updateTrackedWallets(wallet); } function sub(address wallet, bytes32 _type, int256 value, address currencyCt, uint256 currencyId, bool fungible) public onlyActiveService { if (fungible) walletMap[wallet].fungibleBalanceByType[_type].sub( value, currencyCt, currencyId ); else walletMap[wallet].nonFungibleBalanceByType[_type].sub( value, currencyCt, currencyId ); _updateTrackedWallets(wallet); } function hasInUseCurrency(address wallet, bytes32 _type, address currencyCt, uint256 currencyId) public view returns (bool) { return walletMap[wallet].fungibleBalanceByType[_type].hasInUseCurrency(currencyCt, currencyId) || walletMap[wallet].nonFungibleBalanceByType[_type].hasInUseCurrency(currencyCt, currencyId); } function hasEverUsedCurrency(address wallet, bytes32 _type, address currencyCt, uint256 currencyId) public view returns (bool) { return walletMap[wallet].fungibleBalanceByType[_type].hasEverUsedCurrency(currencyCt, currencyId) || walletMap[wallet].nonFungibleBalanceByType[_type].hasEverUsedCurrency(currencyCt, currencyId); } function fungibleRecordsCount(address wallet, bytes32 _type, address currencyCt, uint256 currencyId) public view returns (uint256) { return walletMap[wallet].fungibleBalanceByType[_type].recordsCount(currencyCt, currencyId); } function fungibleRecordByIndex(address wallet, bytes32 _type, address currencyCt, uint256 currencyId, uint256 index) public view returns (int256 amount, uint256 blockNumber) { return walletMap[wallet].fungibleBalanceByType[_type].recordByIndex(currencyCt, currencyId, index); } function fungibleRecordByBlockNumber(address wallet, bytes32 _type, address currencyCt, uint256 currencyId, uint256 _blockNumber) public view returns (int256 amount, uint256 blockNumber) { return walletMap[wallet].fungibleBalanceByType[_type].recordByBlockNumber(currencyCt, currencyId, _blockNumber); } function lastFungibleRecord(address wallet, bytes32 _type, address currencyCt, uint256 currencyId) public view returns (int256 amount, uint256 blockNumber) { return walletMap[wallet].fungibleBalanceByType[_type].lastRecord(currencyCt, currencyId); } function nonFungibleRecordsCount(address wallet, bytes32 _type, address currencyCt, uint256 currencyId) public view returns (uint256) { return walletMap[wallet].nonFungibleBalanceByType[_type].recordsCount(currencyCt, currencyId); } function nonFungibleRecordByIndex(address wallet, bytes32 _type, address currencyCt, uint256 currencyId, uint256 index) public view returns (int256[] memory ids, uint256 blockNumber) { return walletMap[wallet].nonFungibleBalanceByType[_type].recordByIndex(currencyCt, currencyId, index); } function nonFungibleRecordByBlockNumber(address wallet, bytes32 _type, address currencyCt, uint256 currencyId, uint256 _blockNumber) public view returns (int256[] memory ids, uint256 blockNumber) { return walletMap[wallet].nonFungibleBalanceByType[_type].recordByBlockNumber(currencyCt, currencyId, _blockNumber); } function lastNonFungibleRecord(address wallet, bytes32 _type, address currencyCt, uint256 currencyId) public view returns (int256[] memory ids, uint256 blockNumber) { return walletMap[wallet].nonFungibleBalanceByType[_type].lastRecord(currencyCt, currencyId); } function trackedBalanceTypesCount() public view returns (uint256) { return trackedBalanceTypes.length; } function trackedWalletsCount() public view returns (uint256) { return trackedWallets.length; } function allBalanceTypes() public view returns (bytes32[] memory) { return _allBalanceTypes; } function activeBalanceTypes() public view returns (bytes32[] memory) { return _activeBalanceTypes; } function trackedWalletsByIndices(uint256 low, uint256 up) public view returns (address[] memory) { require(0 < trackedWallets.length, "No tracked wallets found [BalanceTracker.sol:473]"); require(low <= up, "Bounds parameters mismatch [BalanceTracker.sol:474]"); up = up.clampMax(trackedWallets.length - 1); address[] memory _trackedWallets = new address[](up - low + 1); for (uint256 i = low; i <= up; i++) _trackedWallets[i - low] = trackedWallets[i]; return _trackedWallets; } function _updateTrackedBalanceTypes(bytes32 _type) private { if (!trackedBalanceTypeMap[_type]) { trackedBalanceTypeMap[_type] = true; trackedBalanceTypes.push(_type); } } function _updateTrackedWallets(address wallet) private { if (0 == trackedWalletIndexByWallet[wallet]) { trackedWallets.push(wallet); trackedWalletIndexByWallet[wallet] = trackedWallets.length; } } } contract BalanceTrackable is Ownable { BalanceTracker public balanceTracker; bool public balanceTrackerFrozen; event SetBalanceTrackerEvent(BalanceTracker oldBalanceTracker, BalanceTracker newBalanceTracker); event FreezeBalanceTrackerEvent(); function setBalanceTracker(BalanceTracker newBalanceTracker) public onlyDeployer notNullAddress(address(newBalanceTracker)) notSameAddresses(address(newBalanceTracker), address(balanceTracker)) { require(!balanceTrackerFrozen, "Balance tracker frozen [BalanceTrackable.sol:43]"); BalanceTracker oldBalanceTracker = balanceTracker; balanceTracker = newBalanceTracker; emit SetBalanceTrackerEvent(oldBalanceTracker, newBalanceTracker); } function freezeBalanceTracker() public onlyDeployer { balanceTrackerFrozen = true; emit FreezeBalanceTrackerEvent(); } modifier balanceTrackerInitialized() { require(address(balanceTracker) != address(0), "Balance tracker not initialized [BalanceTrackable.sol:69]"); _; } } contract TransactionTracker is Ownable, Servable { struct TransactionRecord { int256 value; uint256 blockNumber; address currencyCt; uint256 currencyId; } struct TransactionLog { TransactionRecord[] records; mapping(address => mapping(uint256 => uint256[])) recordIndicesByCurrency; } string constant public DEPOSIT_TRANSACTION_TYPE = "deposit"; string constant public WITHDRAWAL_TRANSACTION_TYPE = "withdrawal"; bytes32 public depositTransactionType; bytes32 public withdrawalTransactionType; mapping(address => mapping(bytes32 => TransactionLog)) private transactionLogByWalletType; constructor(address deployer) Ownable(deployer) public { depositTransactionType = keccak256(abi.encodePacked(DEPOSIT_TRANSACTION_TYPE)); withdrawalTransactionType = keccak256(abi.encodePacked(WITHDRAWAL_TRANSACTION_TYPE)); } function add(address wallet, bytes32 _type, int256 value, address currencyCt, uint256 currencyId) public onlyActiveService { transactionLogByWalletType[wallet][_type].records.length++; uint256 index = transactionLogByWalletType[wallet][_type].records.length - 1; transactionLogByWalletType[wallet][_type].records[index].value = value; transactionLogByWalletType[wallet][_type].records[index].blockNumber = block.number; transactionLogByWalletType[wallet][_type].records[index].currencyCt = currencyCt; transactionLogByWalletType[wallet][_type].records[index].currencyId = currencyId; transactionLogByWalletType[wallet][_type].recordIndicesByCurrency[currencyCt][currencyId].push(index); } function count(address wallet, bytes32 _type) public view returns (uint256) { return transactionLogByWalletType[wallet][_type].records.length; } function getByIndex(address wallet, bytes32 _type, uint256 index) public view returns (int256 value, uint256 blockNumber, address currencyCt, uint256 currencyId) { TransactionRecord storage entry = transactionLogByWalletType[wallet][_type].records[index]; value = entry.value; blockNumber = entry.blockNumber; currencyCt = entry.currencyCt; currencyId = entry.currencyId; } function getByBlockNumber(address wallet, bytes32 _type, uint256 _blockNumber) public view returns (int256 value, uint256 blockNumber, address currencyCt, uint256 currencyId) { return getByIndex(wallet, _type, _indexByBlockNumber(wallet, _type, _blockNumber)); } function countByCurrency(address wallet, bytes32 _type, address currencyCt, uint256 currencyId) public view returns (uint256) { return transactionLogByWalletType[wallet][_type].recordIndicesByCurrency[currencyCt][currencyId].length; } function getByCurrencyIndex(address wallet, bytes32 _type, address currencyCt, uint256 currencyId, uint256 index) public view returns (int256 value, uint256 blockNumber) { uint256 entryIndex = transactionLogByWalletType[wallet][_type].recordIndicesByCurrency[currencyCt][currencyId][index]; TransactionRecord storage entry = transactionLogByWalletType[wallet][_type].records[entryIndex]; value = entry.value; blockNumber = entry.blockNumber; } function getByCurrencyBlockNumber(address wallet, bytes32 _type, address currencyCt, uint256 currencyId, uint256 _blockNumber) public view returns (int256 value, uint256 blockNumber) { return getByCurrencyIndex( wallet, _type, currencyCt, currencyId, _indexByCurrencyBlockNumber( wallet, _type, currencyCt, currencyId, _blockNumber ) ); } function _indexByBlockNumber(address wallet, bytes32 _type, uint256 blockNumber) private view returns (uint256) { require( 0 < transactionLogByWalletType[wallet][_type].records.length, "No transactions found for wallet and type [TransactionTracker.sol:187]" ); for (uint256 i = transactionLogByWalletType[wallet][_type].records.length - 1; i >= 0; i--) if (blockNumber >= transactionLogByWalletType[wallet][_type].records[i].blockNumber) return i; revert(); } function _indexByCurrencyBlockNumber(address wallet, bytes32 _type, address currencyCt, uint256 currencyId, uint256 blockNumber) private view returns (uint256) { require( 0 < transactionLogByWalletType[wallet][_type].recordIndicesByCurrency[currencyCt][currencyId].length, "No transactions found for wallet, type and currency [TransactionTracker.sol:203]" ); for (uint256 i = transactionLogByWalletType[wallet][_type].recordIndicesByCurrency[currencyCt][currencyId].length - 1; i >= 0; i--) { uint256 j = transactionLogByWalletType[wallet][_type].recordIndicesByCurrency[currencyCt][currencyId][i]; if (blockNumber >= transactionLogByWalletType[wallet][_type].records[j].blockNumber) return j; } revert(); } } contract TransactionTrackable is Ownable { TransactionTracker public transactionTracker; bool public transactionTrackerFrozen; event SetTransactionTrackerEvent(TransactionTracker oldTransactionTracker, TransactionTracker newTransactionTracker); event FreezeTransactionTrackerEvent(); function setTransactionTracker(TransactionTracker newTransactionTracker) public onlyDeployer notNullAddress(address(newTransactionTracker)) notSameAddresses(address(newTransactionTracker), address(transactionTracker)) { require(!transactionTrackerFrozen, "Transaction tracker frozen [TransactionTrackable.sol:43]"); TransactionTracker oldTransactionTracker = transactionTracker; transactionTracker = newTransactionTracker; emit SetTransactionTrackerEvent(oldTransactionTracker, newTransactionTracker); } function freezeTransactionTracker() public onlyDeployer { transactionTrackerFrozen = true; emit FreezeTransactionTrackerEvent(); } modifier transactionTrackerInitialized() { require(address(transactionTracker) != address(0), "Transaction track not initialized [TransactionTrackable.sol:69]"); _; } } contract WalletLocker is Ownable, Configurable, AuthorizableServable { using SafeMathUintLib for uint256; struct FungibleLock { address locker; address currencyCt; uint256 currencyId; int256 amount; uint256 visibleTime; uint256 unlockTime; } struct NonFungibleLock { address locker; address currencyCt; uint256 currencyId; int256[] ids; uint256 visibleTime; uint256 unlockTime; } mapping(address => FungibleLock[]) public walletFungibleLocks; mapping(address => mapping(address => mapping(uint256 => mapping(address => uint256)))) public lockedCurrencyLockerFungibleLockIndex; mapping(address => mapping(address => mapping(uint256 => uint256))) public walletCurrencyFungibleLockCount; mapping(address => NonFungibleLock[]) public walletNonFungibleLocks; mapping(address => mapping(address => mapping(uint256 => mapping(address => uint256)))) public lockedCurrencyLockerNonFungibleLockIndex; mapping(address => mapping(address => mapping(uint256 => uint256))) public walletCurrencyNonFungibleLockCount; event LockFungibleByProxyEvent(address lockedWallet, address lockerWallet, int256 amount, address currencyCt, uint256 currencyId, uint256 visibleTimeoutInSeconds); event LockNonFungibleByProxyEvent(address lockedWallet, address lockerWallet, int256[] ids, address currencyCt, uint256 currencyId, uint256 visibleTimeoutInSeconds); event UnlockFungibleEvent(address lockedWallet, address lockerWallet, int256 amount, address currencyCt, uint256 currencyId); event UnlockFungibleByProxyEvent(address lockedWallet, address lockerWallet, int256 amount, address currencyCt, uint256 currencyId); event UnlockNonFungibleEvent(address lockedWallet, address lockerWallet, int256[] ids, address currencyCt, uint256 currencyId); event UnlockNonFungibleByProxyEvent(address lockedWallet, address lockerWallet, int256[] ids, address currencyCt, uint256 currencyId); constructor(address deployer) Ownable(deployer) public { } function lockFungibleByProxy(address lockedWallet, address lockerWallet, int256 amount, address currencyCt, uint256 currencyId, uint256 visibleTimeoutInSeconds) public onlyAuthorizedService(lockedWallet) { require(lockedWallet != lockerWallet); uint256 lockIndex = lockedCurrencyLockerFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockedWallet]; require( (0 == lockIndex) || (block.timestamp >= walletFungibleLocks[lockedWallet][lockIndex - 1].unlockTime) ); if (0 == lockIndex) { lockIndex = ++(walletFungibleLocks[lockedWallet].length); lockedCurrencyLockerFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet] = lockIndex; walletCurrencyFungibleLockCount[lockedWallet][currencyCt][currencyId]++; } walletFungibleLocks[lockedWallet][lockIndex - 1].locker = lockerWallet; walletFungibleLocks[lockedWallet][lockIndex - 1].amount = amount; walletFungibleLocks[lockedWallet][lockIndex - 1].currencyCt = currencyCt; walletFungibleLocks[lockedWallet][lockIndex - 1].currencyId = currencyId; walletFungibleLocks[lockedWallet][lockIndex - 1].visibleTime = block.timestamp.add(visibleTimeoutInSeconds); walletFungibleLocks[lockedWallet][lockIndex - 1].unlockTime = block.timestamp.add(configuration.walletLockTimeout()); emit LockFungibleByProxyEvent(lockedWallet, lockerWallet, amount, currencyCt, currencyId, visibleTimeoutInSeconds); } function lockNonFungibleByProxy(address lockedWallet, address lockerWallet, int256[] memory ids, address currencyCt, uint256 currencyId, uint256 visibleTimeoutInSeconds) public onlyAuthorizedService(lockedWallet) { require(lockedWallet != lockerWallet); uint256 lockIndex = lockedCurrencyLockerNonFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockedWallet]; require( (0 == lockIndex) || (block.timestamp >= walletNonFungibleLocks[lockedWallet][lockIndex - 1].unlockTime) ); if (0 == lockIndex) { lockIndex = ++(walletNonFungibleLocks[lockedWallet].length); lockedCurrencyLockerNonFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet] = lockIndex; walletCurrencyNonFungibleLockCount[lockedWallet][currencyCt][currencyId]++; } walletNonFungibleLocks[lockedWallet][lockIndex - 1].locker = lockerWallet; walletNonFungibleLocks[lockedWallet][lockIndex - 1].ids = ids; walletNonFungibleLocks[lockedWallet][lockIndex - 1].currencyCt = currencyCt; walletNonFungibleLocks[lockedWallet][lockIndex - 1].currencyId = currencyId; walletNonFungibleLocks[lockedWallet][lockIndex - 1].visibleTime = block.timestamp.add(visibleTimeoutInSeconds); walletNonFungibleLocks[lockedWallet][lockIndex - 1].unlockTime = block.timestamp.add(configuration.walletLockTimeout()); emit LockNonFungibleByProxyEvent(lockedWallet, lockerWallet, ids, currencyCt, currencyId, visibleTimeoutInSeconds); } function unlockFungible(address lockedWallet, address lockerWallet, address currencyCt, uint256 currencyId) public { uint256 lockIndex = lockedCurrencyLockerFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet]; if (0 == lockIndex) return; require( block.timestamp >= walletFungibleLocks[lockedWallet][lockIndex - 1].unlockTime ); int256 amount = _unlockFungible(lockedWallet, lockerWallet, currencyCt, currencyId, lockIndex); emit UnlockFungibleEvent(lockedWallet, lockerWallet, amount, currencyCt, currencyId); } function unlockFungibleByProxy(address lockedWallet, address lockerWallet, address currencyCt, uint256 currencyId) public onlyAuthorizedService(lockedWallet) { uint256 lockIndex = lockedCurrencyLockerFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet]; if (0 == lockIndex) return; int256 amount = _unlockFungible(lockedWallet, lockerWallet, currencyCt, currencyId, lockIndex); emit UnlockFungibleByProxyEvent(lockedWallet, lockerWallet, amount, currencyCt, currencyId); } function unlockNonFungible(address lockedWallet, address lockerWallet, address currencyCt, uint256 currencyId) public { uint256 lockIndex = lockedCurrencyLockerNonFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet]; if (0 == lockIndex) return; require( block.timestamp >= walletNonFungibleLocks[lockedWallet][lockIndex - 1].unlockTime ); int256[] memory ids = _unlockNonFungible(lockedWallet, lockerWallet, currencyCt, currencyId, lockIndex); emit UnlockNonFungibleEvent(lockedWallet, lockerWallet, ids, currencyCt, currencyId); } function unlockNonFungibleByProxy(address lockedWallet, address lockerWallet, address currencyCt, uint256 currencyId) public onlyAuthorizedService(lockedWallet) { uint256 lockIndex = lockedCurrencyLockerNonFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet]; if (0 == lockIndex) return; int256[] memory ids = _unlockNonFungible(lockedWallet, lockerWallet, currencyCt, currencyId, lockIndex); emit UnlockNonFungibleByProxyEvent(lockedWallet, lockerWallet, ids, currencyCt, currencyId); } function fungibleLocksCount(address wallet) public view returns (uint256) { return walletFungibleLocks[wallet].length; } function nonFungibleLocksCount(address wallet) public view returns (uint256) { return walletNonFungibleLocks[wallet].length; } function lockedAmount(address lockedWallet, address lockerWallet, address currencyCt, uint256 currencyId) public view returns (int256) { uint256 lockIndex = lockedCurrencyLockerFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet]; if (0 == lockIndex || block.timestamp < walletFungibleLocks[lockedWallet][lockIndex - 1].visibleTime) return 0; return walletFungibleLocks[lockedWallet][lockIndex - 1].amount; } function lockedIdsCount(address lockedWallet, address lockerWallet, address currencyCt, uint256 currencyId) public view returns (uint256) { uint256 lockIndex = lockedCurrencyLockerNonFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet]; if (0 == lockIndex || block.timestamp < walletNonFungibleLocks[lockedWallet][lockIndex - 1].visibleTime) return 0; return walletNonFungibleLocks[lockedWallet][lockIndex - 1].ids.length; } function lockedIdsByIndices(address lockedWallet, address lockerWallet, address currencyCt, uint256 currencyId, uint256 low, uint256 up) public view returns (int256[] memory) { uint256 lockIndex = lockedCurrencyLockerNonFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet]; if (0 == lockIndex || block.timestamp < walletNonFungibleLocks[lockedWallet][lockIndex - 1].visibleTime) return new int256[](0); NonFungibleLock storage lock = walletNonFungibleLocks[lockedWallet][lockIndex - 1]; if (0 == lock.ids.length) return new int256[](0); up = up.clampMax(lock.ids.length - 1); int256[] memory _ids = new int256[](up - low + 1); for (uint256 i = low; i <= up; i++) _ids[i - low] = lock.ids[i]; return _ids; } function isLocked(address wallet) public view returns (bool) { return 0 < walletFungibleLocks[wallet].length || 0 < walletNonFungibleLocks[wallet].length; } function isLocked(address wallet, address currencyCt, uint256 currencyId) public view returns (bool) { return 0 < walletCurrencyFungibleLockCount[wallet][currencyCt][currencyId] || 0 < walletCurrencyNonFungibleLockCount[wallet][currencyCt][currencyId]; } function isLocked(address lockedWallet, address lockerWallet, address currencyCt, uint256 currencyId) public view returns (bool) { return 0 < lockedCurrencyLockerFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet] || 0 < lockedCurrencyLockerNonFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet]; } function _unlockFungible(address lockedWallet, address lockerWallet, address currencyCt, uint256 currencyId, uint256 lockIndex) private returns (int256) { int256 amount = walletFungibleLocks[lockedWallet][lockIndex - 1].amount; if (lockIndex < walletFungibleLocks[lockedWallet].length) { walletFungibleLocks[lockedWallet][lockIndex - 1] = walletFungibleLocks[lockedWallet][walletFungibleLocks[lockedWallet].length - 1]; lockedCurrencyLockerFungibleLockIndex[lockedWallet][currencyCt][currencyId][walletFungibleLocks[lockedWallet][lockIndex - 1].locker] = lockIndex; } walletFungibleLocks[lockedWallet].length--; lockedCurrencyLockerFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet] = 0; walletCurrencyFungibleLockCount[lockedWallet][currencyCt][currencyId]--; return amount; } function _unlockNonFungible(address lockedWallet, address lockerWallet, address currencyCt, uint256 currencyId, uint256 lockIndex) private returns (int256[] memory) { int256[] memory ids = walletNonFungibleLocks[lockedWallet][lockIndex - 1].ids; if (lockIndex < walletNonFungibleLocks[lockedWallet].length) { walletNonFungibleLocks[lockedWallet][lockIndex - 1] = walletNonFungibleLocks[lockedWallet][walletNonFungibleLocks[lockedWallet].length - 1]; lockedCurrencyLockerNonFungibleLockIndex[lockedWallet][currencyCt][currencyId][walletNonFungibleLocks[lockedWallet][lockIndex - 1].locker] = lockIndex; } walletNonFungibleLocks[lockedWallet].length--; lockedCurrencyLockerNonFungibleLockIndex[lockedWallet][currencyCt][currencyId][lockerWallet] = 0; walletCurrencyNonFungibleLockCount[lockedWallet][currencyCt][currencyId]--; return ids; } } contract WalletLockable is Ownable { WalletLocker public walletLocker; bool public walletLockerFrozen; event SetWalletLockerEvent(WalletLocker oldWalletLocker, WalletLocker newWalletLocker); event FreezeWalletLockerEvent(); function setWalletLocker(WalletLocker newWalletLocker) public onlyDeployer notNullAddress(address(newWalletLocker)) notSameAddresses(address(newWalletLocker), address(walletLocker)) { require(!walletLockerFrozen, "Wallet locker frozen [WalletLockable.sol:43]"); WalletLocker oldWalletLocker = walletLocker; walletLocker = newWalletLocker; emit SetWalletLockerEvent(oldWalletLocker, newWalletLocker); } function freezeWalletLocker() public onlyDeployer { walletLockerFrozen = true; emit FreezeWalletLockerEvent(); } modifier walletLockerInitialized() { require(address(walletLocker) != address(0), "Wallet locker not initialized [WalletLockable.sol:69]"); _; } } contract AccrualBeneficiary is Beneficiary { event CloseAccrualPeriodEvent(); function closeAccrualPeriod(MonetaryTypesLib.Currency[] memory) public { emit CloseAccrualPeriodEvent(); } } library TxHistoryLib { struct AssetEntry { int256 amount; uint256 blockNumber; address currencyCt; uint256 currencyId; } struct TxHistory { AssetEntry[] deposits; mapping(address => mapping(uint256 => AssetEntry[])) currencyDeposits; AssetEntry[] withdrawals; mapping(address => mapping(uint256 => AssetEntry[])) currencyWithdrawals; } function addDeposit(TxHistory storage self, int256 amount, address currencyCt, uint256 currencyId) internal { AssetEntry memory deposit = AssetEntry(amount, block.number, currencyCt, currencyId); self.deposits.push(deposit); self.currencyDeposits[currencyCt][currencyId].push(deposit); } function addWithdrawal(TxHistory storage self, int256 amount, address currencyCt, uint256 currencyId) internal { AssetEntry memory withdrawal = AssetEntry(amount, block.number, currencyCt, currencyId); self.withdrawals.push(withdrawal); self.currencyWithdrawals[currencyCt][currencyId].push(withdrawal); } function deposit(TxHistory storage self, uint index) internal view returns (int256 amount, uint256 blockNumber, address currencyCt, uint256 currencyId) { require(index < self.deposits.length, "Index ouf of bounds [TxHistoryLib.sol:56]"); amount = self.deposits[index].amount; blockNumber = self.deposits[index].blockNumber; currencyCt = self.deposits[index].currencyCt; currencyId = self.deposits[index].currencyId; } function depositsCount(TxHistory storage self) internal view returns (uint256) { return self.deposits.length; } function currencyDeposit(TxHistory storage self, address currencyCt, uint256 currencyId, uint index) internal view returns (int256 amount, uint256 blockNumber) { require(index < self.currencyDeposits[currencyCt][currencyId].length, "Index out of bounds [TxHistoryLib.sol:77]"); amount = self.currencyDeposits[currencyCt][currencyId][index].amount; blockNumber = self.currencyDeposits[currencyCt][currencyId][index].blockNumber; } function currencyDepositsCount(TxHistory storage self, address currencyCt, uint256 currencyId) internal view returns (uint256) { return self.currencyDeposits[currencyCt][currencyId].length; } function withdrawal(TxHistory storage self, uint index) internal view returns (int256 amount, uint256 blockNumber, address currencyCt, uint256 currencyId) { require(index < self.withdrawals.length, "Index out of bounds [TxHistoryLib.sol:98]"); amount = self.withdrawals[index].amount; blockNumber = self.withdrawals[index].blockNumber; currencyCt = self.withdrawals[index].currencyCt; currencyId = self.withdrawals[index].currencyId; } function withdrawalsCount(TxHistory storage self) internal view returns (uint256) { return self.withdrawals.length; } function currencyWithdrawal(TxHistory storage self, address currencyCt, uint256 currencyId, uint index) internal view returns (int256 amount, uint256 blockNumber) { require(index < self.currencyWithdrawals[currencyCt][currencyId].length, "Index out of bounds [TxHistoryLib.sol:119]"); amount = self.currencyWithdrawals[currencyCt][currencyId][index].amount; blockNumber = self.currencyWithdrawals[currencyCt][currencyId][index].blockNumber; } function currencyWithdrawalsCount(TxHistory storage self, address currencyCt, uint256 currencyId) internal view returns (uint256) { return self.currencyWithdrawals[currencyCt][currencyId].length; } } interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); uint256 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); uint256 c = a / b; return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } } contract ERC20 is IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; function totalSupply() public view returns (uint256) { return _totalSupply; } function balanceOf(address account) public view returns (uint256) { return _balances[account]; } function transfer(address recipient, uint256 amount) public returns (bool) { _transfer(msg.sender, recipient, amount); return true; } function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } function approve(address spender, uint256 value) public returns (bool) { _approve(msg.sender, spender, value); return true; } function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { _transfer(sender, recipient, amount); _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount)); return true; } function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)); return true; } function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue)); return true; } function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } function _burn(address account, uint256 value) internal { require(account != address(0), "ERC20: burn from the zero address"); _totalSupply = _totalSupply.sub(value); _balances[account] = _balances[account].sub(value); emit Transfer(account, address(0), value); } function _approve(address owner, address spender, uint256 value) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = value; emit Approval(owner, spender, value); } function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, msg.sender, _allowances[account][msg.sender].sub(amount)); } } library Roles { struct Role { mapping (address => bool) bearer; } function add(Role storage role, address account) internal { require(!has(role, account), "Roles: account already has role"); role.bearer[account] = true; } function remove(Role storage role, address account) internal { require(has(role, account), "Roles: account does not have role"); role.bearer[account] = false; } function has(Role storage role, address account) internal view returns (bool) { require(account != address(0), "Roles: account is the zero address"); return role.bearer[account]; } } contract MinterRole { using Roles for Roles.Role; event MinterAdded(address indexed account); event MinterRemoved(address indexed account); Roles.Role private _minters; constructor () internal { _addMinter(msg.sender); } modifier onlyMinter() { require(isMinter(msg.sender), "MinterRole: caller does not have the Minter role"); _; } function isMinter(address account) public view returns (bool) { return _minters.has(account); } function addMinter(address account) public onlyMinter { _addMinter(account); } function renounceMinter() public { _removeMinter(msg.sender); } function _addMinter(address account) internal { _minters.add(account); emit MinterAdded(account); } function _removeMinter(address account) internal { _minters.remove(account); emit MinterRemoved(account); } } contract ERC20Mintable is ERC20, MinterRole { function mint(address account, uint256 amount) public onlyMinter returns (bool) { _mint(account, amount); return true; } } contract RevenueToken is ERC20Mintable { using SafeMath for uint256; bool public mintingDisabled; address[] public holders; mapping(address => bool) public holdersMap; mapping(address => uint256[]) public balances; mapping(address => uint256[]) public balanceBlocks; mapping(address => uint256[]) public balanceBlockNumbers; event DisableMinting(); function disableMinting() public onlyMinter { mintingDisabled = true; emit DisableMinting(); } function mint(address to, uint256 value) public onlyMinter returns (bool) { require(!mintingDisabled, "Minting disabled [RevenueToken.sol:60]"); bool minted = super.mint(to, value); if (minted) { addBalanceBlocks(to); if (!holdersMap[to]) { holdersMap[to] = true; holders.push(to); } } return minted; } function transfer(address to, uint256 value) public returns (bool) { bool transferred = super.transfer(to, value); if (transferred) { addBalanceBlocks(msg.sender); addBalanceBlocks(to); if (!holdersMap[to]) { holdersMap[to] = true; holders.push(to); } } return transferred; } function approve(address spender, uint256 value) public returns (bool) { require( 0 == value || 0 == allowance(msg.sender, spender), "Value or allowance non-zero [RevenueToken.sol:121]" ); return super.approve(spender, value); } function transferFrom(address from, address to, uint256 value) public returns (bool) { bool transferred = super.transferFrom(from, to, value); if (transferred) { addBalanceBlocks(from); addBalanceBlocks(to); if (!holdersMap[to]) { holdersMap[to] = true; holders.push(to); } } return transferred; } function balanceBlocksIn(address account, uint256 startBlock, uint256 endBlock) public view returns (uint256) { require(startBlock < endBlock, "Bounds parameters mismatch [RevenueToken.sol:173]"); require(account != address(0), "Account is null address [RevenueToken.sol:174]"); if (balanceBlockNumbers[account].length == 0 || endBlock < balanceBlockNumbers[account][0]) return 0; uint256 i = 0; while (i < balanceBlockNumbers[account].length && balanceBlockNumbers[account][i] < startBlock) i++; uint256 r; if (i >= balanceBlockNumbers[account].length) r = balances[account][balanceBlockNumbers[account].length - 1].mul(endBlock.sub(startBlock)); else { uint256 l = (i == 0) ? startBlock : balanceBlockNumbers[account][i - 1]; uint256 h = balanceBlockNumbers[account][i]; if (h > endBlock) h = endBlock; h = h.sub(startBlock); r = (h == 0) ? 0 : balanceBlocks[account][i].mul(h).div(balanceBlockNumbers[account][i].sub(l)); i++; while (i < balanceBlockNumbers[account].length && balanceBlockNumbers[account][i] < endBlock) { r = r.add(balanceBlocks[account][i]); i++; } if (i >= balanceBlockNumbers[account].length) r = r.add( balances[account][balanceBlockNumbers[account].length - 1].mul( endBlock.sub(balanceBlockNumbers[account][balanceBlockNumbers[account].length - 1]) ) ); else if (balanceBlockNumbers[account][i - 1] < endBlock) r = r.add( balanceBlocks[account][i].mul( endBlock.sub(balanceBlockNumbers[account][i - 1]) ).div( balanceBlockNumbers[account][i].sub(balanceBlockNumbers[account][i - 1]) ) ); } return r; } function balanceUpdatesCount(address account) public view returns (uint256) { return balanceBlocks[account].length; } function holdersCount() public view returns (uint256) { return holders.length; } function holdersByIndices(uint256 low, uint256 up, bool posOnly) public view returns (address[] memory) { require(low <= up, "Bounds parameters mismatch [RevenueToken.sol:259]"); up = up > holders.length - 1 ? holders.length - 1 : up; uint256 length = 0; if (posOnly) { for (uint256 i = low; i <= up; i++) if (0 < balanceOf(holders[i])) length++; } else length = up - low + 1; address[] memory _holders = new address[](length); uint256 j = 0; for (uint256 i = low; i <= up; i++) if (!posOnly || 0 < balanceOf(holders[i])) _holders[j++] = holders[i]; return _holders; } function addBalanceBlocks(address account) private { uint256 length = balanceBlockNumbers[account].length; balances[account].push(balanceOf(account)); if (0 < length) balanceBlocks[account].push( balances[account][length - 1].mul( block.number.sub(balanceBlockNumbers[account][length - 1]) ) ); else balanceBlocks[account].push(0); balanceBlockNumbers[account].push(block.number); } } library Address { function isContract(address account) internal view returns (bool) { uint256 size; assembly { size := extcodesize(account) } return size > 0; } } library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 token, address spender, uint256 value) internal { require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function callOptionalReturn(IERC20 token, bytes memory data) private { require(address(token).isContract(), "SafeERC20: call to non-contract"); (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } contract TokenMultiTimelock is Ownable { using SafeERC20 for IERC20; struct Release { uint256 earliestReleaseTime; uint256 amount; uint256 blockNumber; bool done; } IERC20 public token; address public beneficiary; Release[] public releases; uint256 public totalLockedAmount; uint256 public executedReleasesCount; event SetTokenEvent(IERC20 token); event SetBeneficiaryEvent(address beneficiary); event DefineReleaseEvent(uint256 earliestReleaseTime, uint256 amount, uint256 blockNumber); event SetReleaseBlockNumberEvent(uint256 index, uint256 blockNumber); event ReleaseEvent(uint256 index, uint256 blockNumber, uint256 earliestReleaseTime, uint256 actualReleaseTime, uint256 amount); constructor(address deployer) Ownable(deployer) public { } function setToken(IERC20 _token) public onlyOperator notNullOrThisAddress(address(_token)) { require(address(token) == address(0), "Token previously set [TokenMultiTimelock.sol:73]"); token = _token; emit SetTokenEvent(token); } function setBeneficiary(address _beneficiary) public onlyOperator notNullAddress(_beneficiary) { beneficiary = _beneficiary; emit SetBeneficiaryEvent(beneficiary); } function defineReleases(uint256[] memory earliestReleaseTimes, uint256[] memory amounts, uint256[] memory releaseBlockNumbers) onlyOperator public { require( earliestReleaseTimes.length == amounts.length, "Earliest release times and amounts lengths mismatch [TokenMultiTimelock.sol:105]" ); require( earliestReleaseTimes.length >= releaseBlockNumbers.length, "Earliest release times and release block numbers lengths mismatch [TokenMultiTimelock.sol:109]" ); require(address(token) != address(0), "Token not initialized [TokenMultiTimelock.sol:115]"); for (uint256 i = 0; i < earliestReleaseTimes.length; i++) { totalLockedAmount += amounts[i]; require(token.balanceOf(address(this)) >= totalLockedAmount, "Total locked amount overrun [TokenMultiTimelock.sol:123]"); uint256 blockNumber = i < releaseBlockNumbers.length ? releaseBlockNumbers[i] : 0; releases.push(Release(earliestReleaseTimes[i], amounts[i], blockNumber, false)); emit DefineReleaseEvent(earliestReleaseTimes[i], amounts[i], blockNumber); } } function releasesCount() public view returns (uint256) { return releases.length; } function setReleaseBlockNumber(uint256 index, uint256 blockNumber) public onlyBeneficiary { require(!releases[index].done, "Release previously done [TokenMultiTimelock.sol:154]"); releases[index].blockNumber = blockNumber; emit SetReleaseBlockNumberEvent(index, blockNumber); } function release(uint256 index) public onlyBeneficiary { Release storage _release = releases[index]; require(0 < _release.amount, "Release amount not strictly positive [TokenMultiTimelock.sol:173]"); require(!_release.done, "Release previously done [TokenMultiTimelock.sol:176]"); require(block.timestamp >= _release.earliestReleaseTime, "Block time stamp less than earliest release time [TokenMultiTimelock.sol:179]"); _release.done = true; if (0 == _release.blockNumber) _release.blockNumber = block.number; executedReleasesCount++; totalLockedAmount -= _release.amount; token.safeTransfer(beneficiary, _release.amount); emit ReleaseEvent(index, _release.blockNumber, _release.earliestReleaseTime, block.timestamp, _release.amount); } modifier onlyBeneficiary() { require(msg.sender == beneficiary, "Message sender not beneficiary [TokenMultiTimelock.sol:204]"); _; } } contract RevenueTokenManager is TokenMultiTimelock { using SafeMathUintLib for uint256; uint256[] public totalReleasedAmounts; uint256[] public totalReleasedAmountBlocks; constructor(address deployer) public TokenMultiTimelock(deployer) { } function release(uint256 index) public onlyBeneficiary { super.release(index); _addAmountBlocks(index); } function releasedAmountBlocksIn(uint256 startBlock, uint256 endBlock) public view returns (uint256) { require(startBlock < endBlock, "Bounds parameters mismatch [RevenueTokenManager.sol:60]"); if (executedReleasesCount == 0 || endBlock < releases[0].blockNumber) return 0; uint256 i = 0; while (i < executedReleasesCount && releases[i].blockNumber < startBlock) i++; uint256 r; if (i >= executedReleasesCount) r = totalReleasedAmounts[executedReleasesCount - 1].mul(endBlock.sub(startBlock)); else { uint256 l = (i == 0) ? startBlock : releases[i - 1].blockNumber; uint256 h = releases[i].blockNumber; if (h > endBlock) h = endBlock; h = h.sub(startBlock); r = (h == 0) ? 0 : totalReleasedAmountBlocks[i].mul(h).div(releases[i].blockNumber.sub(l)); i++; while (i < executedReleasesCount && releases[i].blockNumber < endBlock) { r = r.add(totalReleasedAmountBlocks[i]); i++; } if (i >= executedReleasesCount) r = r.add( totalReleasedAmounts[executedReleasesCount - 1].mul( endBlock.sub(releases[executedReleasesCount - 1].blockNumber) ) ); else if (releases[i - 1].blockNumber < endBlock) r = r.add( totalReleasedAmountBlocks[i].mul( endBlock.sub(releases[i - 1].blockNumber) ).div( releases[i].blockNumber.sub(releases[i - 1].blockNumber) ) ); } return r; } function releaseBlockNumbers(uint256 index) public view returns (uint256) { return releases[index].blockNumber; } function _addAmountBlocks(uint256 index) private { if (0 < index) { totalReleasedAmounts.push( totalReleasedAmounts[index - 1].add(releases[index].amount) ); totalReleasedAmountBlocks.push( totalReleasedAmounts[index - 1].mul( releases[index].blockNumber.sub(releases[index - 1].blockNumber) ) ); } else { totalReleasedAmounts.push(releases[index].amount); totalReleasedAmountBlocks.push(0); } } } contract TokenHolderRevenueFund is Ownable, AccrualBeneficiary, Servable, TransferControllerManageable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; using FungibleBalanceLib for FungibleBalanceLib.Balance; using TxHistoryLib for TxHistoryLib.TxHistory; using CurrenciesLib for CurrenciesLib.Currencies; string constant public CLOSE_ACCRUAL_PERIOD_ACTION = "close_accrual_period"; RevenueTokenManager public revenueTokenManager; FungibleBalanceLib.Balance private periodAccrual; CurrenciesLib.Currencies private periodCurrencies; FungibleBalanceLib.Balance private aggregateAccrual; CurrenciesLib.Currencies private aggregateCurrencies; TxHistoryLib.TxHistory private txHistory; mapping(address => mapping(address => mapping(uint256 => uint256[]))) public claimedAccrualBlockNumbersByWalletCurrency; mapping(address => mapping(uint256 => uint256[])) public accrualBlockNumbersByCurrency; mapping(address => mapping(uint256 => mapping(uint256 => int256))) public aggregateAccrualAmountByCurrencyBlockNumber; mapping(address => FungibleBalanceLib.Balance) private stagedByWallet; event SetRevenueTokenManagerEvent(RevenueTokenManager oldRevenueTokenManager, RevenueTokenManager newRevenueTokenManager); event ReceiveEvent(address wallet, int256 amount, address currencyCt, uint256 currencyId); event WithdrawEvent(address to, int256 amount, address currencyCt, uint256 currencyId); event CloseAccrualPeriodEvent(int256 periodAmount, int256 aggregateAmount, address currencyCt, uint256 currencyId); event ClaimAndTransferToBeneficiaryEvent(address wallet, string balanceType, int256 amount, address currencyCt, uint256 currencyId, string standard); event ClaimAndTransferToBeneficiaryByProxyEvent(address wallet, string balanceType, int256 amount, address currencyCt, uint256 currencyId, string standard); event ClaimAndStageEvent(address from, int256 amount, address currencyCt, uint256 currencyId); event WithdrawEvent(address from, int256 amount, address currencyCt, uint256 currencyId, string standard); constructor(address deployer) Ownable(deployer) public { } function setRevenueTokenManager(RevenueTokenManager newRevenueTokenManager) public onlyDeployer notNullAddress(address(newRevenueTokenManager)) { if (newRevenueTokenManager != revenueTokenManager) { RevenueTokenManager oldRevenueTokenManager = revenueTokenManager; revenueTokenManager = newRevenueTokenManager; emit SetRevenueTokenManagerEvent(oldRevenueTokenManager, newRevenueTokenManager); } } function() external payable { receiveEthersTo(msg.sender, ""); } function receiveEthersTo(address wallet, string memory) public payable { int256 amount = SafeMathIntLib.toNonZeroInt256(msg.value); periodAccrual.add(amount, address(0), 0); aggregateAccrual.add(amount, address(0), 0); periodCurrencies.add(address(0), 0); aggregateCurrencies.add(address(0), 0); txHistory.addDeposit(amount, address(0), 0); emit ReceiveEvent(wallet, amount, address(0), 0); } function receiveTokens(string memory, int256 amount, address currencyCt, uint256 currencyId, string memory standard) public { receiveTokensTo(msg.sender, "", amount, currencyCt, currencyId, standard); } function receiveTokensTo(address wallet, string memory, int256 amount, address currencyCt, uint256 currencyId, string memory standard) public { require(amount.isNonZeroPositiveInt256(), "Amount not strictly positive [TokenHolderRevenueFund.sol:157]"); TransferController controller = transferController(currencyCt, standard); (bool success,) = address(controller).delegatecall( abi.encodeWithSelector( controller.getReceiveSignature(), msg.sender, this, uint256(amount), currencyCt, currencyId ) ); require(success, "Reception by controller failed [TokenHolderRevenueFund.sol:166]"); periodAccrual.add(amount, currencyCt, currencyId); aggregateAccrual.add(amount, currencyCt, currencyId); periodCurrencies.add(currencyCt, currencyId); aggregateCurrencies.add(currencyCt, currencyId); txHistory.addDeposit(amount, currencyCt, currencyId); emit ReceiveEvent(wallet, amount, currencyCt, currencyId); } function periodAccrualBalance(address currencyCt, uint256 currencyId) public view returns (int256) { return periodAccrual.get(currencyCt, currencyId); } function aggregateAccrualBalance(address currencyCt, uint256 currencyId) public view returns (int256) { return aggregateAccrual.get(currencyCt, currencyId); } function periodCurrenciesCount() public view returns (uint256) { return periodCurrencies.count(); } function periodCurrenciesByIndices(uint256 low, uint256 up) public view returns (MonetaryTypesLib.Currency[] memory) { return periodCurrencies.getByIndices(low, up); } function aggregateCurrenciesCount() public view returns (uint256) { return aggregateCurrencies.count(); } function aggregateCurrenciesByIndices(uint256 low, uint256 up) public view returns (MonetaryTypesLib.Currency[] memory) { return aggregateCurrencies.getByIndices(low, up); } function depositsCount() public view returns (uint256) { return txHistory.depositsCount(); } function deposit(uint index) public view returns (int256 amount, uint256 blockNumber, address currencyCt, uint256 currencyId) { return txHistory.deposit(index); } function stagedBalance(address wallet, address currencyCt, uint256 currencyId) public view returns (int256) { return stagedByWallet[wallet].get(currencyCt, currencyId); } function closeAccrualPeriod(MonetaryTypesLib.Currency[] memory currencies) public onlyEnabledServiceAction(CLOSE_ACCRUAL_PERIOD_ACTION) { for (uint256 i = 0; i < currencies.length; i++) { MonetaryTypesLib.Currency memory currency = currencies[i]; int256 periodAmount = periodAccrual.get(currency.ct, currency.id); accrualBlockNumbersByCurrency[currency.ct][currency.id].push(block.number); aggregateAccrualAmountByCurrencyBlockNumber[currency.ct][currency.id][block.number] = aggregateAccrualBalance( currency.ct, currency.id ); if (periodAmount > 0) { periodAccrual.set(0, currency.ct, currency.id); periodCurrencies.removeByCurrency(currency.ct, currency.id); } emit CloseAccrualPeriodEvent( periodAmount, aggregateAccrualAmountByCurrencyBlockNumber[currency.ct][currency.id][block.number], currency.ct, currency.id ); } } function claimAndTransferToBeneficiary(Beneficiary beneficiary, address destWallet, string memory balanceType, address currencyCt, uint256 currencyId, string memory standard) public { int256 claimedAmount = _claim(msg.sender, currencyCt, currencyId); if (address(0) == currencyCt && 0 == currencyId) beneficiary.receiveEthersTo.value(uint256(claimedAmount))(destWallet, balanceType); else { TransferController controller = transferController(currencyCt, standard); (bool success,) = address(controller).delegatecall( abi.encodeWithSelector( controller.getApproveSignature(), address(beneficiary), uint256(claimedAmount), currencyCt, currencyId ) ); require(success, "Approval by controller failed [TokenHolderRevenueFund.sol:349]"); beneficiary.receiveTokensTo(destWallet, balanceType, claimedAmount, currencyCt, currencyId, standard); } emit ClaimAndTransferToBeneficiaryEvent(msg.sender, balanceType, claimedAmount, currencyCt, currencyId, standard); } function claimAndStage(address currencyCt, uint256 currencyId) public { int256 claimedAmount = _claim(msg.sender, currencyCt, currencyId); stagedByWallet[msg.sender].add(claimedAmount, currencyCt, currencyId); emit ClaimAndStageEvent(msg.sender, claimedAmount, currencyCt, currencyId); } function withdraw(int256 amount, address currencyCt, uint256 currencyId, string memory standard) public { require(amount.isNonZeroPositiveInt256(), "Amount not strictly positive [TokenHolderRevenueFund.sol:384]"); amount = amount.clampMax(stagedByWallet[msg.sender].get(currencyCt, currencyId)); stagedByWallet[msg.sender].sub(amount, currencyCt, currencyId); if (address(0) == currencyCt && 0 == currencyId) msg.sender.transfer(uint256(amount)); else { TransferController controller = transferController(currencyCt, standard); (bool success,) = address(controller).delegatecall( abi.encodeWithSelector( controller.getDispatchSignature(), address(this), msg.sender, uint256(amount), currencyCt, currencyId ) ); require(success, "Dispatch by controller failed [TokenHolderRevenueFund.sol:403]"); } emit WithdrawEvent(msg.sender, amount, currencyCt, currencyId, standard); } function _claim(address wallet, address currencyCt, uint256 currencyId) private returns (int256) { require(0 < accrualBlockNumbersByCurrency[currencyCt][currencyId].length, "No terminated accrual period found [TokenHolderRevenueFund.sol:418]"); uint256[] storage claimedAccrualBlockNumbers = claimedAccrualBlockNumbersByWalletCurrency[wallet][currencyCt][currencyId]; uint256 bnLow = (0 == claimedAccrualBlockNumbers.length ? 0 : claimedAccrualBlockNumbers[claimedAccrualBlockNumbers.length - 1]); uint256 bnUp = accrualBlockNumbersByCurrency[currencyCt][currencyId][accrualBlockNumbersByCurrency[currencyCt][currencyId].length - 1]; require(bnLow < bnUp, "Bounds parameters mismatch [TokenHolderRevenueFund.sol:428]"); int256 claimableAmount = aggregateAccrualAmountByCurrencyBlockNumber[currencyCt][currencyId][bnUp] - (0 == bnLow ? 0 : aggregateAccrualAmountByCurrencyBlockNumber[currencyCt][currencyId][bnLow]); require(claimableAmount.isNonZeroPositiveInt256(), "Claimable amount not strictly positive [TokenHolderRevenueFund.sol:435]"); int256 walletBalanceBlocks = int256( RevenueToken(address(revenueTokenManager.token())).balanceBlocksIn(wallet, bnLow, bnUp) ); int256 releasedAmountBlocks = int256( revenueTokenManager.releasedAmountBlocksIn(bnLow, bnUp) ); int256 claimedAmount = walletBalanceBlocks.mul_nn(claimableAmount).mul_nn(1e18).div_nn(releasedAmountBlocks.mul_nn(1e18)); claimedAccrualBlockNumbers.push(bnUp); return claimedAmount; } } contract ClientFund is Ownable, Beneficiary, Benefactor, AuthorizableServable, TransferControllerManageable, BalanceTrackable, TransactionTrackable, WalletLockable { using SafeMathIntLib for int256; address[] public seizedWallets; mapping(address => bool) public seizedByWallet; TokenHolderRevenueFund public tokenHolderRevenueFund; event SetTokenHolderRevenueFundEvent(TokenHolderRevenueFund oldTokenHolderRevenueFund, TokenHolderRevenueFund newTokenHolderRevenueFund); event ReceiveEvent(address wallet, string balanceType, int256 value, address currencyCt, uint256 currencyId, string standard); event WithdrawEvent(address wallet, int256 value, address currencyCt, uint256 currencyId, string standard); event StageEvent(address wallet, int256 value, address currencyCt, uint256 currencyId, string standard); event UnstageEvent(address wallet, int256 value, address currencyCt, uint256 currencyId, string standard); event UpdateSettledBalanceEvent(address wallet, int256 value, address currencyCt, uint256 currencyId); event StageToBeneficiaryEvent(address sourceWallet, Beneficiary beneficiary, int256 value, address currencyCt, uint256 currencyId, string standard); event TransferToBeneficiaryEvent(address wallet, Beneficiary beneficiary, int256 value, address currencyCt, uint256 currencyId, string standard); event SeizeBalancesEvent(address seizedWallet, address seizerWallet, int256 value, address currencyCt, uint256 currencyId); event ClaimRevenueEvent(address claimer, string balanceType, address currencyCt, uint256 currencyId, string standard); constructor(address deployer) Ownable(deployer) Beneficiary() Benefactor() public { serviceActivationTimeout = 1 weeks; } function setTokenHolderRevenueFund(TokenHolderRevenueFund newTokenHolderRevenueFund) public onlyDeployer notNullAddress(address(newTokenHolderRevenueFund)) notSameAddresses(address(newTokenHolderRevenueFund), address(tokenHolderRevenueFund)) { TokenHolderRevenueFund oldTokenHolderRevenueFund = tokenHolderRevenueFund; tokenHolderRevenueFund = newTokenHolderRevenueFund; emit SetTokenHolderRevenueFundEvent(oldTokenHolderRevenueFund, newTokenHolderRevenueFund); } function() external payable { receiveEthersTo(msg.sender, balanceTracker.DEPOSITED_BALANCE_TYPE()); } function receiveEthersTo(address wallet, string memory balanceType) public payable { int256 value = SafeMathIntLib.toNonZeroInt256(msg.value); _receiveTo(wallet, balanceType, value, address(0), 0, true); emit ReceiveEvent(wallet, balanceType, value, address(0), 0, ""); } function receiveTokens(string memory balanceType, int256 value, address currencyCt, uint256 currencyId, string memory standard) public { receiveTokensTo(msg.sender, balanceType, value, currencyCt, currencyId, standard); } function receiveTokensTo(address wallet, string memory balanceType, int256 value, address currencyCt, uint256 currencyId, string memory standard) public { require(value.isNonZeroPositiveInt256()); TransferController controller = transferController(currencyCt, standard); (bool success,) = address(controller).delegatecall( abi.encodeWithSelector( controller.getReceiveSignature(), msg.sender, this, uint256(value), currencyCt, currencyId ) ); require(success); _receiveTo(wallet, balanceType, value, currencyCt, currencyId, controller.isFungible()); emit ReceiveEvent(wallet, balanceType, value, currencyCt, currencyId, standard); } function updateSettledBalance(address wallet, int256 value, address currencyCt, uint256 currencyId, string memory standard, uint256 blockNumber) public onlyAuthorizedService(wallet) notNullAddress(wallet) { require(value.isPositiveInt256()); if (_isFungible(currencyCt, currencyId, standard)) { (int256 depositedValue,) = balanceTracker.fungibleRecordByBlockNumber( wallet, balanceTracker.depositedBalanceType(), currencyCt, currencyId, blockNumber ); balanceTracker.set( wallet, balanceTracker.settledBalanceType(), value.sub(depositedValue), currencyCt, currencyId, true ); } else { balanceTracker.sub( wallet, balanceTracker.depositedBalanceType(), value, currencyCt, currencyId, false ); balanceTracker.add( wallet, balanceTracker.settledBalanceType(), value, currencyCt, currencyId, false ); } emit UpdateSettledBalanceEvent(wallet, value, currencyCt, currencyId); } function stage(address wallet, int256 value, address currencyCt, uint256 currencyId, string memory standard) public onlyAuthorizedService(wallet) { require(value.isNonZeroPositiveInt256()); bool fungible = _isFungible(currencyCt, currencyId, standard); value = _subtractSequentially(wallet, balanceTracker.activeBalanceTypes(), value, currencyCt, currencyId, fungible); balanceTracker.add( wallet, balanceTracker.stagedBalanceType(), value, currencyCt, currencyId, fungible ); emit StageEvent(wallet, value, currencyCt, currencyId, standard); } function unstage(int256 value, address currencyCt, uint256 currencyId, string memory standard) public { require(value.isNonZeroPositiveInt256()); bool fungible = _isFungible(currencyCt, currencyId, standard); value = _subtractFromStaged(msg.sender, value, currencyCt, currencyId, fungible); balanceTracker.add( msg.sender, balanceTracker.depositedBalanceType(), value, currencyCt, currencyId, fungible ); emit UnstageEvent(msg.sender, value, currencyCt, currencyId, standard); } function stageToBeneficiary(address wallet, Beneficiary beneficiary, int256 value, address currencyCt, uint256 currencyId, string memory standard) public onlyAuthorizedService(wallet) { bool fungible = _isFungible(currencyCt, currencyId, standard); value = _subtractSequentially(wallet, balanceTracker.activeBalanceTypes(), value, currencyCt, currencyId, fungible); _transferToBeneficiary(wallet, beneficiary, value, currencyCt, currencyId, standard); emit StageToBeneficiaryEvent(wallet, beneficiary, value, currencyCt, currencyId, standard); } function transferToBeneficiary(address wallet, Beneficiary beneficiary, int256 value, address currencyCt, uint256 currencyId, string memory standard) public onlyAuthorizedService(wallet) { _transferToBeneficiary(wallet, beneficiary, value, currencyCt, currencyId, standard); emit TransferToBeneficiaryEvent(wallet, beneficiary, value, currencyCt, currencyId, standard); } function seizeBalances(address wallet, address currencyCt, uint256 currencyId, string memory standard) public { if (_isFungible(currencyCt, currencyId, standard)) _seizeFungibleBalances(wallet, msg.sender, currencyCt, currencyId); else _seizeNonFungibleBalances(wallet, msg.sender, currencyCt, currencyId); if (!seizedByWallet[wallet]) { seizedByWallet[wallet] = true; seizedWallets.push(wallet); } } function withdraw(int256 value, address currencyCt, uint256 currencyId, string memory standard) public { require(value.isNonZeroPositiveInt256()); require(!walletLocker.isLocked(msg.sender, currencyCt, currencyId)); bool fungible = _isFungible(currencyCt, currencyId, standard); value = _subtractFromStaged(msg.sender, value, currencyCt, currencyId, fungible); transactionTracker.add( msg.sender, transactionTracker.withdrawalTransactionType(), value, currencyCt, currencyId ); _transferToWallet(msg.sender, value, currencyCt, currencyId, standard); emit WithdrawEvent(msg.sender, value, currencyCt, currencyId, standard); } function isSeizedWallet(address wallet) public view returns (bool) { return seizedByWallet[wallet]; } function seizedWalletsCount() public view returns (uint256) { return seizedWallets.length; } function claimRevenue(address claimer, string memory balanceType, address currencyCt, uint256 currencyId, string memory standard) public onlyOperator { tokenHolderRevenueFund.claimAndTransferToBeneficiary( this, claimer, balanceType, currencyCt, currencyId, standard ); emit ClaimRevenueEvent(claimer, balanceType, currencyCt, currencyId, standard); } function _receiveTo(address wallet, string memory balanceType, int256 value, address currencyCt, uint256 currencyId, bool fungible) private { bytes32 balanceHash = 0 < bytes(balanceType).length ? keccak256(abi.encodePacked(balanceType)) : balanceTracker.depositedBalanceType(); if (balanceTracker.stagedBalanceType() == balanceHash) balanceTracker.add( wallet, balanceTracker.stagedBalanceType(), value, currencyCt, currencyId, fungible ); else if (balanceTracker.depositedBalanceType() == balanceHash) { balanceTracker.add( wallet, balanceTracker.depositedBalanceType(), value, currencyCt, currencyId, fungible ); transactionTracker.add( wallet, transactionTracker.depositTransactionType(), value, currencyCt, currencyId ); } else revert(); } function _subtractSequentially(address wallet, bytes32[] memory balanceTypes, int256 value, address currencyCt, uint256 currencyId, bool fungible) private returns (int256) { if (fungible) return _subtractFungibleSequentially(wallet, balanceTypes, value, currencyCt, currencyId); else return _subtractNonFungibleSequentially(wallet, balanceTypes, value, currencyCt, currencyId); } function _subtractFungibleSequentially(address wallet, bytes32[] memory balanceTypes, int256 amount, address currencyCt, uint256 currencyId) private returns (int256) { require(0 <= amount); uint256 i; int256 totalBalanceAmount = 0; for (i = 0; i < balanceTypes.length; i++) totalBalanceAmount = totalBalanceAmount.add( balanceTracker.get( wallet, balanceTypes[i], currencyCt, currencyId ) ); amount = amount.clampMax(totalBalanceAmount); int256 _amount = amount; for (i = 0; i < balanceTypes.length; i++) { int256 typeAmount = balanceTracker.get( wallet, balanceTypes[i], currencyCt, currencyId ); if (typeAmount >= _amount) { balanceTracker.sub( wallet, balanceTypes[i], _amount, currencyCt, currencyId, true ); break; } else { balanceTracker.set( wallet, balanceTypes[i], 0, currencyCt, currencyId, true ); _amount = _amount.sub(typeAmount); } } return amount; } function _subtractNonFungibleSequentially(address wallet, bytes32[] memory balanceTypes, int256 id, address currencyCt, uint256 currencyId) private returns (int256) { for (uint256 i = 0; i < balanceTypes.length; i++) if (balanceTracker.hasId(wallet, balanceTypes[i], id, currencyCt, currencyId)) { balanceTracker.sub(wallet, balanceTypes[i], id, currencyCt, currencyId, false); break; } return id; } function _subtractFromStaged(address wallet, int256 value, address currencyCt, uint256 currencyId, bool fungible) private returns (int256) { if (fungible) { value = value.clampMax( balanceTracker.get(wallet, balanceTracker.stagedBalanceType(), currencyCt, currencyId) ); require(0 <= value); } else { require(balanceTracker.hasId(wallet, balanceTracker.stagedBalanceType(), value, currencyCt, currencyId)); } balanceTracker.sub(wallet, balanceTracker.stagedBalanceType(), value, currencyCt, currencyId, fungible); return value; } function _transferToBeneficiary(address destWallet, Beneficiary beneficiary, int256 value, address currencyCt, uint256 currencyId, string memory standard) private { require(value.isNonZeroPositiveInt256()); require(isRegisteredBeneficiary(beneficiary)); if (address(0) == currencyCt && 0 == currencyId) beneficiary.receiveEthersTo.value(uint256(value))(destWallet, ""); else { TransferController controller = transferController(currencyCt, standard); (bool success,) = address(controller).delegatecall( abi.encodeWithSelector( controller.getApproveSignature(), address(beneficiary), uint256(value), currencyCt, currencyId ) ); require(success); beneficiary.receiveTokensTo(destWallet, "", value, currencyCt, currencyId, controller.standard()); } } function _transferToWallet(address payable wallet, int256 value, address currencyCt, uint256 currencyId, string memory standard) private { if (address(0) == currencyCt && 0 == currencyId) wallet.transfer(uint256(value)); else { TransferController controller = transferController(currencyCt, standard); (bool success,) = address(controller).delegatecall( abi.encodeWithSelector( controller.getDispatchSignature(), address(this), wallet, uint256(value), currencyCt, currencyId ) ); require(success); } } function _seizeFungibleBalances(address lockedWallet, address lockerWallet, address currencyCt, uint256 currencyId) private { int256 amount = walletLocker.lockedAmount(lockedWallet, lockerWallet, currencyCt, currencyId); require(amount > 0); _subtractFungibleSequentially(lockedWallet, balanceTracker.allBalanceTypes(), amount, currencyCt, currencyId); balanceTracker.add( lockerWallet, balanceTracker.stagedBalanceType(), amount, currencyCt, currencyId, true ); emit SeizeBalancesEvent(lockedWallet, lockerWallet, amount, currencyCt, currencyId); } function _seizeNonFungibleBalances(address lockedWallet, address lockerWallet, address currencyCt, uint256 currencyId) private { uint256 lockedIdsCount = walletLocker.lockedIdsCount(lockedWallet, lockerWallet, currencyCt, currencyId); require(0 < lockedIdsCount); int256[] memory ids = walletLocker.lockedIdsByIndices( lockedWallet, lockerWallet, currencyCt, currencyId, 0, lockedIdsCount - 1 ); for (uint256 i = 0; i < ids.length; i++) { _subtractNonFungibleSequentially(lockedWallet, balanceTracker.allBalanceTypes(), ids[i], currencyCt, currencyId); balanceTracker.add( lockerWallet, balanceTracker.stagedBalanceType(), ids[i], currencyCt, currencyId, false ); emit SeizeBalancesEvent(lockedWallet, lockerWallet, ids[i], currencyCt, currencyId); } } function _isFungible(address currencyCt, uint256 currencyId, string memory standard) private view returns (bool) { return (address(0) == currencyCt && 0 == currencyId) || transferController(currencyCt, standard).isFungible(); } } contract ClientFundable is Ownable { ClientFund public clientFund; event SetClientFundEvent(ClientFund oldClientFund, ClientFund newClientFund); function setClientFund(ClientFund newClientFund) public onlyDeployer notNullAddress(address(newClientFund)) notSameAddresses(address(newClientFund), address(clientFund)) { ClientFund oldClientFund = clientFund; clientFund = newClientFund; emit SetClientFundEvent(oldClientFund, newClientFund); } modifier clientFundInitialized() { require(address(clientFund) != address(0), "Client fund not initialized [ClientFundable.sol:51]"); _; } } contract CommunityVote is Ownable { mapping(address => bool) doubleSpenderByWallet; uint256 maxDriipNonce; uint256 maxNullNonce; bool dataAvailable; constructor(address deployer) Ownable(deployer) public { dataAvailable = true; } function isDoubleSpenderWallet(address wallet) public view returns (bool) { return doubleSpenderByWallet[wallet]; } function getMaxDriipNonce() public view returns (uint256) { return maxDriipNonce; } function getMaxNullNonce() public view returns (uint256) { return maxNullNonce; } function isDataAvailable() public view returns (bool) { return dataAvailable; } } contract CommunityVotable is Ownable { CommunityVote public communityVote; bool public communityVoteFrozen; event SetCommunityVoteEvent(CommunityVote oldCommunityVote, CommunityVote newCommunityVote); event FreezeCommunityVoteEvent(); function setCommunityVote(CommunityVote newCommunityVote) public onlyDeployer notNullAddress(address(newCommunityVote)) notSameAddresses(address(newCommunityVote), address(communityVote)) { require(!communityVoteFrozen, "Community vote frozen [CommunityVotable.sol:41]"); CommunityVote oldCommunityVote = communityVote; communityVote = newCommunityVote; emit SetCommunityVoteEvent(oldCommunityVote, newCommunityVote); } function freezeCommunityVote() public onlyDeployer { communityVoteFrozen = true; emit FreezeCommunityVoteEvent(); } modifier communityVoteInitialized() { require(address(communityVote) != address(0), "Community vote not initialized [CommunityVotable.sol:67]"); _; } } contract AccrualBenefactor is Benefactor { using SafeMathIntLib for int256; mapping(address => int256) private _beneficiaryFractionMap; int256 public totalBeneficiaryFraction; event RegisterAccrualBeneficiaryEvent(Beneficiary beneficiary, int256 fraction); event DeregisterAccrualBeneficiaryEvent(Beneficiary beneficiary); function registerBeneficiary(Beneficiary beneficiary) public onlyDeployer notNullAddress(address(beneficiary)) returns (bool) { return registerFractionalBeneficiary(AccrualBeneficiary(address(beneficiary)), ConstantsLib.PARTS_PER()); } function registerFractionalBeneficiary(AccrualBeneficiary beneficiary, int256 fraction) public onlyDeployer notNullAddress(address(beneficiary)) returns (bool) { require(fraction > 0, "Fraction not strictly positive [AccrualBenefactor.sol:59]"); require( totalBeneficiaryFraction.add(fraction) <= ConstantsLib.PARTS_PER(), "Total beneficiary fraction out of bounds [AccrualBenefactor.sol:60]" ); if (!super.registerBeneficiary(beneficiary)) return false; _beneficiaryFractionMap[address(beneficiary)] = fraction; totalBeneficiaryFraction = totalBeneficiaryFraction.add(fraction); emit RegisterAccrualBeneficiaryEvent(beneficiary, fraction); return true; } function deregisterBeneficiary(Beneficiary beneficiary) public onlyDeployer notNullAddress(address(beneficiary)) returns (bool) { if (!super.deregisterBeneficiary(beneficiary)) return false; address _beneficiary = address(beneficiary); totalBeneficiaryFraction = totalBeneficiaryFraction.sub(_beneficiaryFractionMap[_beneficiary]); _beneficiaryFractionMap[_beneficiary] = 0; emit DeregisterAccrualBeneficiaryEvent(beneficiary); return true; } function beneficiaryFraction(AccrualBeneficiary beneficiary) public view returns (int256) { return _beneficiaryFractionMap[address(beneficiary)]; } } contract RevenueFund is Ownable, AccrualBeneficiary, AccrualBenefactor, TransferControllerManageable { using FungibleBalanceLib for FungibleBalanceLib.Balance; using TxHistoryLib for TxHistoryLib.TxHistory; using SafeMathIntLib for int256; using SafeMathUintLib for uint256; using CurrenciesLib for CurrenciesLib.Currencies; FungibleBalanceLib.Balance periodAccrual; CurrenciesLib.Currencies periodCurrencies; FungibleBalanceLib.Balance aggregateAccrual; CurrenciesLib.Currencies aggregateCurrencies; TxHistoryLib.TxHistory private txHistory; event ReceiveEvent(address from, int256 amount, address currencyCt, uint256 currencyId); event CloseAccrualPeriodEvent(); event RegisterServiceEvent(address service); event DeregisterServiceEvent(address service); constructor(address deployer) Ownable(deployer) public { } function() external payable { receiveEthersTo(msg.sender, ""); } function receiveEthersTo(address wallet, string memory) public payable { int256 amount = SafeMathIntLib.toNonZeroInt256(msg.value); periodAccrual.add(amount, address(0), 0); aggregateAccrual.add(amount, address(0), 0); periodCurrencies.add(address(0), 0); aggregateCurrencies.add(address(0), 0); txHistory.addDeposit(amount, address(0), 0); emit ReceiveEvent(wallet, amount, address(0), 0); } function receiveTokens(string memory balanceType, int256 amount, address currencyCt, uint256 currencyId, string memory standard) public { receiveTokensTo(msg.sender, balanceType, amount, currencyCt, currencyId, standard); } function receiveTokensTo(address wallet, string memory, int256 amount, address currencyCt, uint256 currencyId, string memory standard) public { require(amount.isNonZeroPositiveInt256(), "Amount not strictly positive [RevenueFund.sol:115]"); TransferController controller = transferController(currencyCt, standard); (bool success,) = address(controller).delegatecall( abi.encodeWithSelector( controller.getReceiveSignature(), msg.sender, this, uint256(amount), currencyCt, currencyId ) ); require(success, "Reception by controller failed [RevenueFund.sol:124]"); periodAccrual.add(amount, currencyCt, currencyId); aggregateAccrual.add(amount, currencyCt, currencyId); periodCurrencies.add(currencyCt, currencyId); aggregateCurrencies.add(currencyCt, currencyId); txHistory.addDeposit(amount, currencyCt, currencyId); emit ReceiveEvent(wallet, amount, currencyCt, currencyId); } function periodAccrualBalance(address currencyCt, uint256 currencyId) public view returns (int256) { return periodAccrual.get(currencyCt, currencyId); } function aggregateAccrualBalance(address currencyCt, uint256 currencyId) public view returns (int256) { return aggregateAccrual.get(currencyCt, currencyId); } function periodCurrenciesCount() public view returns (uint256) { return periodCurrencies.count(); } function periodCurrenciesByIndices(uint256 low, uint256 up) public view returns (MonetaryTypesLib.Currency[] memory) { return periodCurrencies.getByIndices(low, up); } function aggregateCurrenciesCount() public view returns (uint256) { return aggregateCurrencies.count(); } function aggregateCurrenciesByIndices(uint256 low, uint256 up) public view returns (MonetaryTypesLib.Currency[] memory) { return aggregateCurrencies.getByIndices(low, up); } function depositsCount() public view returns (uint256) { return txHistory.depositsCount(); } function deposit(uint index) public view returns (int256 amount, uint256 blockNumber, address currencyCt, uint256 currencyId) { return txHistory.deposit(index); } function closeAccrualPeriod(MonetaryTypesLib.Currency[] memory currencies) public onlyOperator { require( ConstantsLib.PARTS_PER() == totalBeneficiaryFraction, "Total beneficiary fraction out of bounds [RevenueFund.sol:236]" ); for (uint256 i = 0; i < currencies.length; i++) { MonetaryTypesLib.Currency memory currency = currencies[i]; int256 remaining = periodAccrual.get(currency.ct, currency.id); if (0 >= remaining) continue; for (uint256 j = 0; j < beneficiaries.length; j++) { AccrualBeneficiary beneficiary = AccrualBeneficiary(address(beneficiaries[j])); if (beneficiaryFraction(beneficiary) > 0) { int256 transferable = periodAccrual.get(currency.ct, currency.id) .mul(beneficiaryFraction(beneficiary)) .div(ConstantsLib.PARTS_PER()); if (transferable > remaining) transferable = remaining; if (transferable > 0) { if (currency.ct == address(0)) beneficiary.receiveEthersTo.value(uint256(transferable))(address(0), ""); else { TransferController controller = transferController(currency.ct, ""); (bool success,) = address(controller).delegatecall( abi.encodeWithSelector( controller.getApproveSignature(), address(beneficiary), uint256(transferable), currency.ct, currency.id ) ); require(success, "Approval by controller failed [RevenueFund.sol:274]"); beneficiary.receiveTokensTo(address(0), "", transferable, currency.ct, currency.id, ""); } remaining = remaining.sub(transferable); } } } periodAccrual.set(remaining, currency.ct, currency.id); } for (uint256 j = 0; j < beneficiaries.length; j++) { AccrualBeneficiary beneficiary = AccrualBeneficiary(address(beneficiaries[j])); if (0 >= beneficiaryFraction(beneficiary)) continue; beneficiary.closeAccrualPeriod(currencies); } emit CloseAccrualPeriodEvent(); } } contract Upgradable { address public upgradeAgent; bool public upgradesFrozen; event SetUpgradeAgentEvent(address upgradeAgent); event FreezeUpgradesEvent(); function setUpgradeAgent(address _upgradeAgent) public onlyWhenUpgradable { require(address(0) == upgradeAgent, "Upgrade agent has already been set [Upgradable.sol:37]"); upgradeAgent = _upgradeAgent; emit SetUpgradeAgentEvent(upgradeAgent); } function freezeUpgrades() public onlyWhenUpgrading { upgradesFrozen = true; emit FreezeUpgradesEvent(); } modifier onlyWhenUpgrading() { require(msg.sender == upgradeAgent, "Caller is not upgrade agent [Upgradable.sol:63]"); require(!upgradesFrozen, "Upgrades have been frozen [Upgradable.sol:64]"); _; } modifier onlyWhenUpgradable() { require(!upgradesFrozen, "Upgrades have been frozen [Upgradable.sol:69]"); _; } } library NahmiiTypesLib { enum ChallengePhase {Dispute, Closed} struct OriginFigure { uint256 originId; MonetaryTypesLib.Figure figure; } struct IntendedConjugateCurrency { MonetaryTypesLib.Currency intended; MonetaryTypesLib.Currency conjugate; } struct SingleFigureTotalOriginFigures { MonetaryTypesLib.Figure single; OriginFigure[] total; } struct TotalOriginFigures { OriginFigure[] total; } struct CurrentPreviousInt256 { int256 current; int256 previous; } struct SingleTotalInt256 { int256 single; int256 total; } struct IntendedConjugateCurrentPreviousInt256 { CurrentPreviousInt256 intended; CurrentPreviousInt256 conjugate; } struct IntendedConjugateSingleTotalInt256 { SingleTotalInt256 intended; SingleTotalInt256 conjugate; } struct WalletOperatorHashes { bytes32 wallet; bytes32 operator; } struct Signature { bytes32 r; bytes32 s; uint8 v; } struct Seal { bytes32 hash; Signature signature; } struct WalletOperatorSeal { Seal wallet; Seal operator; } } library SettlementChallengeTypesLib { enum Status {Qualified, Disqualified} struct Proposal { address wallet; uint256 nonce; uint256 referenceBlockNumber; uint256 definitionBlockNumber; uint256 expirationTime; Status status; Amounts amounts; MonetaryTypesLib.Currency currency; Driip challenged; bool walletInitiated; bool terminated; Disqualification disqualification; } struct Amounts { int256 cumulativeTransfer; int256 stage; int256 targetBalance; } struct Driip { string kind; bytes32 hash; } struct Disqualification { address challenger; uint256 nonce; uint256 blockNumber; Driip candidate; } } contract NullSettlementChallengeState is Ownable, Servable, Configurable, BalanceTrackable, Upgradable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; string constant public INITIATE_PROPOSAL_ACTION = "initiate_proposal"; string constant public TERMINATE_PROPOSAL_ACTION = "terminate_proposal"; string constant public REMOVE_PROPOSAL_ACTION = "remove_proposal"; string constant public DISQUALIFY_PROPOSAL_ACTION = "disqualify_proposal"; SettlementChallengeTypesLib.Proposal[] public proposals; mapping(address => mapping(address => mapping(uint256 => uint256))) public proposalIndexByWalletCurrency; event InitiateProposalEvent(address wallet, uint256 nonce, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated); event TerminateProposalEvent(address wallet, uint256 nonce, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated); event RemoveProposalEvent(address wallet, uint256 nonce, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated); event DisqualifyProposalEvent(address challengedWallet, uint256 challangedNonce, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated, address challengerWallet, uint256 candidateNonce, bytes32 candidateHash, string candidateKind); event UpgradeProposalEvent(SettlementChallengeTypesLib.Proposal proposal); constructor(address deployer) Ownable(deployer) public { } function proposalsCount() public view returns (uint256) { return proposals.length; } function initiateProposal(address wallet, uint256 nonce, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency memory currency, uint256 blockNumber, bool walletInitiated) public onlyEnabledServiceAction(INITIATE_PROPOSAL_ACTION) { _initiateProposal( wallet, nonce, stageAmount, targetBalanceAmount, currency, blockNumber, walletInitiated ); emit InitiateProposalEvent( wallet, nonce, stageAmount, targetBalanceAmount, currency, blockNumber, walletInitiated ); } function terminateProposal(address wallet, MonetaryTypesLib.Currency memory currency) public onlyEnabledServiceAction(TERMINATE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; proposals[index - 1].terminated = true; emit TerminateProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated ); } function terminateProposal(address wallet, MonetaryTypesLib.Currency memory currency, bool walletTerminated) public onlyEnabledServiceAction(TERMINATE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; require(walletTerminated == proposals[index - 1].walletInitiated, "Wallet initiation and termination mismatch [NullSettlementChallengeState.sol:145]"); proposals[index - 1].terminated = true; emit TerminateProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated ); } function removeProposal(address wallet, MonetaryTypesLib.Currency memory currency) public onlyEnabledServiceAction(REMOVE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; emit RemoveProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated ); _removeProposal(index); } function removeProposal(address wallet, MonetaryTypesLib.Currency memory currency, bool walletTerminated) public onlyEnabledServiceAction(REMOVE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; require(walletTerminated == proposals[index - 1].walletInitiated, "Wallet initiation and termination mismatch [NullSettlementChallengeState.sol:199]"); emit RemoveProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated ); _removeProposal(index); } function disqualifyProposal(address challengedWallet, MonetaryTypesLib.Currency memory currency, address challengerWallet, uint256 blockNumber, uint256 candidateNonce, bytes32 candidateHash, string memory candidateKind) public onlyEnabledServiceAction(DISQUALIFY_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[challengedWallet][currency.ct][currency.id]; require(0 != index, "No settlement found for wallet and currency [NullSettlementChallengeState.sol:228]"); proposals[index - 1].status = SettlementChallengeTypesLib.Status.Disqualified; proposals[index - 1].expirationTime = block.timestamp.add(configuration.settlementChallengeTimeout()); proposals[index - 1].disqualification.challenger = challengerWallet; proposals[index - 1].disqualification.nonce = candidateNonce; proposals[index - 1].disqualification.blockNumber = blockNumber; proposals[index - 1].disqualification.candidate.hash = candidateHash; proposals[index - 1].disqualification.candidate.kind = candidateKind; emit DisqualifyProposalEvent( challengedWallet, proposals[index - 1].nonce, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, challengerWallet, candidateNonce, candidateHash, candidateKind ); } function hasProposal(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { return 0 != proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; } function hasProposalTerminated(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:271]"); return proposals[index - 1].terminated; } function hasProposalExpired(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:286]"); return block.timestamp >= proposals[index - 1].expirationTime; } function proposalNonce(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:300]"); return proposals[index - 1].nonce; } function proposalReferenceBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:314]"); return proposals[index - 1].referenceBlockNumber; } function proposalDefinitionBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:328]"); return proposals[index - 1].definitionBlockNumber; } function proposalExpirationTime(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:342]"); return proposals[index - 1].expirationTime; } function proposalStatus(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (SettlementChallengeTypesLib.Status) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:356]"); return proposals[index - 1].status; } function proposalStageAmount(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (int256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:370]"); return proposals[index - 1].amounts.stage; } function proposalTargetBalanceAmount(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (int256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:384]"); return proposals[index - 1].amounts.targetBalance; } function proposalWalletInitiated(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:398]"); return proposals[index - 1].walletInitiated; } function proposalDisqualificationChallenger(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (address) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:412]"); return proposals[index - 1].disqualification.challenger; } function proposalDisqualificationBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:426]"); return proposals[index - 1].disqualification.blockNumber; } function proposalDisqualificationNonce(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:440]"); return proposals[index - 1].disqualification.nonce; } function proposalDisqualificationCandidateHash(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bytes32) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:454]"); return proposals[index - 1].disqualification.candidate.hash; } function proposalDisqualificationCandidateKind(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (string memory) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:468]"); return proposals[index - 1].disqualification.candidate.kind; } function upgradeProposal(SettlementChallengeTypesLib.Proposal memory proposal) public onlyWhenUpgrading { require( 0 == proposalIndexByWalletCurrency[proposal.wallet][proposal.currency.ct][proposal.currency.id], "Proposal exists for wallet and currency [NullSettlementChallengeState.sol:479]" ); proposals.push(proposal); uint256 index = proposals.length; proposalIndexByWalletCurrency[proposal.wallet][proposal.currency.ct][proposal.currency.id] = index; emit UpgradeProposalEvent(proposal); } function _initiateProposal(address wallet, uint256 nonce, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency memory currency, uint256 referenceBlockNumber, bool walletInitiated) private { require(stageAmount.isPositiveInt256(), "Stage amount not positive [NullSettlementChallengeState.sol:506]"); require(targetBalanceAmount.isPositiveInt256(), "Target balance amount not positive [NullSettlementChallengeState.sol:507]"); uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) { index = ++(proposals.length); proposalIndexByWalletCurrency[wallet][currency.ct][currency.id] = index; } proposals[index - 1].wallet = wallet; proposals[index - 1].nonce = nonce; proposals[index - 1].referenceBlockNumber = referenceBlockNumber; proposals[index - 1].definitionBlockNumber = block.number; proposals[index - 1].expirationTime = block.timestamp.add(configuration.settlementChallengeTimeout()); proposals[index - 1].status = SettlementChallengeTypesLib.Status.Qualified; proposals[index - 1].currency = currency; proposals[index - 1].amounts.stage = stageAmount; proposals[index - 1].amounts.targetBalance = targetBalanceAmount; proposals[index - 1].walletInitiated = walletInitiated; proposals[index - 1].terminated = false; } function _removeProposal(uint256 index) private returns (bool) { proposalIndexByWalletCurrency[proposals[index - 1].wallet][proposals[index - 1].currency.ct][proposals[index - 1].currency.id] = 0; if (index < proposals.length) { proposals[index - 1] = proposals[proposals.length - 1]; proposalIndexByWalletCurrency[proposals[index - 1].wallet][proposals[index - 1].currency.ct][proposals[index - 1].currency.id] = index; } proposals.length--; } function _activeBalanceLogEntry(address wallet, address currencyCt, uint256 currencyId) private view returns (int256 amount, uint256 blockNumber) { (int256 depositedAmount, uint256 depositedBlockNumber) = balanceTracker.lastFungibleRecord( wallet, balanceTracker.depositedBalanceType(), currencyCt, currencyId ); (int256 settledAmount, uint256 settledBlockNumber) = balanceTracker.lastFungibleRecord( wallet, balanceTracker.settledBalanceType(), currencyCt, currencyId ); amount = depositedAmount.add(settledAmount); blockNumber = depositedBlockNumber > settledBlockNumber ? depositedBlockNumber : settledBlockNumber; } } contract NullSettlementState is Ownable, Servable, CommunityVotable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; string constant public SET_MAX_NULL_NONCE_ACTION = "set_max_null_nonce"; string constant public SET_MAX_NONCE_ACTION = "set_max_nonce"; uint256 public maxNullNonce; mapping(address => mapping(address => mapping(uint256 => uint256))) public walletCurrencyMaxNonce; event SetMaxNullNonceEvent(uint256 maxNullNonce); event SetMaxNonceByWalletAndCurrencyEvent(address wallet, MonetaryTypesLib.Currency currency, uint256 maxNonce); event UpdateMaxNullNonceFromCommunityVoteEvent(uint256 maxNullNonce); constructor(address deployer) Ownable(deployer) public { } function setMaxNullNonce(uint256 _maxNullNonce) public onlyEnabledServiceAction(SET_MAX_NULL_NONCE_ACTION) { maxNullNonce = _maxNullNonce; emit SetMaxNullNonceEvent(_maxNullNonce); } function maxNonceByWalletAndCurrency(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { return walletCurrencyMaxNonce[wallet][currency.ct][currency.id]; } function setMaxNonceByWalletAndCurrency(address wallet, MonetaryTypesLib.Currency memory currency, uint256 _maxNullNonce) public onlyEnabledServiceAction(SET_MAX_NONCE_ACTION) { walletCurrencyMaxNonce[wallet][currency.ct][currency.id] = _maxNullNonce; emit SetMaxNonceByWalletAndCurrencyEvent(wallet, currency, _maxNullNonce); } function updateMaxNullNonceFromCommunityVote() public { uint256 _maxNullNonce = communityVote.getMaxNullNonce(); if (0 == _maxNullNonce) return; maxNullNonce = _maxNullNonce; emit UpdateMaxNullNonceFromCommunityVoteEvent(maxNullNonce); } } contract DriipSettlementChallengeState is Ownable, Servable, Configurable, Upgradable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; string constant public INITIATE_PROPOSAL_ACTION = "initiate_proposal"; string constant public TERMINATE_PROPOSAL_ACTION = "terminate_proposal"; string constant public REMOVE_PROPOSAL_ACTION = "remove_proposal"; string constant public DISQUALIFY_PROPOSAL_ACTION = "disqualify_proposal"; string constant public QUALIFY_PROPOSAL_ACTION = "qualify_proposal"; SettlementChallengeTypesLib.Proposal[] public proposals; mapping(address => mapping(address => mapping(uint256 => uint256))) public proposalIndexByWalletCurrency; mapping(address => mapping(uint256 => mapping(address => mapping(uint256 => uint256)))) public proposalIndexByWalletNonceCurrency; event InitiateProposalEvent(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated, bytes32 challengedHash, string challengedKind); event TerminateProposalEvent(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated, bytes32 challengedHash, string challengedKind); event RemoveProposalEvent(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated, bytes32 challengedHash, string challengedKind); event DisqualifyProposalEvent(address challengedWallet, uint256 challengedNonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated, address challengerWallet, uint256 candidateNonce, bytes32 candidateHash, string candidateKind); event QualifyProposalEvent(address challengedWallet, uint256 challengedNonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated, address challengerWallet, uint256 candidateNonce, bytes32 candidateHash, string candidateKind); event UpgradeProposalEvent(SettlementChallengeTypesLib.Proposal proposal); constructor(address deployer) Ownable(deployer) public { } function proposalsCount() public view returns (uint256) { return proposals.length; } function initiateProposal(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency memory currency, uint256 blockNumber, bool walletInitiated, bytes32 challengedHash, string memory challengedKind) public onlyEnabledServiceAction(INITIATE_PROPOSAL_ACTION) { _initiateProposal( wallet, nonce, cumulativeTransferAmount, stageAmount, targetBalanceAmount, currency, blockNumber, walletInitiated, challengedHash, challengedKind ); emit InitiateProposalEvent( wallet, nonce, cumulativeTransferAmount, stageAmount, targetBalanceAmount, currency, blockNumber, walletInitiated, challengedHash, challengedKind ); } function terminateProposal(address wallet, MonetaryTypesLib.Currency memory currency, bool clearNonce) public onlyEnabledServiceAction(TERMINATE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; if (clearNonce) proposalIndexByWalletNonceCurrency[wallet][proposals[index - 1].nonce][currency.ct][currency.id] = 0; proposals[index - 1].terminated = true; emit TerminateProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.cumulativeTransfer, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, proposals[index - 1].challenged.hash, proposals[index - 1].challenged.kind ); } function terminateProposal(address wallet, MonetaryTypesLib.Currency memory currency, bool clearNonce, bool walletTerminated) public onlyEnabledServiceAction(TERMINATE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; require(walletTerminated == proposals[index - 1].walletInitiated, "Wallet initiation and termination mismatch [DriipSettlementChallengeState.sol:165]"); if (clearNonce) proposalIndexByWalletNonceCurrency[wallet][proposals[index - 1].nonce][currency.ct][currency.id] = 0; proposals[index - 1].terminated = true; emit TerminateProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.cumulativeTransfer, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, proposals[index - 1].challenged.hash, proposals[index - 1].challenged.kind ); } function removeProposal(address wallet, MonetaryTypesLib.Currency memory currency) public onlyEnabledServiceAction(REMOVE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; emit RemoveProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.cumulativeTransfer, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, proposals[index - 1].challenged.hash, proposals[index - 1].challenged.kind ); _removeProposal(index); } function removeProposal(address wallet, MonetaryTypesLib.Currency memory currency, bool walletTerminated) public onlyEnabledServiceAction(REMOVE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; require(walletTerminated == proposals[index - 1].walletInitiated, "Wallet initiation and termination mismatch [DriipSettlementChallengeState.sol:225]"); emit RemoveProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.cumulativeTransfer, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, proposals[index - 1].challenged.hash, proposals[index - 1].challenged.kind ); _removeProposal(index); } function disqualifyProposal(address challengedWallet, MonetaryTypesLib.Currency memory currency, address challengerWallet, uint256 blockNumber, uint256 candidateNonce, bytes32 candidateHash, string memory candidateKind) public onlyEnabledServiceAction(DISQUALIFY_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[challengedWallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:255]"); proposals[index - 1].status = SettlementChallengeTypesLib.Status.Disqualified; proposals[index - 1].expirationTime = block.timestamp.add(configuration.settlementChallengeTimeout()); proposals[index - 1].disqualification.challenger = challengerWallet; proposals[index - 1].disqualification.nonce = candidateNonce; proposals[index - 1].disqualification.blockNumber = blockNumber; proposals[index - 1].disqualification.candidate.hash = candidateHash; proposals[index - 1].disqualification.candidate.kind = candidateKind; emit DisqualifyProposalEvent( challengedWallet, proposals[index - 1].nonce, proposals[index - 1].amounts.cumulativeTransfer, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, challengerWallet, candidateNonce, candidateHash, candidateKind ); } function qualifyProposal(address wallet, MonetaryTypesLib.Currency memory currency) public onlyEnabledServiceAction(QUALIFY_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:284]"); emit QualifyProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.cumulativeTransfer, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, proposals[index - 1].disqualification.challenger, proposals[index - 1].disqualification.nonce, proposals[index - 1].disqualification.candidate.hash, proposals[index - 1].disqualification.candidate.kind ); proposals[index - 1].status = SettlementChallengeTypesLib.Status.Qualified; proposals[index - 1].expirationTime = block.timestamp.add(configuration.settlementChallengeTimeout()); delete proposals[index - 1].disqualification; } function hasProposal(address wallet, uint256 nonce, MonetaryTypesLib.Currency memory currency) public view returns (bool) { return 0 != proposalIndexByWalletNonceCurrency[wallet][nonce][currency.ct][currency.id]; } function hasProposal(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { return 0 != proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; } function hasProposalTerminated(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:342]"); return proposals[index - 1].terminated; } function hasProposalExpired(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:357]"); return block.timestamp >= proposals[index - 1].expirationTime; } function proposalNonce(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:371]"); return proposals[index - 1].nonce; } function proposalReferenceBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:385]"); return proposals[index - 1].referenceBlockNumber; } function proposalDefinitionBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:399]"); return proposals[index - 1].definitionBlockNumber; } function proposalExpirationTime(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:413]"); return proposals[index - 1].expirationTime; } function proposalStatus(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (SettlementChallengeTypesLib.Status) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:427]"); return proposals[index - 1].status; } function proposalCumulativeTransferAmount(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (int256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:441]"); return proposals[index - 1].amounts.cumulativeTransfer; } function proposalStageAmount(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (int256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:455]"); return proposals[index - 1].amounts.stage; } function proposalTargetBalanceAmount(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (int256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:469]"); return proposals[index - 1].amounts.targetBalance; } function proposalChallengedHash(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bytes32) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:483]"); return proposals[index - 1].challenged.hash; } function proposalChallengedKind(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (string memory) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:497]"); return proposals[index - 1].challenged.kind; } function proposalWalletInitiated(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:511]"); return proposals[index - 1].walletInitiated; } function proposalDisqualificationChallenger(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (address) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:525]"); return proposals[index - 1].disqualification.challenger; } function proposalDisqualificationNonce(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:539]"); return proposals[index - 1].disqualification.nonce; } function proposalDisqualificationBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:553]"); return proposals[index - 1].disqualification.blockNumber; } function proposalDisqualificationCandidateHash(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bytes32) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:567]"); return proposals[index - 1].disqualification.candidate.hash; } function proposalDisqualificationCandidateKind(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (string memory) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:581]"); return proposals[index - 1].disqualification.candidate.kind; } function upgradeProposal(SettlementChallengeTypesLib.Proposal memory proposal) public onlyWhenUpgrading { require( 0 == proposalIndexByWalletNonceCurrency[proposal.wallet][proposal.nonce][proposal.currency.ct][proposal.currency.id], "Proposal exists for wallet, nonce and currency [DriipSettlementChallengeState.sol:592]" ); proposals.push(proposal); uint256 index = proposals.length; proposalIndexByWalletCurrency[proposal.wallet][proposal.currency.ct][proposal.currency.id] = index; proposalIndexByWalletNonceCurrency[proposal.wallet][proposal.nonce][proposal.currency.ct][proposal.currency.id] = index; emit UpgradeProposalEvent(proposal); } function _initiateProposal(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency memory currency, uint256 referenceBlockNumber, bool walletInitiated, bytes32 challengedHash, string memory challengedKind) private { require( 0 == proposalIndexByWalletNonceCurrency[wallet][nonce][currency.ct][currency.id], "Existing proposal found for wallet, nonce and currency [DriipSettlementChallengeState.sol:620]" ); require(stageAmount.isPositiveInt256(), "Stage amount not positive [DriipSettlementChallengeState.sol:626]"); require(targetBalanceAmount.isPositiveInt256(), "Target balance amount not positive [DriipSettlementChallengeState.sol:627]"); uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) { index = ++(proposals.length); proposalIndexByWalletCurrency[wallet][currency.ct][currency.id] = index; } proposals[index - 1].wallet = wallet; proposals[index - 1].nonce = nonce; proposals[index - 1].referenceBlockNumber = referenceBlockNumber; proposals[index - 1].definitionBlockNumber = block.number; proposals[index - 1].expirationTime = block.timestamp.add(configuration.settlementChallengeTimeout()); proposals[index - 1].status = SettlementChallengeTypesLib.Status.Qualified; proposals[index - 1].currency = currency; proposals[index - 1].amounts.cumulativeTransfer = cumulativeTransferAmount; proposals[index - 1].amounts.stage = stageAmount; proposals[index - 1].amounts.targetBalance = targetBalanceAmount; proposals[index - 1].walletInitiated = walletInitiated; proposals[index - 1].terminated = false; proposals[index - 1].challenged.hash = challengedHash; proposals[index - 1].challenged.kind = challengedKind; proposalIndexByWalletNonceCurrency[wallet][nonce][currency.ct][currency.id] = index; } function _removeProposal(uint256 index) private { proposalIndexByWalletCurrency[proposals[index - 1].wallet][proposals[index - 1].currency.ct][proposals[index - 1].currency.id] = 0; proposalIndexByWalletNonceCurrency[proposals[index - 1].wallet][proposals[index - 1].nonce][proposals[index - 1].currency.ct][proposals[index - 1].currency.id] = 0; if (index < proposals.length) { proposals[index - 1] = proposals[proposals.length - 1]; proposalIndexByWalletCurrency[proposals[index - 1].wallet][proposals[index - 1].currency.ct][proposals[index - 1].currency.id] = index; proposalIndexByWalletNonceCurrency[proposals[index - 1].wallet][proposals[index - 1].nonce][proposals[index - 1].currency.ct][proposals[index - 1].currency.id] = index; } proposals.length--; } } contract NullSettlement is Ownable, Configurable, ClientFundable, CommunityVotable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; NullSettlementChallengeState public nullSettlementChallengeState; NullSettlementState public nullSettlementState; DriipSettlementChallengeState public driipSettlementChallengeState; event SetNullSettlementChallengeStateEvent(NullSettlementChallengeState oldNullSettlementChallengeState, NullSettlementChallengeState newNullSettlementChallengeState); event SetNullSettlementStateEvent(NullSettlementState oldNullSettlementState, NullSettlementState newNullSettlementState); event SetDriipSettlementChallengeStateEvent(DriipSettlementChallengeState oldDriipSettlementChallengeState, DriipSettlementChallengeState newDriipSettlementChallengeState); event SettleNullEvent(address wallet, address currencyCt, uint256 currencyId, string standard); event SettleNullByProxyEvent(address proxy, address wallet, address currencyCt, uint256 currencyId, string standard); constructor(address deployer) Ownable(deployer) public { } function setNullSettlementChallengeState(NullSettlementChallengeState newNullSettlementChallengeState) public onlyDeployer notNullAddress(address(newNullSettlementChallengeState)) { NullSettlementChallengeState oldNullSettlementChallengeState = nullSettlementChallengeState; nullSettlementChallengeState = newNullSettlementChallengeState; emit SetNullSettlementChallengeStateEvent(oldNullSettlementChallengeState, nullSettlementChallengeState); } function setNullSettlementState(NullSettlementState newNullSettlementState) public onlyDeployer notNullAddress(address(newNullSettlementState)) { NullSettlementState oldNullSettlementState = nullSettlementState; nullSettlementState = newNullSettlementState; emit SetNullSettlementStateEvent(oldNullSettlementState, nullSettlementState); } function setDriipSettlementChallengeState(DriipSettlementChallengeState newDriipSettlementChallengeState) public onlyDeployer notNullAddress(address(newDriipSettlementChallengeState)) { DriipSettlementChallengeState oldDriipSettlementChallengeState = driipSettlementChallengeState; driipSettlementChallengeState = newDriipSettlementChallengeState; emit SetDriipSettlementChallengeStateEvent(oldDriipSettlementChallengeState, driipSettlementChallengeState); } function settleNull(address currencyCt, uint256 currencyId, string memory standard) public { _settleNull(msg.sender, MonetaryTypesLib.Currency(currencyCt, currencyId), standard); emit SettleNullEvent(msg.sender, currencyCt, currencyId, standard); } function settleNullByProxy(address wallet, address currencyCt, uint256 currencyId, string memory standard) public onlyOperator { _settleNull(wallet, MonetaryTypesLib.Currency(currencyCt, currencyId), standard); emit SettleNullByProxyEvent(msg.sender, wallet, currencyCt, currencyId, standard); } function _settleNull(address wallet, MonetaryTypesLib.Currency memory currency, string memory standard) private { require( !driipSettlementChallengeState.hasProposal(wallet, currency) || driipSettlementChallengeState.hasProposalTerminated(wallet, currency), "Overlapping driip settlement challenge proposal found [NullSettlement.sol:136]" ); require(nullSettlementChallengeState.hasProposal(wallet, currency), "No proposal found [NullSettlement.sol:143]"); require(!nullSettlementChallengeState.hasProposalTerminated(wallet, currency), "Proposal found terminated [NullSettlement.sol:146]"); require(nullSettlementChallengeState.hasProposalExpired(wallet, currency), "Proposal found not expired [NullSettlement.sol:149]"); require(SettlementChallengeTypesLib.Status.Qualified == nullSettlementChallengeState.proposalStatus( wallet, currency ), "Proposal found not qualified [NullSettlement.sol:152]"); require(configuration.isOperationalModeNormal(), "Not normal operational mode [NullSettlement.sol:158]"); require(communityVote.isDataAvailable(), "Data not available [NullSettlement.sol:159]"); uint256 nonce = nullSettlementChallengeState.proposalNonce(wallet, currency); require(nonce >= nullSettlementState.maxNonceByWalletAndCurrency(wallet, currency), "Nonce deemed smaller than max nonce by wallet and currency [NullSettlement.sol:166]"); nullSettlementState.setMaxNonceByWalletAndCurrency(wallet, currency, nonce); clientFund.stage( wallet, nullSettlementChallengeState.proposalStageAmount( wallet, currency ), currency.ct, currency.id, standard ); nullSettlementChallengeState.terminateProposal(wallet, currency); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":false,"inputs":[],"name":"triggerSelfDestruction","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract DriipSettlementChallengeState","name":"newDriipSettlementChallengeState","type":"address"}],"name":"setDriipSettlementChallengeState","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"selfDestructionDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"destructor","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"driipSettlementChallengeState","outputs":[{"internalType":"contract DriipSettlementChallengeState","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract Configuration","name":"newConfiguration","type":"address"}],"name":"setConfiguration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"},{"internalType":"string","name":"standard","type":"string"}],"name":"settleNull","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"freezeCommunityVote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"configuration","outputs":[{"internalType":"contract Configuration","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract NullSettlementChallengeState","name":"newNullSettlementChallengeState","type":"address"}],"name":"setNullSettlementChallengeState","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"disableSelfDestruction","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nullSettlementState","outputs":[{"internalType":"contract NullSettlementState","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"},{"internalType":"string","name":"standard","type":"string"}],"name":"settleNullByProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"communityVoteFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newDeployer","type":"address"}],"name":"setDeployer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOperator","type":"address"}],"name":"setOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract ClientFund","name":"newClientFund","type":"address"}],"name":"setClientFund","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"communityVote","outputs":[{"internalType":"contract CommunityVote","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract NullSettlementState","name":"newNullSettlementState","type":"address"}],"name":"setNullSettlementState","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"clientFund","outputs":[{"internalType":"contract ClientFund","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract CommunityVote","name":"newCommunityVote","type":"address"}],"name":"setCommunityVote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nullSettlementChallengeState","outputs":[{"internalType":"contract NullSettlementChallengeState","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"deployer","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract NullSettlementChallengeState","name":"oldNullSettlementChallengeState","type":"address"},{"indexed":false,"internalType":"contract NullSettlementChallengeState","name":"newNullSettlementChallengeState","type":"address"}],"name":"SetNullSettlementChallengeStateEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract NullSettlementState","name":"oldNullSettlementState","type":"address"},{"indexed":false,"internalType":"contract NullSettlementState","name":"newNullSettlementState","type":"address"}],"name":"SetNullSettlementStateEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract DriipSettlementChallengeState","name":"oldDriipSettlementChallengeState","type":"address"},{"indexed":false,"internalType":"contract DriipSettlementChallengeState","name":"newDriipSettlementChallengeState","type":"address"}],"name":"SetDriipSettlementChallengeStateEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"address","name":"currencyCt","type":"address"},{"indexed":false,"internalType":"uint256","name":"currencyId","type":"uint256"},{"indexed":false,"internalType":"string","name":"standard","type":"string"}],"name":"SettleNullEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"proxy","type":"address"},{"indexed":false,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"address","name":"currencyCt","type":"address"},{"indexed":false,"internalType":"uint256","name":"currencyId","type":"uint256"},{"indexed":false,"internalType":"string","name":"standard","type":"string"}],"name":"SettleNullByProxyEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract CommunityVote","name":"oldCommunityVote","type":"address"},{"indexed":false,"internalType":"contract CommunityVote","name":"newCommunityVote","type":"address"}],"name":"SetCommunityVoteEvent","type":"event"},{"anonymous":false,"inputs":[],"name":"FreezeCommunityVoteEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ClientFund","name":"oldClientFund","type":"address"},{"indexed":false,"internalType":"contract ClientFund","name":"newClientFund","type":"address"}],"name":"SetClientFundEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract Configuration","name":"oldConfiguration","type":"address"},{"indexed":false,"internalType":"contract Configuration","name":"newConfiguration","type":"address"}],"name":"SetConfigurationEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldDeployer","type":"address"},{"indexed":false,"internalType":"address","name":"newDeployer","type":"address"}],"name":"SetDeployerEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOperator","type":"address"},{"indexed":false,"internalType":"address","name":"newOperator","type":"address"}],"name":"SetOperatorEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"wallet","type":"address"}],"name":"SelfDestructionDisabledEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"wallet","type":"address"}],"name":"TriggerSelfDestructionEvent","type":"event"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162001c1e38038062001c1e8339810160408190526200003491620000b3565b80806001600160a01b0381166200004a57600080fd5b6001600160a01b0381163014156200006157600080fd5b5060008054610100600160a81b0319166101006001600160a01b0393909316928302179055600180546001600160a01b03191690911790555062000108565b8051620000ad81620000ee565b92915050565b600060208284031215620000c657600080fd5b6000620000d48484620000a0565b949350505050565b60006001600160a01b038216620000ad565b620000f981620000dc565b81146200010557600080fd5b50565b611b0680620001186000396000f3fe608060405234801561001057600080fd5b50600436106101285760003560e01c80632738a1121461012d5780632aa1c9d9146101375780632f013a001461014a5780634476d23b1461016857806351d7cd611461017d578063570ca73514610192578063627f09c31461019a57806366a83a6f146101ad578063670732a7146101c05780636c70bee9146101c85780636ccb43c8146101d057806370327ea1146101e357806379bf6b36146101eb5780637d1c66f5146101f35780638e9d6cbd14610206578063962147351461020e578063b3ab15fb14610221578063b71ded2f14610234578063bf24e7d014610247578063d5f394881461024f578063da5a3b7014610257578063e754476f1461026a578063e86ab8f614610272578063fa7424f214610285575b600080fd5b61013561028d565b005b6101356101453660046113a0565b6102f3565b61015261037a565b60405161015f91906118ec565b60405180910390f35b610170610383565b60405161015f91906117ba565b610185610397565b60405161015f91906118fa565b6101706103a6565b6101356101a83660046113a0565b6103b5565b6101356101bb36600461131e565b610456565b6101356104b3565b610185610502565b6101356101de3660046113a0565b610511565b61013561058b565b6101856105ee565b6101356102013660046112a6565b6105fd565b61015261067b565b61013561021c366004611280565b61068b565b61013561022f366004611280565b610741565b6101356102423660046113a0565b6107e4565b610185610875565b610170610884565b6101356102653660046113a0565b610898565b610185610912565b6101356102803660046113a0565b610921565b6101856109e5565b33610296610383565b6001600160a01b0316146102a957600080fd5b60005460ff16156102b957600080fd5b7f787a5d936e74f4b564b9153575886059829c78cd9927b1be5e0d976b317ef736336040516102e891906117c8565b60405180910390a133ff5b6102fb6109f4565b61030457600080fd5b806001600160a01b03811661031857600080fd5b600780546001600160a01b038481166001600160a01b031983161792839055604051918116927f4f7125332801996cdeaabf9cff1ac89ddf4b52c673558936affe853ab64a88da9261036d9285921690611908565b60405180910390a1505050565b60005460ff1681565b60005461010090046001600160a01b031690565b6007546001600160a01b031681565b6001546001600160a01b031681565b6103bd6109f4565b6103c657600080fd5b806001600160a01b0381166103da57600080fd5b60025482906001600160a01b03908116908216811461045057600280546001600160a01b038681166001600160a01b03198316179092556040519116907f634f61bf00e14adedce330c80c2823e16e184f189ebe853e1ddecc4a268477ff906104469083908890611908565b60405180910390a1505b50505050565b61047e336040518060400160405280866001600160a01b031681526020018581525083610a0a565b7f7af90506400bab47d6ae3ab121fdc88885ef30e2a90b93bb288f718d4b0140e13384848460405161036d9493929190611828565b6104bb6109f4565b6104c457600080fd5b6004805460ff60a01b1916600160a01b1790556040517fc1668d45f18667fb6eadfbcacfd5cdcc7dd4ecdfc9b0ab8786cfdbad86bb83d890600090a1565b6002546001600160a01b031681565b6105196109f4565b61052257600080fd5b806001600160a01b03811661053657600080fd5b600580546001600160a01b038481166001600160a01b031983161792839055604051918116927ff21c127205310467822e10c64b2d9ffae588e019194d6af71f2bdddc0b7ef5269261036d9285921690611908565b33610594610383565b6001600160a01b0316146105a757600080fd5b6000805460ff191660011790556040517fd5a2a04a775c741c2ca0dc46ea7ce4835190e1aaf1ca018def0e82568ec33616906105e49033906117c8565b60405180910390a1565b6006546001600160a01b031681565b6106056111d3565b61060e57600080fd5b610636846040518060400160405280866001600160a01b031681526020018581525083610a0a565b7f2230380baaf6690f9dafe46d5407a6f9ebc1bfc5bc0e0488bf5fd36504a7cf0a338585858560405161066d9594939291906117d6565b60405180910390a150505050565b600454600160a01b900460ff1681565b6106936109f4565b61069c57600080fd5b806001600160a01b0381166106b057600080fd5b6001600160a01b0381163014156106c657600080fd5b6000546001600160a01b03838116610100909204161461073d57600080546001600160a01b03848116610100908102610100600160a81b03198416179093556040519290910416907f977e5fa58e458501775e0008d275006294c5249e3c08d1d0e3a9f3acad14f6e49061036d908390869061186c565b5050565b6107496111d3565b61075257600080fd5b806001600160a01b03811661076657600080fd5b6001600160a01b03811630141561077c57600080fd5b6001546001600160a01b0383811691161461073d57600180546001600160a01b038481166001600160a01b03198316179092556040519116907f9f611b789425d0d5b90b920f1b2852907dd865c80074a30b1629aaa041d1812c9061036d908390869061186c565b6107ec6109f4565b6107f557600080fd5b806001600160a01b03811661080957600080fd5b60035482906001600160a01b03908116908216811461045057600380546001600160a01b038681166001600160a01b03198316179092556040519116907f4d96d2a04c886b313bd1e28be6324ed4c8867b3203e512756722f8be0195e16d906104469083908890611908565b6004546001600160a01b031681565b60005461010090046001600160a01b031681565b6108a06109f4565b6108a957600080fd5b806001600160a01b0381166108bd57600080fd5b600680546001600160a01b038481166001600160a01b031983161792839055604051918116927f7983934b0c7a4c64fbf3454ed2053b3bc71c8fd637308a7d2ee8eb51cbc68e359261036d9285921690611908565b6003546001600160a01b031681565b6109296109f4565b61093257600080fd5b806001600160a01b03811661094657600080fd5b60045482906001600160a01b03908116908216811461045057600454600160a01b900460ff16156109925760405162461bcd60e51b815260040161098990611993565b60405180910390fd5b600480546001600160a01b038681166001600160a01b03198316179092556040519116907f624c4d4225a45f5bf8a9755adba1ef9be3464a9970b05a371fb6cca0c0caf204906104469083908890611908565b6005546001600160a01b031681565b60005461010090046001600160a01b0316331490565b60075460405163076470a560e31b81526001600160a01b0390911690633b23852890610a3c90869086906004016118a9565b60206040518083038186803b158015610a5457600080fd5b505afa158015610a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a8c9190810190611382565b1580610b155750600754604051637ff81c3760e01b81526001600160a01b0390911690637ff81c3790610ac590869086906004016118a9565b60206040518083038186803b158015610add57600080fd5b505afa158015610af1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b159190810190611382565b610b315760405162461bcd60e51b815260040161098990611973565b60055460405163076470a560e31b81526001600160a01b0390911690633b23852890610b6390869086906004016118a9565b60206040518083038186803b158015610b7b57600080fd5b505afa158015610b8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bb39190810190611382565b610bcf5760405162461bcd60e51b815260040161098990611943565b600554604051637ff81c3760e01b81526001600160a01b0390911690637ff81c3790610c0190869086906004016118a9565b60206040518083038186803b158015610c1957600080fd5b505afa158015610c2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c519190810190611382565b15610c6e5760405162461bcd60e51b815260040161098990611963565b600554604051635482c73560e01b81526001600160a01b0390911690635482c73590610ca090869086906004016118a9565b60206040518083038186803b158015610cb857600080fd5b505afa158015610ccc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610cf09190810190611382565b610d0c5760405162461bcd60e51b815260040161098990611933565b60055460405163b6e2fc3360e01b81526001600160a01b039091169063b6e2fc3390610d3e90869086906004016118a9565b60206040518083038186803b158015610d5657600080fd5b505afa158015610d6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d8e91908101906113be565b6001811115610d9957fe5b15610db65760405162461bcd60e51b8152600401610989906119a3565b600260009054906101000a90046001600160a01b03166001600160a01b031663f71e860f6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e0457600080fd5b505afa158015610e18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e3c9190810190611382565b610e585760405162461bcd60e51b815260040161098990611983565b6004805460408051634ca7103b60e11b815290516001600160a01b039092169263994e2076928282019260209290829003018186803b158015610e9a57600080fd5b505afa158015610eae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ed29190810190611382565b610eee5760405162461bcd60e51b815260040161098990611923565b600554604051632ee2ed2560e01b81526000916001600160a01b031690632ee2ed2590610f2190879087906004016118a9565b60206040518083038186803b158015610f3957600080fd5b505afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f7191908101906113dc565b600654604051633858654b60e01b81529192506001600160a01b031690633858654b90610fa490879087906004016118a9565b60206040518083038186803b158015610fbc57600080fd5b505afa158015610fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ff491908101906113dc565b8110156110135760405162461bcd60e51b815260040161098990611953565b600654604051630284774760e31b81526001600160a01b0390911690631423ba3890611047908790879086906004016118c4565b600060405180830381600087803b15801561106157600080fd5b505af1158015611075573d6000803e3d6000fd5b5050600354600554604051633007230f60e11b81526001600160a01b03928316945063ad468df9935088929091169063600e461e906110ba9084908a906004016118a9565b60206040518083038186803b1580156110d257600080fd5b505afa1580156110e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061110a91908101906113dc565b865160208801516040516001600160e01b031960e087901b1681526111379493929190899060040161188e565b600060405180830381600087803b15801561115157600080fd5b505af1158015611165573d6000803e3d6000fd5b5050600554604051632ce4e29b60e21b81526001600160a01b03909116925063b3938a6c915061119b90879087906004016118a9565b600060405180830381600087803b1580156111b557600080fd5b505af11580156111c9573d6000803e3d6000fd5b5050505050505050565b6001546001600160a01b0316331490565b80356111ef81611a84565b92915050565b80516111ef81611a9b565b80356111ef81611aa4565b80516111ef81611aad565b80516111ef81611aba565b600082601f83011261123257600080fd5b8135611245611240826119d9565b6119b3565b9150808252602083016020830185838301111561126157600080fd5b61126c838284611a42565b50505092915050565b80356111ef81611aba565b60006020828403121561129257600080fd5b600061129e84846111e4565b949350505050565b600080600080608085870312156112bc57600080fd5b60006112c887876111e4565b94505060206112d9878288016111e4565b93505060406112ea87828801611275565b92505060608501356001600160401b0381111561130657600080fd5b61131287828801611221565b91505092959194509250565b60008060006060848603121561133357600080fd5b600061133f86866111e4565b935050602061135086828701611275565b92505060408401356001600160401b0381111561136c57600080fd5b61137886828701611221565b9150509250925092565b60006020828403121561139457600080fd5b600061129e84846111f5565b6000602082840312156113b257600080fd5b600061129e8484611200565b6000602082840312156113d057600080fd5b600061129e848461120b565b6000602082840312156113ee57600080fd5b600061129e8484611216565b61140381611a37565b82525050565b61140381611a0d565b61140381611a18565b61140381611a1d565b61140381611a28565b600061143882611a00565b6114428185611a04565b9350611452818560208601611a4e565b61145b81611a7a565b9093019392505050565b6000611472602b83611a04565b7f44617461206e6f7420617661696c61626c65205b4e756c6c536574746c656d6581526a6e742e736f6c3a3135395d60a81b602082015260400192915050565b60006114bf603383611a04565b7f50726f706f73616c20666f756e64206e6f742065787069726564205b4e756c6c815272536574746c656d656e742e736f6c3a3134395d60681b602082015260400192915050565b6000611514602a83611a04565b7f4e6f2070726f706f73616c20666f756e64205b4e756c6c536574746c656d656e815269742e736f6c3a3134335d60b01b602082015260400192915050565b6000611560605383611a04565b7f4e6f6e6365206465656d656420736d616c6c6572207468616e206d6178206e6f81527f6e63652062792077616c6c657420616e642063757272656e6379205b4e756c6c602082015272536574746c656d656e742e736f6c3a3136365d60681b604082015260600192915050565b60006115db603283611a04565b7f50726f706f73616c20666f756e64207465726d696e61746564205b4e756c6c538152716574746c656d656e742e736f6c3a3134365d60701b602082015260400192915050565b600061162f604e83611a04565b7f4f7665726c617070696e6720647269697020736574746c656d656e742063686181527f6c6c656e67652070726f706f73616c20666f756e64205b4e756c6c536574746c60208201526d656d656e742e736f6c3a3133365d60901b604082015260600192915050565b60006116a5603483611a04565b7f4e6f74206e6f726d616c206f7065726174696f6e616c206d6f6465205b4e756c8152736c536574746c656d656e742e736f6c3a3135385d60601b602082015260400192915050565b60006116fb602f83611a04565b7f436f6d6d756e69747920766f74652066726f7a656e205b436f6d6d756e69747981526e566f7461626c652e736f6c3a34315d60881b602082015260400192915050565b600061174c603583611a04565b7f50726f706f73616c20666f756e64206e6f74207175616c6966696564205b4e758152746c6c536574746c656d656e742e736f6c3a3135325d60581b602082015260400192915050565b805160408301906117a78482611409565b5060208201516104506020850182611424565b602081016111ef8284611409565b602081016111ef82846113fa565b60a081016117e482886113fa565b6117f16020830187611409565b6117fe6040830186611409565b61180b6060830185611424565b818103608083015261181d818461142d565b979650505050505050565b6080810161183682876113fa565b6118436020830186611409565b6118506040830185611424565b8181036060830152611862818461142d565b9695505050505050565b6040810161187a8285611409565b6118876020830184611409565b9392505050565b60a0810161189c8288611409565b6117f16020830187611424565b606081016118b78285611409565b6118876020830184611796565b608081016118d28286611409565b6118df6020830185611796565b61129e6060830184611424565b602081016111ef8284611412565b602081016111ef828461141b565b60408101611916828561141b565b611887602083018461141b565b602080825281016111ef81611465565b602080825281016111ef816114b2565b602080825281016111ef81611507565b602080825281016111ef81611553565b602080825281016111ef816115ce565b602080825281016111ef81611622565b602080825281016111ef81611698565b602080825281016111ef816116ee565b602080825281016111ef8161173f565b6040518181016001600160401b03811182821017156119d157600080fd5b604052919050565b60006001600160401b038211156119ef57600080fd5b506020601f91909101601f19160190565b5190565b90815260200190565b60006111ef82611a2b565b151590565b60006111ef82611a0d565b90565b6001600160a01b031690565b60006111ef82611a1d565b82818337506000910152565b60005b83811015611a69578181015183820152602001611a51565b838111156104505750506000910152565b601f01601f191690565b611a8d81611a0d565b8114611a9857600080fd5b50565b611a8d81611a18565b611a8d81611a1d565b60028110611a9857600080fd5b611a8d81611a2856fea365627a7a72315820ae654329e250ad9bf2bd2066a912b24bfd9af0af1318b6b449270d0de657b61f6c6578706572696d656e74616cf564736f6c634300050b0040000000000000000000000000f05179bac3d1fbef58a2fcd7ad0f769840027cc6
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101285760003560e01c80632738a1121461012d5780632aa1c9d9146101375780632f013a001461014a5780634476d23b1461016857806351d7cd611461017d578063570ca73514610192578063627f09c31461019a57806366a83a6f146101ad578063670732a7146101c05780636c70bee9146101c85780636ccb43c8146101d057806370327ea1146101e357806379bf6b36146101eb5780637d1c66f5146101f35780638e9d6cbd14610206578063962147351461020e578063b3ab15fb14610221578063b71ded2f14610234578063bf24e7d014610247578063d5f394881461024f578063da5a3b7014610257578063e754476f1461026a578063e86ab8f614610272578063fa7424f214610285575b600080fd5b61013561028d565b005b6101356101453660046113a0565b6102f3565b61015261037a565b60405161015f91906118ec565b60405180910390f35b610170610383565b60405161015f91906117ba565b610185610397565b60405161015f91906118fa565b6101706103a6565b6101356101a83660046113a0565b6103b5565b6101356101bb36600461131e565b610456565b6101356104b3565b610185610502565b6101356101de3660046113a0565b610511565b61013561058b565b6101856105ee565b6101356102013660046112a6565b6105fd565b61015261067b565b61013561021c366004611280565b61068b565b61013561022f366004611280565b610741565b6101356102423660046113a0565b6107e4565b610185610875565b610170610884565b6101356102653660046113a0565b610898565b610185610912565b6101356102803660046113a0565b610921565b6101856109e5565b33610296610383565b6001600160a01b0316146102a957600080fd5b60005460ff16156102b957600080fd5b7f787a5d936e74f4b564b9153575886059829c78cd9927b1be5e0d976b317ef736336040516102e891906117c8565b60405180910390a133ff5b6102fb6109f4565b61030457600080fd5b806001600160a01b03811661031857600080fd5b600780546001600160a01b038481166001600160a01b031983161792839055604051918116927f4f7125332801996cdeaabf9cff1ac89ddf4b52c673558936affe853ab64a88da9261036d9285921690611908565b60405180910390a1505050565b60005460ff1681565b60005461010090046001600160a01b031690565b6007546001600160a01b031681565b6001546001600160a01b031681565b6103bd6109f4565b6103c657600080fd5b806001600160a01b0381166103da57600080fd5b60025482906001600160a01b03908116908216811461045057600280546001600160a01b038681166001600160a01b03198316179092556040519116907f634f61bf00e14adedce330c80c2823e16e184f189ebe853e1ddecc4a268477ff906104469083908890611908565b60405180910390a1505b50505050565b61047e336040518060400160405280866001600160a01b031681526020018581525083610a0a565b7f7af90506400bab47d6ae3ab121fdc88885ef30e2a90b93bb288f718d4b0140e13384848460405161036d9493929190611828565b6104bb6109f4565b6104c457600080fd5b6004805460ff60a01b1916600160a01b1790556040517fc1668d45f18667fb6eadfbcacfd5cdcc7dd4ecdfc9b0ab8786cfdbad86bb83d890600090a1565b6002546001600160a01b031681565b6105196109f4565b61052257600080fd5b806001600160a01b03811661053657600080fd5b600580546001600160a01b038481166001600160a01b031983161792839055604051918116927ff21c127205310467822e10c64b2d9ffae588e019194d6af71f2bdddc0b7ef5269261036d9285921690611908565b33610594610383565b6001600160a01b0316146105a757600080fd5b6000805460ff191660011790556040517fd5a2a04a775c741c2ca0dc46ea7ce4835190e1aaf1ca018def0e82568ec33616906105e49033906117c8565b60405180910390a1565b6006546001600160a01b031681565b6106056111d3565b61060e57600080fd5b610636846040518060400160405280866001600160a01b031681526020018581525083610a0a565b7f2230380baaf6690f9dafe46d5407a6f9ebc1bfc5bc0e0488bf5fd36504a7cf0a338585858560405161066d9594939291906117d6565b60405180910390a150505050565b600454600160a01b900460ff1681565b6106936109f4565b61069c57600080fd5b806001600160a01b0381166106b057600080fd5b6001600160a01b0381163014156106c657600080fd5b6000546001600160a01b03838116610100909204161461073d57600080546001600160a01b03848116610100908102610100600160a81b03198416179093556040519290910416907f977e5fa58e458501775e0008d275006294c5249e3c08d1d0e3a9f3acad14f6e49061036d908390869061186c565b5050565b6107496111d3565b61075257600080fd5b806001600160a01b03811661076657600080fd5b6001600160a01b03811630141561077c57600080fd5b6001546001600160a01b0383811691161461073d57600180546001600160a01b038481166001600160a01b03198316179092556040519116907f9f611b789425d0d5b90b920f1b2852907dd865c80074a30b1629aaa041d1812c9061036d908390869061186c565b6107ec6109f4565b6107f557600080fd5b806001600160a01b03811661080957600080fd5b60035482906001600160a01b03908116908216811461045057600380546001600160a01b038681166001600160a01b03198316179092556040519116907f4d96d2a04c886b313bd1e28be6324ed4c8867b3203e512756722f8be0195e16d906104469083908890611908565b6004546001600160a01b031681565b60005461010090046001600160a01b031681565b6108a06109f4565b6108a957600080fd5b806001600160a01b0381166108bd57600080fd5b600680546001600160a01b038481166001600160a01b031983161792839055604051918116927f7983934b0c7a4c64fbf3454ed2053b3bc71c8fd637308a7d2ee8eb51cbc68e359261036d9285921690611908565b6003546001600160a01b031681565b6109296109f4565b61093257600080fd5b806001600160a01b03811661094657600080fd5b60045482906001600160a01b03908116908216811461045057600454600160a01b900460ff16156109925760405162461bcd60e51b815260040161098990611993565b60405180910390fd5b600480546001600160a01b038681166001600160a01b03198316179092556040519116907f624c4d4225a45f5bf8a9755adba1ef9be3464a9970b05a371fb6cca0c0caf204906104469083908890611908565b6005546001600160a01b031681565b60005461010090046001600160a01b0316331490565b60075460405163076470a560e31b81526001600160a01b0390911690633b23852890610a3c90869086906004016118a9565b60206040518083038186803b158015610a5457600080fd5b505afa158015610a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a8c9190810190611382565b1580610b155750600754604051637ff81c3760e01b81526001600160a01b0390911690637ff81c3790610ac590869086906004016118a9565b60206040518083038186803b158015610add57600080fd5b505afa158015610af1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b159190810190611382565b610b315760405162461bcd60e51b815260040161098990611973565b60055460405163076470a560e31b81526001600160a01b0390911690633b23852890610b6390869086906004016118a9565b60206040518083038186803b158015610b7b57600080fd5b505afa158015610b8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bb39190810190611382565b610bcf5760405162461bcd60e51b815260040161098990611943565b600554604051637ff81c3760e01b81526001600160a01b0390911690637ff81c3790610c0190869086906004016118a9565b60206040518083038186803b158015610c1957600080fd5b505afa158015610c2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c519190810190611382565b15610c6e5760405162461bcd60e51b815260040161098990611963565b600554604051635482c73560e01b81526001600160a01b0390911690635482c73590610ca090869086906004016118a9565b60206040518083038186803b158015610cb857600080fd5b505afa158015610ccc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610cf09190810190611382565b610d0c5760405162461bcd60e51b815260040161098990611933565b60055460405163b6e2fc3360e01b81526001600160a01b039091169063b6e2fc3390610d3e90869086906004016118a9565b60206040518083038186803b158015610d5657600080fd5b505afa158015610d6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d8e91908101906113be565b6001811115610d9957fe5b15610db65760405162461bcd60e51b8152600401610989906119a3565b600260009054906101000a90046001600160a01b03166001600160a01b031663f71e860f6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e0457600080fd5b505afa158015610e18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e3c9190810190611382565b610e585760405162461bcd60e51b815260040161098990611983565b6004805460408051634ca7103b60e11b815290516001600160a01b039092169263994e2076928282019260209290829003018186803b158015610e9a57600080fd5b505afa158015610eae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ed29190810190611382565b610eee5760405162461bcd60e51b815260040161098990611923565b600554604051632ee2ed2560e01b81526000916001600160a01b031690632ee2ed2590610f2190879087906004016118a9565b60206040518083038186803b158015610f3957600080fd5b505afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f7191908101906113dc565b600654604051633858654b60e01b81529192506001600160a01b031690633858654b90610fa490879087906004016118a9565b60206040518083038186803b158015610fbc57600080fd5b505afa158015610fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ff491908101906113dc565b8110156110135760405162461bcd60e51b815260040161098990611953565b600654604051630284774760e31b81526001600160a01b0390911690631423ba3890611047908790879086906004016118c4565b600060405180830381600087803b15801561106157600080fd5b505af1158015611075573d6000803e3d6000fd5b5050600354600554604051633007230f60e11b81526001600160a01b03928316945063ad468df9935088929091169063600e461e906110ba9084908a906004016118a9565b60206040518083038186803b1580156110d257600080fd5b505afa1580156110e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061110a91908101906113dc565b865160208801516040516001600160e01b031960e087901b1681526111379493929190899060040161188e565b600060405180830381600087803b15801561115157600080fd5b505af1158015611165573d6000803e3d6000fd5b5050600554604051632ce4e29b60e21b81526001600160a01b03909116925063b3938a6c915061119b90879087906004016118a9565b600060405180830381600087803b1580156111b557600080fd5b505af11580156111c9573d6000803e3d6000fd5b5050505050505050565b6001546001600160a01b0316331490565b80356111ef81611a84565b92915050565b80516111ef81611a9b565b80356111ef81611aa4565b80516111ef81611aad565b80516111ef81611aba565b600082601f83011261123257600080fd5b8135611245611240826119d9565b6119b3565b9150808252602083016020830185838301111561126157600080fd5b61126c838284611a42565b50505092915050565b80356111ef81611aba565b60006020828403121561129257600080fd5b600061129e84846111e4565b949350505050565b600080600080608085870312156112bc57600080fd5b60006112c887876111e4565b94505060206112d9878288016111e4565b93505060406112ea87828801611275565b92505060608501356001600160401b0381111561130657600080fd5b61131287828801611221565b91505092959194509250565b60008060006060848603121561133357600080fd5b600061133f86866111e4565b935050602061135086828701611275565b92505060408401356001600160401b0381111561136c57600080fd5b61137886828701611221565b9150509250925092565b60006020828403121561139457600080fd5b600061129e84846111f5565b6000602082840312156113b257600080fd5b600061129e8484611200565b6000602082840312156113d057600080fd5b600061129e848461120b565b6000602082840312156113ee57600080fd5b600061129e8484611216565b61140381611a37565b82525050565b61140381611a0d565b61140381611a18565b61140381611a1d565b61140381611a28565b600061143882611a00565b6114428185611a04565b9350611452818560208601611a4e565b61145b81611a7a565b9093019392505050565b6000611472602b83611a04565b7f44617461206e6f7420617661696c61626c65205b4e756c6c536574746c656d6581526a6e742e736f6c3a3135395d60a81b602082015260400192915050565b60006114bf603383611a04565b7f50726f706f73616c20666f756e64206e6f742065787069726564205b4e756c6c815272536574746c656d656e742e736f6c3a3134395d60681b602082015260400192915050565b6000611514602a83611a04565b7f4e6f2070726f706f73616c20666f756e64205b4e756c6c536574746c656d656e815269742e736f6c3a3134335d60b01b602082015260400192915050565b6000611560605383611a04565b7f4e6f6e6365206465656d656420736d616c6c6572207468616e206d6178206e6f81527f6e63652062792077616c6c657420616e642063757272656e6379205b4e756c6c602082015272536574746c656d656e742e736f6c3a3136365d60681b604082015260600192915050565b60006115db603283611a04565b7f50726f706f73616c20666f756e64207465726d696e61746564205b4e756c6c538152716574746c656d656e742e736f6c3a3134365d60701b602082015260400192915050565b600061162f604e83611a04565b7f4f7665726c617070696e6720647269697020736574746c656d656e742063686181527f6c6c656e67652070726f706f73616c20666f756e64205b4e756c6c536574746c60208201526d656d656e742e736f6c3a3133365d60901b604082015260600192915050565b60006116a5603483611a04565b7f4e6f74206e6f726d616c206f7065726174696f6e616c206d6f6465205b4e756c8152736c536574746c656d656e742e736f6c3a3135385d60601b602082015260400192915050565b60006116fb602f83611a04565b7f436f6d6d756e69747920766f74652066726f7a656e205b436f6d6d756e69747981526e566f7461626c652e736f6c3a34315d60881b602082015260400192915050565b600061174c603583611a04565b7f50726f706f73616c20666f756e64206e6f74207175616c6966696564205b4e758152746c6c536574746c656d656e742e736f6c3a3135325d60581b602082015260400192915050565b805160408301906117a78482611409565b5060208201516104506020850182611424565b602081016111ef8284611409565b602081016111ef82846113fa565b60a081016117e482886113fa565b6117f16020830187611409565b6117fe6040830186611409565b61180b6060830185611424565b818103608083015261181d818461142d565b979650505050505050565b6080810161183682876113fa565b6118436020830186611409565b6118506040830185611424565b8181036060830152611862818461142d565b9695505050505050565b6040810161187a8285611409565b6118876020830184611409565b9392505050565b60a0810161189c8288611409565b6117f16020830187611424565b606081016118b78285611409565b6118876020830184611796565b608081016118d28286611409565b6118df6020830185611796565b61129e6060830184611424565b602081016111ef8284611412565b602081016111ef828461141b565b60408101611916828561141b565b611887602083018461141b565b602080825281016111ef81611465565b602080825281016111ef816114b2565b602080825281016111ef81611507565b602080825281016111ef81611553565b602080825281016111ef816115ce565b602080825281016111ef81611622565b602080825281016111ef81611698565b602080825281016111ef816116ee565b602080825281016111ef8161173f565b6040518181016001600160401b03811182821017156119d157600080fd5b604052919050565b60006001600160401b038211156119ef57600080fd5b506020601f91909101601f19160190565b5190565b90815260200190565b60006111ef82611a2b565b151590565b60006111ef82611a0d565b90565b6001600160a01b031690565b60006111ef82611a1d565b82818337506000910152565b60005b83811015611a69578181015183820152602001611a51565b838111156104505750506000910152565b601f01601f191690565b611a8d81611a0d565b8114611a9857600080fd5b50565b611a8d81611a18565b611a8d81611a1d565b60028110611a9857600080fd5b611a8d81611a2856fea365627a7a72315820ae654329e250ad9bf2bd2066a912b24bfd9af0af1318b6b449270d0de657b61f6c6578706572696d656e74616cf564736f6c634300050b0040
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f05179bac3d1fbef58a2fcd7ad0f769840027cc6
-----Decoded View---------------
Arg [0] : deployer (address): 0xf05179bAc3D1fbEF58A2fcD7AD0F769840027cc6
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000f05179bac3d1fbef58a2fcd7ad0f769840027cc6
Deployed Bytecode Sourcemap
237916:5501:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;237916:5501:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1229:285;;;:::i;:::-;;240109:510;;;;;;;;;:::i;691:35::-;;;:::i;:::-;;;;;;;;;;;;;;;;2011:106;;;:::i;:::-;;;;;;;;238228:66;;;:::i;:::-;;;;;;;;1625:23;;;:::i;47333:416::-;;;;;;;;;:::i;240651:303::-;;;;;;;;;:::i;180713:165::-;;;:::i;47142:34::-;;;:::i;239181:498::-;;;;;;;;;:::i;979:236::-;;;:::i;238175:46::-;;;:::i;240992:355::-;;;;;;;;;:::i;179955:31::-;;;:::i;2137:349::-;;;;;;;;;:::i;2506:::-;;;;;;;;;:::i;178378:369::-;;;;;;;;;:::i;179914:34::-;;;:::i;1595:23::-;;;:::i;239699:390::-;;;;;;;;;:::i;178208:28::-;;;:::i;180182:511::-;;;;;;;;;:::i;238104:64::-;;;:::i;1229:285::-;1325:10;1309:12;:10;:12::i;:::-;-1:-1:-1;;;;;1309:26:0;;1301:35;;;;;;1368:23;;;;1367:24;1359:33;;;;;;1420:39;1448:10;1420:39;;;;;;;;;;;;;;;1495:10;1482:24;240109:510;3357:12;:10;:12::i;:::-;3349:21;;;;;;240273:32;-1:-1:-1;;;;;179:22:0;;171:31;;;;;;240389:29;;;-1:-1:-1;;;;;240429:64:0;;;-1:-1:-1;;;;;;240429:64:0;;;;;;;240509:102;;240389:29;;;;240509:102;;;;240389:29;;240581;;240509:102;;;;;;;;;;213:1;3381;240109:510;:::o;691:35::-;;;;;;:::o;2011:106::-;2069:7;2101:8;;;;-1:-1:-1;;;;;2101:8:0;;2011:106::o;238228:66::-;;;-1:-1:-1;;;;;238228:66:0;;:::o;1625:23::-;;;-1:-1:-1;;;;;1625:23:0;;:::o;47333:416::-;3357:12;:10;:12::i;:::-;3349:21;;;;;;47449:16;-1:-1:-1;;;;;179:22:0;;171:31;;;;;;47525:13;;47498:16;;-1:-1:-1;;;;;47525:13:0;;;;587:22;;;;583:42;;47600:13;;;-1:-1:-1;;;;;47624:32:0;;;-1:-1:-1;;;;;;47624:32:0;;;;;;47684:57;;47600:13;;;47684:57;;;;47600:13;;47640:16;;47684:57;;;;;;;;;;624:1;583:42;213:1;;3381;47333:416;:::o;240651:303::-;240773:84;240785:10;240797:49;;;;;;;;240823:10;-1:-1:-1;;;;;240797:49:0;;;;;240835:10;240797:49;;;240848:8;240773:11;:84::i;:::-;240885:61;240901:10;240913;240925;240937:8;240885:61;;;;;;;;;;180713:165;3357:12;:10;:12::i;:::-;3349:21;;;;;;180790:19;:26;;-1:-1:-1;;;;180790:26:0;-1:-1:-1;;;180790:26:0;;;180844;;;;180790;;180844;180713:165::o;47142:34::-;;;-1:-1:-1;;;;;47142:34:0;;:::o;239181:498::-;3357:12;:10;:12::i;:::-;3349:21;;;;;;239342:31;-1:-1:-1;;;;;179:22:0;;171:31;;;;;;239455:28;;;-1:-1:-1;;;;;239494:62:0;;;-1:-1:-1;;;;;;239494:62:0;;;;;;;239572:99;;239455:28;;;;239572:99;;;;239455:28;;239642;;239572:99;;979:236;1075:10;1059:12;:10;:12::i;:::-;-1:-1:-1;;;;;1059:26:0;;1051:35;;;;;;1109:23;:30;;-1:-1:-1;;1109:30:0;1135:4;1109:30;;;1167:40;;;;;;1196:10;;1167:40;;;;;;;;;;979:236::o;238175:46::-;;;-1:-1:-1;;;;;238175:46:0;;:::o;240992:355::-;3525:12;:10;:12::i;:::-;3517:21;;;;;;241155:80;241167:6;241175:49;;;;;;;;241201:10;-1:-1:-1;;;;;241175:49:0;;;;;241213:10;241175:49;;;241226:8;241155:11;:80::i;:::-;241263:76;241286:10;241298:6;241306:10;241318;241330:8;241263:76;;;;;;;;;;;;;;;;;;;240992:355;;;;:::o;179955:31::-;;;-1:-1:-1;;;179955:31:0;;;;;:::o;2137:349::-;3357:12;:10;:12::i;:::-;3349:21;;;;;;2235:11;-1:-1:-1;;;;;412:22:0;;404:31;;;;;;-1:-1:-1;;;;;454:25:0;;474:4;454:25;;446:34;;;;;;2283:8;;-1:-1:-1;;;;;2268:23:0;;;2283:8;;;;;2268:23;2264:215;;2322:19;2344:8;;-1:-1:-1;;;;;2367:22:0;;;2344:8;2367:22;;;-1:-1:-1;;;;;;2367:22:0;;;;;;2425:42;;2344:8;;;;;;2425:42;;;;2344:8;;2378:11;;2425:42;;2264:215;3381:1;2137:349;:::o;2506:::-;3525:12;:10;:12::i;:::-;3517:21;;;;;;2604:11;-1:-1:-1;;;;;412:22:0;;404:31;;;;;;-1:-1:-1;;;;;454:25:0;;474:4;454:25;;446:34;;;;;;2652:8;;-1:-1:-1;;;;;2637:23:0;;;2652:8;;2637:23;2633:215;;2713:8;;;-1:-1:-1;;;;;2736:22:0;;;-1:-1:-1;;;;;;2736:22:0;;;;;;2794:42;;2713:8;;;2794:42;;;;2713:8;;2747:11;;2794:42;;178378:369;3357:12;:10;:12::i;:::-;3349:21;;;;;;178480:13;-1:-1:-1;;;;;179:22:0;;171:31;;;;;;178550:10;;178526:13;;-1:-1:-1;;;;;178550:10:0;;;;587:22;;;;583:42;;178616:10;;;-1:-1:-1;;;;;178637:26:0;;;-1:-1:-1;;;;;;178637:26:0;;;;;;178691:48;;178616:10;;;178691:48;;;;178616:10;;178650:13;;178691:48;;179914:34;;;-1:-1:-1;;;;;179914:34:0;;:::o;1595:23::-;;;;;;-1:-1:-1;;;;;1595:23:0;;:::o;239699:390::-;3357:12;:10;:12::i;:::-;3349:21;;;;;;239833:22;-1:-1:-1;;;;;179:22:0;;171:31;;;;;;239919:19;;;-1:-1:-1;;;;;239949:44:0;;;-1:-1:-1;;;;;;239949:44:0;;;;;;;240009:72;;239919:19;;;;240009:72;;;;239919:19;;240061;;240009:72;;178208:28;;;-1:-1:-1;;;;;178208:28:0;;:::o;180182:511::-;3357:12;:10;:12::i;:::-;3349:21;;;;;;180300:16;-1:-1:-1;;;;;179:22:0;;171:31;;;;;;180376:13;;180349:16;;-1:-1:-1;;;;;180376:13:0;;;;587:22;;;;583:42;;180417:19;;-1:-1:-1;;;180417:19:0;;;;180416:20;180408:80;;;;-1:-1:-1;;;180408:80:0;;;;;;;;;;;;;;;;;180544:13;;;-1:-1:-1;;;;;180568:32:0;;;-1:-1:-1;;;;;;180568:32:0;;;;;;180628:57;;180544:13;;;180628:57;;;;180544:13;;180584:16;;180628:57;;238104:64;;;-1:-1:-1;;;;;238104:64:0;;:::o;2875:119::-;2935:4;2978:8;;;;-1:-1:-1;;;;;2978:8:0;2964:10;:22;;2875:119::o;241373:2041::-;241539:29;;:59;;-1:-1:-1;;;241539:59:0;;-1:-1:-1;;;;;241539:29:0;;;;:41;;:59;;241581:6;;241589:8;;241539:59;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;241539:59:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;241539:59:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;241539:59:0;;;;;;;;;241538:60;:142;;;-1:-1:-1;241611:29:0;;:69;;-1:-1:-1;;;241611:69:0;;-1:-1:-1;;;;;241611:29:0;;;;:51;;:69;;241663:6;;241671:8;;241611:69;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;241611:69:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;241611:69:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;241611:69:0;;;;;;;;;241516:270;;;;-1:-1:-1;;;241516:270:0;;;;;;;;;241817:28;;:58;;-1:-1:-1;;;241817:58:0;;-1:-1:-1;;;;;241817:28:0;;;;:40;;:58;;241858:6;;241866:8;;241817:58;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;241817:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;241817:58:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;241817:58:0;;;;;;;;;241809:113;;;;-1:-1:-1;;;241809:113:0;;;;;;;;;241954:28;;:68;;-1:-1:-1;;;241954:68:0;;-1:-1:-1;;;;;241954:28:0;;;;:50;;:68;;242005:6;;242013:8;;241954:68;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;241954:68:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;241954:68:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;241954:68:0;;;;;;;;;241953:69;241945:132;;;;-1:-1:-1;;;241945:132:0;;;;;;;;;242108:28;;:65;;-1:-1:-1;;;242108:65:0;;-1:-1:-1;;;;;242108:28:0;;;;:47;;:65;;242156:6;;242164:8;;242108:65;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;242108:65:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;242108:65:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;242108:65:0;;;;;;;;;242100:129;;;;-1:-1:-1;;;242100:129:0;;;;;;;;;242308:28;;:85;;-1:-1:-1;;;242308:85:0;;-1:-1:-1;;;;;242308:28:0;;;;:43;;:85;;242366:6;;242374:8;;242308:85;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;242308:85:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;242308:85:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;242308:85:0;;;;;;;;;242260:133;;;;;;;;;242252:199;;;;-1:-1:-1;;;242252:199:0;;;;;;;;;242492:13;;;;;;;;;-1:-1:-1;;;;;242492:13:0;-1:-1:-1;;;;;242492:37:0;;:39;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;242492:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;242492:39:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;242492:39:0;;;;;;;;;242484:104;;;;-1:-1:-1;;;242484:104:0;;;;;;;;;242607:13;;;:31;;;-1:-1:-1;;;242607:31:0;;;;-1:-1:-1;;;;;242607:13:0;;;;:29;;:31;;;;;;;;;;;;:13;:31;;;5:2:-1;;;;30:1;27;20:12;5:2;242607:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;242607:31:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;242607:31:0;;;;;;;;;242599:87;;;;-1:-1:-1;;;242599:87:0;;;;;;;;;242725:28;;:60;;-1:-1:-1;;;242725:60:0;;242709:13;;-1:-1:-1;;;;;242725:28:0;;:42;;:60;;242768:6;;242776:8;;242725:60;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;242725:60:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;242725:60:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;242725:60:0;;;;;;;;;242835:19;;:65;;-1:-1:-1;;;242835:65:0;;242709:76;;-1:-1:-1;;;;;;242835:19:0;;:47;;:65;;242883:6;;242891:8;;242835:65;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;242835:65:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;242835:65:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;242835:65:0;;;;;;;;;242826:5;:74;;242818:170;;;;-1:-1:-1;;;242818:170:0;;;;;;;;;243011:19;;:75;;-1:-1:-1;;;243011:75:0;;-1:-1:-1;;;;;243011:19:0;;;;:50;;:75;;243062:6;;243070:8;;243080:5;;243011:75;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;243011:75:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;243109:10:0;;243161:28;;:98;;-1:-1:-1;;;243161:98:0;;-1:-1:-1;;;;;243109:10:0;;;;-1:-1:-1;243109:16:0;;-1:-1:-1;243140:6:0;;243161:28;;;;:48;;:98;;243140:6;;243236:8;;243161:98;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;243161:98:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;243161:98:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;243161:98:0;;;;;;;;;243274:11;;243287;;;;243109:210;;-1:-1:-1;;;;;;243109:210:0;;;;;;;;;;;243274:11;243287;243300:8;;243109:210;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;243109:210:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;243342:28:0;;:64;;-1:-1:-1;;;243342:64:0;;-1:-1:-1;;;;;243342:28:0;;;;-1:-1:-1;243342:46:0;;-1:-1:-1;243342:64:0;;243389:6;;243397:8;;243342:64;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;243342:64:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;243342:64:0;;;;241373:2041;;;;:::o;3014:119::-;3117:8;;-1:-1:-1;;;;;3117:8:0;3103:10;:22;;3014:119::o;5:130:-1:-;72:20;;97:33;72:20;97:33;;;57:78;;;;;142:128;217:13;;235:30;217:13;235:30;;277:170;364:20;;389:53;364:20;389:53;;1441:158;1531:13;;1549:45;1531:13;1549:45;;1606:132;1683:13;;1701:32;1683:13;1701:32;;1746:442;;1848:3;1841:4;1833:6;1829:17;1825:27;1815:2;;1866:1;1863;1856:12;1815:2;1903:6;1890:20;1925:65;1940:49;1982:6;1940:49;;;1925:65;;;1916:74;;2010:6;2003:5;1996:21;2046:4;2038:6;2034:17;2079:4;2072:5;2068:16;2114:3;2105:6;2100:3;2096:16;2093:25;2090:2;;;2131:1;2128;2121:12;2090:2;2141:41;2175:6;2170:3;2165;2141:41;;;1808:380;;;;;;;;2196:130;2263:20;;2288:33;2263:20;2288:33;;2474:241;;2578:2;2566:9;2557:7;2553:23;2549:32;2546:2;;;2594:1;2591;2584:12;2546:2;2629:1;2646:53;2691:7;2671:9;2646:53;;;2636:63;2540:175;-1:-1;;;;2540:175;2722:723;;;;;2887:3;2875:9;2866:7;2862:23;2858:33;2855:2;;;2904:1;2901;2894:12;2855:2;2939:1;2956:53;3001:7;2981:9;2956:53;;;2946:63;;2918:97;3046:2;3064:53;3109:7;3100:6;3089:9;3085:22;3064:53;;;3054:63;;3025:98;3154:2;3172:53;3217:7;3208:6;3197:9;3193:22;3172:53;;;3162:63;;3133:98;3290:2;3279:9;3275:18;3262:32;-1:-1;;;;;3306:6;3303:30;3300:2;;;3346:1;3343;3336:12;3300:2;3366:63;3421:7;3412:6;3401:9;3397:22;3366:63;;;3356:73;;3241:194;2849:596;;;;;;;;3452:597;;;;3600:2;3588:9;3579:7;3575:23;3571:32;3568:2;;;3616:1;3613;3606:12;3568:2;3651:1;3668:53;3713:7;3693:9;3668:53;;;3658:63;;3630:97;3758:2;3776:53;3821:7;3812:6;3801:9;3797:22;3776:53;;;3766:63;;3737:98;3894:2;3883:9;3879:18;3866:32;-1:-1;;;;;3910:6;3907:30;3904:2;;;3950:1;3947;3940:12;3904:2;3970:63;4025:7;4016:6;4005:9;4001:22;3970:63;;;3960:73;;3845:194;3562:487;;;;;;4056:257;;4168:2;4156:9;4147:7;4143:23;4139:32;4136:2;;;4184:1;4181;4174:12;4136:2;4219:1;4236:61;4289:7;4269:9;4236:61;;4320:281;;4444:2;4432:9;4423:7;4419:23;4415:32;4412:2;;;4460:1;4457;4450:12;4412:2;4495:1;4512:73;4577:7;4557:9;4512:73;;6150:287;;6277:2;6265:9;6256:7;6252:23;6248:32;6245:2;;;6293:1;6290;6283:12;6245:2;6328:1;6345:76;6413:7;6393:9;6345:76;;6444:261;;6558:2;6546:9;6537:7;6533:23;6529:32;6526:2;;;6574:1;6571;6564:12;6526:2;6609:1;6626:63;6681:7;6661:9;6626:63;;6982:142;7073:45;7112:5;7073:45;;;7068:3;7061:58;7055:69;;;7131:103;7204:24;7222:5;7204:24;;7361:104;7438:21;7453:5;7438:21;;7472:182;7583:65;7642:5;7583:65;;8628:110;8709:23;8726:5;8709:23;;8745:347;;8857:39;8890:5;8857:39;;;8908:71;8972:6;8967:3;8908:71;;;8901:78;;8984:52;9029:6;9024:3;9017:4;9010:5;9006:16;8984:52;;;9057:29;9079:6;9057:29;;;9048:39;;;;8837:255;-1:-1;;;8837:255;9100:465;;9260:67;9324:2;9319:3;9260:67;;;9360:66;9340:87;;-1:-1;;;9456:2;9447:12;;9440:88;9556:2;9547:12;;9246:319;-1:-1;;9246:319;9574:465;;9734:67;9798:2;9793:3;9734:67;;;9834:66;9814:87;;-1:-1;;;9930:2;9921:12;;9914:88;10030:2;10021:12;;9720:319;-1:-1;;9720:319;10048:465;;10208:67;10272:2;10267:3;10208:67;;;10308:66;10288:87;;-1:-1;;;10404:2;10395:12;;10388:88;10504:2;10495:12;;10194:319;-1:-1;;10194:319;10522:566;;10682:67;10746:2;10741:3;10682:67;;;10782:66;10762:87;;10883:66;10878:2;10869:12;;10862:88;-1:-1;;;10979:2;10970:12;;10963:88;11079:2;11070:12;;10668:420;-1:-1;;10668:420;11097:465;;11257:67;11321:2;11316:3;11257:67;;;11357:66;11337:87;;-1:-1;;;11453:2;11444:12;;11437:88;11553:2;11544:12;;11243:319;-1:-1;;11243:319;11571:566;;11731:67;11795:2;11790:3;11731:67;;;11831:66;11811:87;;11932:66;11927:2;11918:12;;11911:88;-1:-1;;;12028:2;12019:12;;12012:88;12128:2;12119:12;;11717:420;-1:-1;;11717:420;12146:465;;12306:67;12370:2;12365:3;12306:67;;;12406:66;12386:87;;-1:-1;;;12502:2;12493:12;;12486:88;12602:2;12593:12;;12292:319;-1:-1;;12292:319;12620:465;;12780:67;12844:2;12839:3;12780:67;;;12880:66;12860:87;;-1:-1;;;12976:2;12967:12;;12960:88;13076:2;13067:12;;12766:319;-1:-1;;12766:319;13094:465;;13254:67;13318:2;13313:3;13254:67;;;13354:66;13334:87;;-1:-1;;;13450:2;13441:12;;13434:88;13550:2;13541:12;;13240:319;-1:-1;;13240:319;13642:472;13851:22;;13787:4;13778:14;;;13879:62;13782:3;13851:22;13879:62;;;13807:140;14018:4;14011:5;14007:16;14001:23;14030:63;14087:4;14082:3;14078:14;14064:12;14030:63;;14351:213;14469:2;14454:18;;14483:71;14458:9;14527:6;14483:71;;14571:229;14697:2;14682:18;;14711:79;14686:9;14763:6;14711:79;;14807:763;15065:3;15050:19;;15080:79;15054:9;15132:6;15080:79;;;15170:72;15238:2;15227:9;15223:18;15214:6;15170:72;;;15253;15321:2;15310:9;15306:18;15297:6;15253:72;;;15336;15404:2;15393:9;15389:18;15380:6;15336:72;;;15457:9;15451:4;15447:20;15441:3;15430:9;15426:19;15419:49;15482:78;15555:4;15546:6;15482:78;;;15474:86;15036:534;-1:-1;;;;;;;15036:534;15577:651;15807:3;15792:19;;15822:79;15796:9;15874:6;15822:79;;;15912:72;15980:2;15969:9;15965:18;15956:6;15912:72;;;15995;16063:2;16052:9;16048:18;16039:6;15995:72;;;16115:9;16109:4;16105:20;16100:2;16089:9;16085:18;16078:48;16140:78;16213:4;16204:6;16140:78;;;16132:86;15778:450;-1:-1;;;;;;15778:450;16235:324;16381:2;16366:18;;16395:71;16370:9;16439:6;16395:71;;;16477:72;16545:2;16534:9;16530:18;16521:6;16477:72;;;16352:207;;;;;;16566:743;16814:3;16799:19;;16829:71;16803:9;16873:6;16829:71;;;16911:70;16977:2;16966:9;16962:18;16953:6;16911:70;;17316:428;17514:2;17499:18;;17528:71;17503:9;17572:6;17528:71;;;17610:124;17730:2;17719:9;17715:18;17706:6;17610:124;;17751:540;17977:3;17962:19;;17992:71;17966:9;18036:6;17992:71;;;18074:124;18194:2;18183:9;18179:18;18170:6;18074:124;;;18209:72;18277:2;18266:9;18262:18;18253:6;18209:72;;18298:201;18410:2;18395:18;;18424:65;18399:9;18462:6;18424:65;;18506:269;18652:2;18637:18;;18666:99;18641:9;18738:6;18666:99;;18782:436;18984:2;18969:18;;18998:99;18973:9;19070:6;18998:99;;;19108:100;19204:2;19193:9;19189:18;19180:6;19108:100;;22886:407;23077:2;23091:47;;;23062:18;;23152:131;23062:18;23152:131;;23300:407;23491:2;23505:47;;;23476:18;;23566:131;23476:18;23566:131;;23714:407;23905:2;23919:47;;;23890:18;;23980:131;23890:18;23980:131;;24128:407;24319:2;24333:47;;;24304:18;;24394:131;24304:18;24394:131;;24542:407;24733:2;24747:47;;;24718:18;;24808:131;24718:18;24808:131;;24956:407;25147:2;25161:47;;;25132:18;;25222:131;25132:18;25222:131;;25370:407;25561:2;25575:47;;;25546:18;;25636:131;25546:18;25636:131;;25784:407;25975:2;25989:47;;;25960:18;;26050:131;25960:18;26050:131;;26198:407;26389:2;26403:47;;;26374:18;;26464:131;26374:18;26464:131;;26612:256;26674:2;26668:9;26700:17;;;-1:-1;;;;;26760:34;;26796:22;;;26757:62;26754:2;;;26832:1;26829;26822:12;26754:2;26848;26841:22;26652:216;;-1:-1;26652:216;26875:322;;-1:-1;;;;;27011:6;27008:30;27005:2;;;27051:1;27048;27041:12;27005:2;-1:-1;27182:4;27118;27095:17;;;;-1:-1;;27091:33;27172:15;;26942:255;27204:122;27292:12;;27263:63;27334:163;27437:19;;;27486:4;27477:14;;27430:67;27505:91;;27567:24;27585:5;27567:24;;27709:85;27775:13;27768:21;;27751:43;27801:119;;27883:32;27909:5;27883:32;;28568:71;28629:5;28612:27;28646:121;-1:-1;;;;;28708:54;;28691:76;28853:129;;28940:37;28971:5;28940:37;;31212:145;31293:6;31288:3;31283;31270:30;-1:-1;31349:1;31331:16;;31324:27;31263:94;31366:268;31431:1;31438:101;31452:6;31449:1;31446:13;31438:101;;;31519:11;;;31513:18;31500:11;;;31493:39;31474:2;31467:10;31438:101;;;31554:6;31551:1;31548:13;31545:2;;;-1:-1;;31619:1;31601:16;;31594:27;31415:219;31642:97;31730:2;31710:14;-1:-1;;31706:28;;31690:49;31747:117;31816:24;31834:5;31816:24;;;31809:5;31806:35;31796:2;;31855:1;31852;31845:12;31796:2;31790:74;;31871:111;31937:21;31952:5;31937:21;;31989:157;32078:44;32116:5;32078:44;;33075:106;33156:1;33149:5;33146:12;33136:2;;33172:1;33169;33162:12;33188:115;33256:23;33273:5;33256:23;
Swarm Source
bzzr://ae654329e250ad9bf2bd2066a912b24bfd9af0af1318b6b449270d0de657b61f
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.