Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 1,149 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Settle Payment | 20088763 | 23 days ago | IN | 0 ETH | 0.02072533 | ||||
Settle Payment | 20088480 | 23 days ago | IN | 0 ETH | 0.01219747 | ||||
Settle Payment | 20088049 | 23 days ago | IN | 0 ETH | 0.01131595 | ||||
Settle Payment | 20046084 | 29 days ago | IN | 0 ETH | 0.00147287 | ||||
Settle Payment | 20046070 | 29 days ago | IN | 0 ETH | 0.00144485 | ||||
Settle Payment | 19988500 | 37 days ago | IN | 0 ETH | 0.01028699 | ||||
Settle Payment | 15517473 | 665 days ago | IN | 0 ETH | 0.02048689 | ||||
Settle Payment | 15380549 | 687 days ago | IN | 0 ETH | 0.05656095 | ||||
Settle Payment | 15377741 | 687 days ago | IN | 0 ETH | 0.01700236 | ||||
Settle Payment | 15377696 | 687 days ago | IN | 0 ETH | 0.02065513 | ||||
Settle Payment | 15377686 | 687 days ago | IN | 0 ETH | 0.01790298 | ||||
Settle Payment | 15377658 | 687 days ago | IN | 0 ETH | 0.01465943 | ||||
Settle Payment | 15377656 | 687 days ago | IN | 0 ETH | 0.01353178 | ||||
Settle Payment | 15377553 | 687 days ago | IN | 0 ETH | 0.00676589 | ||||
Settle Payment | 15377537 | 687 days ago | IN | 0 ETH | 0.00676589 | ||||
Settle Payment | 15377497 | 687 days ago | IN | 0 ETH | 0.00902119 | ||||
Settle Payment | 15377453 | 687 days ago | IN | 0 ETH | 0.01316088 | ||||
Settle Payment | 15079125 | 734 days ago | IN | 0 ETH | 0.04421451 | ||||
Settle Payment | 15072254 | 735 days ago | IN | 0 ETH | 0.02237658 | ||||
Settle Payment | 15059973 | 737 days ago | IN | 0 ETH | 0.02237658 | ||||
Settle Payment | 15055266 | 737 days ago | IN | 0 ETH | 0.01049065 | ||||
Settle Payment | 15047368 | 739 days ago | IN | 0 ETH | 0.03412458 | ||||
Settle Payment | 15003048 | 747 days ago | IN | 0 ETH | 0.04421595 | ||||
Settle Payment | 14981463 | 751 days ago | IN | 0 ETH | 0.02683857 | ||||
Settle Payment | 14978562 | 751 days ago | IN | 0 ETH | 0.03192872 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
DriipSettlementByPayment
Compiler Version
v0.5.11+commit.c082d0b4
Optimization Enabled:
Yes with 0 runs
Other Settings:
default evmVersion
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]"); _; } } 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 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 PaymentTypesLib { enum PaymentPartyRole {Sender, Recipient} struct PaymentSenderParty { uint256 nonce; address wallet; NahmiiTypesLib.CurrentPreviousInt256 balances; NahmiiTypesLib.SingleFigureTotalOriginFigures fees; string data; } struct PaymentRecipientParty { uint256 nonce; address wallet; NahmiiTypesLib.CurrentPreviousInt256 balances; NahmiiTypesLib.TotalOriginFigures fees; } struct Operator { uint256 id; string data; } struct Payment { int256 amount; MonetaryTypesLib.Currency currency; PaymentSenderParty sender; PaymentRecipientParty recipient; NahmiiTypesLib.SingleTotalInt256 transfers; NahmiiTypesLib.WalletOperatorSeal seals; uint256 blockNumber; Operator operator; } function PAYMENT_KIND() public pure returns (string memory) { return "payment"; } } contract PaymentHasher is Ownable { constructor(address deployer) Ownable(deployer) public { } function hashPaymentAsWallet(PaymentTypesLib.Payment memory payment) public pure returns (bytes32) { bytes32 amountCurrencyHash = hashPaymentAmountCurrency(payment); bytes32 senderHash = hashPaymentSenderPartyAsWallet(payment.sender); bytes32 recipientHash = hashAddress(payment.recipient.wallet); return keccak256(abi.encodePacked(amountCurrencyHash, senderHash, recipientHash)); } function hashPaymentAsOperator(PaymentTypesLib.Payment memory payment) public pure returns (bytes32) { bytes32 walletSignatureHash = hashSignature(payment.seals.wallet.signature); bytes32 senderHash = hashPaymentSenderPartyAsOperator(payment.sender); bytes32 recipientHash = hashPaymentRecipientPartyAsOperator(payment.recipient); bytes32 transfersHash = hashSingleTotalInt256(payment.transfers); bytes32 operatorHash = hashString(payment.operator.data); return keccak256(abi.encodePacked( walletSignatureHash, senderHash, recipientHash, transfersHash, operatorHash )); } function hashPaymentAmountCurrency(PaymentTypesLib.Payment memory payment) public pure returns (bytes32) { return keccak256(abi.encodePacked( payment.amount, payment.currency.ct, payment.currency.id )); } function hashPaymentSenderPartyAsWallet( PaymentTypesLib.PaymentSenderParty memory paymentSenderParty) public pure returns (bytes32) { return keccak256(abi.encodePacked( paymentSenderParty.wallet, paymentSenderParty.data )); } function hashPaymentSenderPartyAsOperator( PaymentTypesLib.PaymentSenderParty memory paymentSenderParty) public pure returns (bytes32) { bytes32 rootHash = hashUint256(paymentSenderParty.nonce); bytes32 balancesHash = hashCurrentPreviousInt256(paymentSenderParty.balances); bytes32 singleFeeHash = hashFigure(paymentSenderParty.fees.single); bytes32 totalFeesHash = hashOriginFigures(paymentSenderParty.fees.total); return keccak256(abi.encodePacked( rootHash, balancesHash, singleFeeHash, totalFeesHash )); } function hashPaymentRecipientPartyAsOperator( PaymentTypesLib.PaymentRecipientParty memory paymentRecipientParty) public pure returns (bytes32) { bytes32 rootHash = hashUint256(paymentRecipientParty.nonce); bytes32 balancesHash = hashCurrentPreviousInt256(paymentRecipientParty.balances); bytes32 totalFeesHash = hashOriginFigures(paymentRecipientParty.fees.total); return keccak256(abi.encodePacked( rootHash, balancesHash, totalFeesHash )); } function hashCurrentPreviousInt256( NahmiiTypesLib.CurrentPreviousInt256 memory currentPreviousInt256) public pure returns (bytes32) { return keccak256(abi.encodePacked( currentPreviousInt256.current, currentPreviousInt256.previous )); } function hashSingleTotalInt256( NahmiiTypesLib.SingleTotalInt256 memory singleTotalInt256) public pure returns (bytes32) { return keccak256(abi.encodePacked( singleTotalInt256.single, singleTotalInt256.total )); } function hashFigure(MonetaryTypesLib.Figure memory figure) public pure returns (bytes32) { return keccak256(abi.encodePacked( figure.amount, figure.currency.ct, figure.currency.id )); } function hashOriginFigures(NahmiiTypesLib.OriginFigure[] memory originFigures) public pure returns (bytes32) { bytes32 hash; for (uint256 i = 0; i < originFigures.length; i++) { hash = keccak256(abi.encodePacked( hash, originFigures[i].originId, originFigures[i].figure.amount, originFigures[i].figure.currency.ct, originFigures[i].figure.currency.id ) ); } return hash; } function hashUint256(uint256 _uint256) public pure returns (bytes32) { return keccak256(abi.encodePacked(_uint256)); } function hashString(string memory _string) public pure returns (bytes32) { return keccak256(abi.encodePacked(_string)); } function hashAddress(address _address) public pure returns (bytes32) { return keccak256(abi.encodePacked(_address)); } function hashSignature(NahmiiTypesLib.Signature memory signature) public pure returns (bytes32) { return keccak256(abi.encodePacked( signature.v, signature.r, signature.s )); } } contract PaymentHashable is Ownable { PaymentHasher public paymentHasher; event SetPaymentHasherEvent(PaymentHasher oldPaymentHasher, PaymentHasher newPaymentHasher); function setPaymentHasher(PaymentHasher newPaymentHasher) public onlyDeployer notNullAddress(address(newPaymentHasher)) notSameAddresses(address(newPaymentHasher), address(paymentHasher)) { PaymentHasher oldPaymentHasher = paymentHasher; paymentHasher = newPaymentHasher; emit SetPaymentHasherEvent(oldPaymentHasher, newPaymentHasher); } modifier paymentHasherInitialized() { require(address(paymentHasher) != address(0), "Payment hasher not initialized [PaymentHashable.sol:52]"); _; } } contract SignerManager is Ownable { using SafeMathUintLib for uint256; mapping(address => uint256) public signerIndicesMap; address[] public signers; event RegisterSignerEvent(address signer); constructor(address deployer) Ownable(deployer) public { registerSigner(deployer); } function isSigner(address _address) public view returns (bool) { return 0 < signerIndicesMap[_address]; } function signersCount() public view returns (uint256) { return signers.length; } function signerIndex(address _address) public view returns (uint256) { require(isSigner(_address), "Address not signer [SignerManager.sol:71]"); return signerIndicesMap[_address] - 1; } function registerSigner(address newSigner) public onlyOperator notNullOrThisAddress(newSigner) { if (0 == signerIndicesMap[newSigner]) { signers.push(newSigner); signerIndicesMap[newSigner] = signers.length; emit RegisterSignerEvent(newSigner); } } function signersByIndices(uint256 low, uint256 up) public view returns (address[] memory) { require(0 < signers.length, "No signers found [SignerManager.sol:101]"); require(low <= up, "Bounds parameters mismatch [SignerManager.sol:102]"); up = up.clampMax(signers.length - 1); address[] memory _signers = new address[](up - low + 1); for (uint256 i = low; i <= up; i++) _signers[i - low] = signers[i]; return _signers; } } contract SignerManageable is Ownable { SignerManager public signerManager; event SetSignerManagerEvent(address oldSignerManager, address newSignerManager); constructor(address manager) public notNullAddress(manager) { signerManager = SignerManager(manager); } function setSignerManager(address newSignerManager) public onlyDeployer notNullOrThisAddress(newSignerManager) { if (newSignerManager != address(signerManager)) { address oldSignerManager = address(signerManager); signerManager = SignerManager(newSignerManager); emit SetSignerManagerEvent(oldSignerManager, newSignerManager); } } function ethrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public pure returns (address) { bytes memory prefix = "\x19Ethereum Signed Message:\n32"; bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, hash)); return ecrecover(prefixedHash, v, r, s); } function isSignedByRegisteredSigner(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public view returns (bool) { return signerManager.isSigner(ethrecover(hash, v, r, s)); } function isSignedBy(bytes32 hash, uint8 v, bytes32 r, bytes32 s, address signer) public pure returns (bool) { return signer == ethrecover(hash, v, r, s); } modifier signerManagerInitialized() { require(address(signerManager) != address(0), "Signer manager not initialized [SignerManageable.sol:105]"); _; } } contract Validator is Ownable, SignerManageable, Configurable, PaymentHashable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; constructor(address deployer, address signerManager) Ownable(deployer) SignerManageable(signerManager) public { } function isGenuineOperatorSignature(bytes32 hash, NahmiiTypesLib.Signature memory signature) public view returns (bool) { return isSignedByRegisteredSigner(hash, signature.v, signature.r, signature.s); } function isGenuineWalletSignature(bytes32 hash, NahmiiTypesLib.Signature memory signature, address wallet) public pure returns (bool) { return isSignedBy(hash, signature.v, signature.r, signature.s, wallet); } function isGenuinePaymentWalletHash(PaymentTypesLib.Payment memory payment) public view returns (bool) { return paymentHasher.hashPaymentAsWallet(payment) == payment.seals.wallet.hash; } function isGenuinePaymentOperatorHash(PaymentTypesLib.Payment memory payment) public view returns (bool) { return paymentHasher.hashPaymentAsOperator(payment) == payment.seals.operator.hash; } function isGenuinePaymentWalletSeal(PaymentTypesLib.Payment memory payment) public view returns (bool) { return isGenuinePaymentWalletHash(payment) && isGenuineWalletSignature(payment.seals.wallet.hash, payment.seals.wallet.signature, payment.sender.wallet); } function isGenuinePaymentOperatorSeal(PaymentTypesLib.Payment memory payment) public view returns (bool) { return isGenuinePaymentOperatorHash(payment) && isGenuineOperatorSignature(payment.seals.operator.hash, payment.seals.operator.signature); } function isGenuinePaymentSeals(PaymentTypesLib.Payment memory payment) public view returns (bool) { return isGenuinePaymentWalletSeal(payment) && isGenuinePaymentOperatorSeal(payment); } function isGenuinePaymentFeeOfFungible(PaymentTypesLib.Payment memory payment) public view returns (bool) { int256 feePartsPer = int256(ConstantsLib.PARTS_PER()); int256 feeAmount = payment.amount .mul( configuration.currencyPaymentFee( payment.blockNumber, payment.currency.ct, payment.currency.id, payment.amount ) ).div(feePartsPer); if (1 > feeAmount) feeAmount = 1; return (payment.sender.fees.single.amount == feeAmount); } function isGenuinePaymentFeeOfNonFungible(PaymentTypesLib.Payment memory payment) public view returns (bool) { (address feeCurrencyCt, uint256 feeCurrencyId) = configuration.feeCurrency( payment.blockNumber, payment.currency.ct, payment.currency.id ); return feeCurrencyCt == payment.sender.fees.single.currency.ct && feeCurrencyId == payment.sender.fees.single.currency.id; } function isGenuinePaymentSenderOfFungible(PaymentTypesLib.Payment memory payment) public view returns (bool) { return (payment.sender.wallet != payment.recipient.wallet) && (!signerManager.isSigner(payment.sender.wallet)) && (payment.sender.balances.current == payment.sender.balances.previous.sub(payment.transfers.single).sub(payment.sender.fees.single.amount)); } function isGenuinePaymentRecipientOfFungible(PaymentTypesLib.Payment memory payment) public pure returns (bool) { return (payment.sender.wallet != payment.recipient.wallet) && (payment.recipient.balances.current == payment.recipient.balances.previous.add(payment.transfers.single)); } function isGenuinePaymentSenderOfNonFungible(PaymentTypesLib.Payment memory payment) public view returns (bool) { return (payment.sender.wallet != payment.recipient.wallet) && (!signerManager.isSigner(payment.sender.wallet)); } function isGenuinePaymentRecipientOfNonFungible(PaymentTypesLib.Payment memory payment) public pure returns (bool) { return (payment.sender.wallet != payment.recipient.wallet); } function isSuccessivePaymentsPartyNonces( PaymentTypesLib.Payment memory firstPayment, PaymentTypesLib.PaymentPartyRole firstPaymentPartyRole, PaymentTypesLib.Payment memory lastPayment, PaymentTypesLib.PaymentPartyRole lastPaymentPartyRole ) public pure returns (bool) { uint256 firstNonce = (PaymentTypesLib.PaymentPartyRole.Sender == firstPaymentPartyRole ? firstPayment.sender.nonce : firstPayment.recipient.nonce); uint256 lastNonce = (PaymentTypesLib.PaymentPartyRole.Sender == lastPaymentPartyRole ? lastPayment.sender.nonce : lastPayment.recipient.nonce); return lastNonce == firstNonce.add(1); } function isGenuineSuccessivePaymentsBalances( PaymentTypesLib.Payment memory firstPayment, PaymentTypesLib.PaymentPartyRole firstPaymentPartyRole, PaymentTypesLib.Payment memory lastPayment, PaymentTypesLib.PaymentPartyRole lastPaymentPartyRole, int256 delta ) public pure returns (bool) { NahmiiTypesLib.CurrentPreviousInt256 memory firstCurrentPreviousBalances = (PaymentTypesLib.PaymentPartyRole.Sender == firstPaymentPartyRole ? firstPayment.sender.balances : firstPayment.recipient.balances); NahmiiTypesLib.CurrentPreviousInt256 memory lastCurrentPreviousBalances = (PaymentTypesLib.PaymentPartyRole.Sender == lastPaymentPartyRole ? lastPayment.sender.balances : lastPayment.recipient.balances); return lastCurrentPreviousBalances.previous == firstCurrentPreviousBalances.current.add(delta); } function isGenuineSuccessivePaymentsTotalFees( PaymentTypesLib.Payment memory firstPayment, PaymentTypesLib.Payment memory lastPayment ) public pure returns (bool) { MonetaryTypesLib.Figure memory firstTotalFee = getProtocolFigureByCurrency(firstPayment.sender.fees.total, lastPayment.sender.fees.single.currency); MonetaryTypesLib.Figure memory lastTotalFee = getProtocolFigureByCurrency(lastPayment.sender.fees.total, lastPayment.sender.fees.single.currency); return lastTotalFee.amount == firstTotalFee.amount.add(lastPayment.sender.fees.single.amount); } function isPaymentParty(PaymentTypesLib.Payment memory payment, address wallet) public pure returns (bool) { return wallet == payment.sender.wallet || wallet == payment.recipient.wallet; } function isPaymentSender(PaymentTypesLib.Payment memory payment, address wallet) public pure returns (bool) { return wallet == payment.sender.wallet; } function isPaymentRecipient(PaymentTypesLib.Payment memory payment, address wallet) public pure returns (bool) { return wallet == payment.recipient.wallet; } function isPaymentCurrency(PaymentTypesLib.Payment memory payment, MonetaryTypesLib.Currency memory currency) public pure returns (bool) { return currency.ct == payment.currency.ct && currency.id == payment.currency.id; } function isPaymentCurrencyNonFungible(PaymentTypesLib.Payment memory payment) public pure returns (bool) { return payment.currency.ct != payment.sender.fees.single.currency.ct || payment.currency.id != payment.sender.fees.single.currency.id; } function getProtocolFigureByCurrency(NahmiiTypesLib.OriginFigure[] memory originFigures, MonetaryTypesLib.Currency memory currency) private pure returns (MonetaryTypesLib.Figure memory) { for (uint256 i = 0; i < originFigures.length; i++) if (originFigures[i].figure.currency.ct == currency.ct && originFigures[i].figure.currency.id == currency.id && originFigures[i].originId == 0) return originFigures[i].figure; return MonetaryTypesLib.Figure(0, currency); } } library TradeTypesLib { enum CurrencyRole {Intended, Conjugate} enum LiquidityRole {Maker, Taker} enum Intention {Buy, Sell} enum TradePartyRole {Buyer, Seller} struct OrderPlacement { Intention intention; int256 amount; NahmiiTypesLib.IntendedConjugateCurrency currencies; int256 rate; NahmiiTypesLib.CurrentPreviousInt256 residuals; } struct Order { uint256 nonce; address wallet; OrderPlacement placement; NahmiiTypesLib.WalletOperatorSeal seals; uint256 blockNumber; uint256 operatorId; } struct TradeOrder { int256 amount; NahmiiTypesLib.WalletOperatorHashes hashes; NahmiiTypesLib.CurrentPreviousInt256 residuals; } struct TradeParty { uint256 nonce; address wallet; uint256 rollingVolume; LiquidityRole liquidityRole; TradeOrder order; NahmiiTypesLib.IntendedConjugateCurrentPreviousInt256 balances; NahmiiTypesLib.SingleFigureTotalOriginFigures fees; } struct Trade { uint256 nonce; int256 amount; NahmiiTypesLib.IntendedConjugateCurrency currencies; int256 rate; TradeParty buyer; TradeParty seller; NahmiiTypesLib.IntendedConjugateSingleTotalInt256 transfers; NahmiiTypesLib.Seal seal; uint256 blockNumber; uint256 operatorId; } function TRADE_KIND() public pure returns (string memory) { return "trade"; } function ORDER_KIND() public pure returns (string memory) { return "order"; } } contract Validatable is Ownable { Validator public validator; event SetValidatorEvent(Validator oldValidator, Validator newValidator); function setValidator(Validator newValidator) public onlyDeployer notNullAddress(address(newValidator)) notSameAddresses(address(newValidator), address(validator)) { Validator oldValidator = validator; validator = newValidator; emit SetValidatorEvent(oldValidator, newValidator); } modifier validatorInitialized() { require(address(validator) != address(0), "Validator not initialized [Validatable.sol:55]"); _; } modifier onlyOperatorSealedPayment(PaymentTypesLib.Payment memory payment) { require(validator.isGenuinePaymentOperatorSeal(payment), "Payment operator seal not genuine [Validatable.sol:60]"); _; } modifier onlySealedPayment(PaymentTypesLib.Payment memory payment) { require(validator.isGenuinePaymentSeals(payment), "Payment seals not genuine [Validatable.sol:65]"); _; } modifier onlyPaymentParty(PaymentTypesLib.Payment memory payment, address wallet) { require(validator.isPaymentParty(payment, wallet), "Wallet not payment party [Validatable.sol:70]"); _; } modifier onlyPaymentSender(PaymentTypesLib.Payment memory payment, address wallet) { require(validator.isPaymentSender(payment, wallet), "Wallet not payment sender [Validatable.sol:75]"); _; } } 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 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 FraudChallenge is Ownable, Servable { string constant public ADD_SEIZED_WALLET_ACTION = "add_seized_wallet"; string constant public ADD_DOUBLE_SPENDER_WALLET_ACTION = "add_double_spender_wallet"; string constant public ADD_FRAUDULENT_ORDER_ACTION = "add_fraudulent_order"; string constant public ADD_FRAUDULENT_TRADE_ACTION = "add_fraudulent_trade"; string constant public ADD_FRAUDULENT_PAYMENT_ACTION = "add_fraudulent_payment"; address[] public doubleSpenderWallets; mapping(address => bool) public doubleSpenderByWallet; bytes32[] public fraudulentOrderHashes; mapping(bytes32 => bool) public fraudulentByOrderHash; bytes32[] public fraudulentTradeHashes; mapping(bytes32 => bool) public fraudulentByTradeHash; bytes32[] public fraudulentPaymentHashes; mapping(bytes32 => bool) public fraudulentByPaymentHash; event AddDoubleSpenderWalletEvent(address wallet); event AddFraudulentOrderHashEvent(bytes32 hash); event AddFraudulentTradeHashEvent(bytes32 hash); event AddFraudulentPaymentHashEvent(bytes32 hash); constructor(address deployer) Ownable(deployer) public { } function isDoubleSpenderWallet(address wallet) public view returns (bool) { return doubleSpenderByWallet[wallet]; } function doubleSpenderWalletsCount() public view returns (uint256) { return doubleSpenderWallets.length; } function addDoubleSpenderWallet(address wallet) public onlyEnabledServiceAction(ADD_DOUBLE_SPENDER_WALLET_ACTION) { if (!doubleSpenderByWallet[wallet]) { doubleSpenderWallets.push(wallet); doubleSpenderByWallet[wallet] = true; emit AddDoubleSpenderWalletEvent(wallet); } } function fraudulentOrderHashesCount() public view returns (uint256) { return fraudulentOrderHashes.length; } function isFraudulentOrderHash(bytes32 hash) public view returns (bool) { return fraudulentByOrderHash[hash]; } function addFraudulentOrderHash(bytes32 hash) public onlyEnabledServiceAction(ADD_FRAUDULENT_ORDER_ACTION) { if (!fraudulentByOrderHash[hash]) { fraudulentByOrderHash[hash] = true; fraudulentOrderHashes.push(hash); emit AddFraudulentOrderHashEvent(hash); } } function fraudulentTradeHashesCount() public view returns (uint256) { return fraudulentTradeHashes.length; } function isFraudulentTradeHash(bytes32 hash) public view returns (bool) { return fraudulentByTradeHash[hash]; } function addFraudulentTradeHash(bytes32 hash) public onlyEnabledServiceAction(ADD_FRAUDULENT_TRADE_ACTION) { if (!fraudulentByTradeHash[hash]) { fraudulentByTradeHash[hash] = true; fraudulentTradeHashes.push(hash); emit AddFraudulentTradeHashEvent(hash); } } function fraudulentPaymentHashesCount() public view returns (uint256) { return fraudulentPaymentHashes.length; } function isFraudulentPaymentHash(bytes32 hash) public view returns (bool) { return fraudulentByPaymentHash[hash]; } function addFraudulentPaymentHash(bytes32 hash) public onlyEnabledServiceAction(ADD_FRAUDULENT_PAYMENT_ACTION) { if (!fraudulentByPaymentHash[hash]) { fraudulentByPaymentHash[hash] = true; fraudulentPaymentHashes.push(hash); emit AddFraudulentPaymentHashEvent(hash); } } } contract FraudChallengable is Ownable { FraudChallenge public fraudChallenge; event SetFraudChallengeEvent(FraudChallenge oldFraudChallenge, FraudChallenge newFraudChallenge); function setFraudChallenge(FraudChallenge newFraudChallenge) public onlyDeployer notNullAddress(address(newFraudChallenge)) notSameAddresses(address(newFraudChallenge), address(fraudChallenge)) { FraudChallenge oldFraudChallenge = fraudChallenge; fraudChallenge = newFraudChallenge; emit SetFraudChallengeEvent(oldFraudChallenge, newFraudChallenge); } modifier fraudChallengeInitialized() { require(address(fraudChallenge) != address(0), "Fraud challenge not initialized [FraudChallengable.sol:52]"); _; } } contract PartnerBenefactor is Ownable, Benefactor { constructor(address deployer) Ownable(deployer) Benefactor() public { } } contract PartnerBenefactorable is Ownable { PartnerBenefactor public partnerBenefactor; event SetPartnerBenefactorEvent(PartnerBenefactor oldPartnerBenefactor, PartnerBenefactor newPartnerBenefactor); function setPartnerBenefactor(PartnerBenefactor newPartnerBenefactor) public onlyDeployer notNullAddress(address(newPartnerBenefactor)) notSameAddresses(address(newPartnerBenefactor), address(partnerBenefactor)) { PartnerBenefactor oldPartnerBenefactor = partnerBenefactor; partnerBenefactor = newPartnerBenefactor; emit SetPartnerBenefactorEvent(oldPartnerBenefactor, newPartnerBenefactor); } modifier partnerBenefactorInitialized() { require(address(partnerBenefactor) != address(0), "Partner benefactor not initialized [PartnerBenefactorable.sol:52]"); _; } } 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 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 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--; } } library Strings { function concat(string memory _base, string memory _value) internal pure returns (string memory) { bytes memory _baseBytes = bytes(_base); bytes memory _valueBytes = bytes(_value); assert(_valueBytes.length > 0); string memory _tmpValue = new string(_baseBytes.length + _valueBytes.length); bytes memory _newValue = bytes(_tmpValue); uint i; uint j; for (i = 0; i < _baseBytes.length; i++) { _newValue[j++] = _baseBytes[i]; } for (i = 0; i < _valueBytes.length; i++) { _newValue[j++] = _valueBytes[i]; } return string(_newValue); } function indexOf(string memory _base, string memory _value) internal pure returns (int) { return _indexOf(_base, _value, 0); } function _indexOf(string memory _base, string memory _value, uint _offset) internal pure returns (int) { bytes memory _baseBytes = bytes(_base); bytes memory _valueBytes = bytes(_value); assert(_valueBytes.length == 1); for (uint i = _offset; i < _baseBytes.length; i++) { if (_baseBytes[i] == _valueBytes[0]) { return int(i); } } return -1; } function length(string memory _base) internal pure returns (uint) { bytes memory _baseBytes = bytes(_base); return _baseBytes.length; } function substring(string memory _base, int _length) internal pure returns (string memory) { return _substring(_base, _length, 0); } function _substring(string memory _base, int _length, int _offset) internal pure returns (string memory) { bytes memory _baseBytes = bytes(_base); assert(uint(_offset + _length) <= _baseBytes.length); string memory _tmp = new string(uint(_length)); bytes memory _tmpBytes = bytes(_tmp); uint j = 0; for (uint i = uint(_offset); i < uint(_offset + _length); i++) { _tmpBytes[j++] = _baseBytes[i]; } return string(_tmpBytes); } function split(string memory _base, string memory _value) internal pure returns (string[] memory splitArr) { bytes memory _baseBytes = bytes(_base); uint _offset = 0; uint _splitsCount = 1; while (_offset < _baseBytes.length - 1) { int _limit = _indexOf(_base, _value, _offset); if (_limit == -1) break; else { _splitsCount++; _offset = uint(_limit) + 1; } } splitArr = new string[](_splitsCount); _offset = 0; _splitsCount = 0; while (_offset < _baseBytes.length - 1) { int _limit = _indexOf(_base, _value, _offset); if (_limit == - 1) { _limit = int(_baseBytes.length); } string memory _tmp = new string(uint(_limit) - _offset); bytes memory _tmpBytes = bytes(_tmp); uint j = 0; for (uint i = _offset; i < uint(_limit); i++) { _tmpBytes[j++] = _baseBytes[i]; } _offset = uint(_limit) + 1; splitArr[_splitsCount++] = string(_tmpBytes); } return splitArr; } function compareTo(string memory _base, string memory _value) internal pure returns (bool) { bytes memory _baseBytes = bytes(_base); bytes memory _valueBytes = bytes(_value); if (_baseBytes.length != _valueBytes.length) { return false; } for (uint i = 0; i < _baseBytes.length; i++) { if (_baseBytes[i] != _valueBytes[i]) { return false; } } return true; } function compareToIgnoreCase(string memory _base, string memory _value) internal pure returns (bool) { bytes memory _baseBytes = bytes(_base); bytes memory _valueBytes = bytes(_value); if (_baseBytes.length != _valueBytes.length) { return false; } for (uint i = 0; i < _baseBytes.length; i++) { if (_baseBytes[i] != _valueBytes[i] && _upper(_baseBytes[i]) != _upper(_valueBytes[i])) { return false; } } return true; } function upper(string memory _base) internal pure returns (string memory) { bytes memory _baseBytes = bytes(_base); for (uint i = 0; i < _baseBytes.length; i++) { _baseBytes[i] = _upper(_baseBytes[i]); } return string(_baseBytes); } function lower(string memory _base) internal pure returns (string memory) { bytes memory _baseBytes = bytes(_base); for (uint i = 0; i < _baseBytes.length; i++) { _baseBytes[i] = _lower(_baseBytes[i]); } return string(_baseBytes); } function _upper(bytes1 _b1) private pure returns (bytes1) { if (_b1 >= 0x61 && _b1 <= 0x7A) { return bytes1(uint8(_b1) - 32); } return _b1; } function _lower(bytes1 _b1) private pure returns (bytes1) { if (_b1 >= 0x41 && _b1 <= 0x5A) { return bytes1(uint8(_b1) + 32); } return _b1; } } contract PartnerFund is Ownable, Beneficiary, TransferControllerManageable { using FungibleBalanceLib for FungibleBalanceLib.Balance; using TxHistoryLib for TxHistoryLib.TxHistory; using SafeMathIntLib for int256; using Strings for string; struct Partner { bytes32 nameHash; uint256 fee; address wallet; uint256 index; bool operatorCanUpdate; bool partnerCanUpdate; FungibleBalanceLib.Balance active; FungibleBalanceLib.Balance staged; TxHistoryLib.TxHistory txHistory; FullBalanceHistory[] fullBalanceHistory; } struct FullBalanceHistory { uint256 listIndex; int256 balance; uint256 blockNumber; } Partner[] private partners; mapping(bytes32 => uint256) private _indexByNameHash; mapping(address => uint256) private _indexByWallet; event ReceiveEvent(address from, int256 amount, address currencyCt, uint256 currencyId); event RegisterPartnerByNameEvent(string name, uint256 fee, address wallet); event RegisterPartnerByNameHashEvent(bytes32 nameHash, uint256 fee, address wallet); event SetFeeByIndexEvent(uint256 index, uint256 oldFee, uint256 newFee); event SetFeeByNameEvent(string name, uint256 oldFee, uint256 newFee); event SetFeeByNameHashEvent(bytes32 nameHash, uint256 oldFee, uint256 newFee); event SetFeeByWalletEvent(address wallet, uint256 oldFee, uint256 newFee); event SetPartnerWalletByIndexEvent(uint256 index, address oldWallet, address newWallet); event SetPartnerWalletByNameEvent(string name, address oldWallet, address newWallet); event SetPartnerWalletByNameHashEvent(bytes32 nameHash, address oldWallet, address newWallet); event SetPartnerWalletByWalletEvent(address oldWallet, address newWallet); event StageEvent(address from, int256 amount, address currencyCt, uint256 currencyId); event WithdrawEvent(address to, int256 amount, address currencyCt, uint256 currencyId); constructor(address deployer) Ownable(deployer) public { } function() external payable { _receiveEthersTo( indexByWallet(msg.sender) - 1, SafeMathIntLib.toNonZeroInt256(msg.value) ); } function receiveEthersTo(address tag, string memory) public payable { _receiveEthersTo( uint256(tag) - 1, SafeMathIntLib.toNonZeroInt256(msg.value) ); } function receiveTokens(string memory, int256 amount, address currencyCt, uint256 currencyId, string memory standard) public { _receiveTokensTo( indexByWallet(msg.sender) - 1, amount, currencyCt, currencyId, standard ); } function receiveTokensTo(address tag, string memory, int256 amount, address currencyCt, uint256 currencyId, string memory standard) public { _receiveTokensTo( uint256(tag) - 1, amount, currencyCt, currencyId, standard ); } function hashName(string memory name) public pure returns (bytes32) { return keccak256(abi.encodePacked(name.upper())); } function depositByIndices(uint256 partnerIndex, uint256 depositIndex) public view returns (int256 balance, uint256 blockNumber, address currencyCt, uint256 currencyId) { require(0 < partnerIndex && partnerIndex <= partners.length, "Some error message when require fails [PartnerFund.sol:160]"); return _depositByIndices(partnerIndex - 1, depositIndex); } function depositByName(string memory name, uint depositIndex) public view returns (int256 balance, uint256 blockNumber, address currencyCt, uint256 currencyId) { return _depositByIndices(indexByName(name) - 1, depositIndex); } function depositByNameHash(bytes32 nameHash, uint depositIndex) public view returns (int256 balance, uint256 blockNumber, address currencyCt, uint256 currencyId) { return _depositByIndices(indexByNameHash(nameHash) - 1, depositIndex); } function depositByWallet(address wallet, uint depositIndex) public view returns (int256 balance, uint256 blockNumber, address currencyCt, uint256 currencyId) { return _depositByIndices(indexByWallet(wallet) - 1, depositIndex); } function depositsCountByIndex(uint256 index) public view returns (uint256) { require(0 < index && index <= partners.length, "Some error message when require fails [PartnerFund.sol:213]"); return _depositsCountByIndex(index - 1); } function depositsCountByName(string memory name) public view returns (uint256) { return _depositsCountByIndex(indexByName(name) - 1); } function depositsCountByNameHash(bytes32 nameHash) public view returns (uint256) { return _depositsCountByIndex(indexByNameHash(nameHash) - 1); } function depositsCountByWallet(address wallet) public view returns (uint256) { return _depositsCountByIndex(indexByWallet(wallet) - 1); } function activeBalanceByIndex(uint256 index, address currencyCt, uint256 currencyId) public view returns (int256) { require(0 < index && index <= partners.length, "Some error message when require fails [PartnerFund.sol:265]"); return _activeBalanceByIndex(index - 1, currencyCt, currencyId); } function activeBalanceByName(string memory name, address currencyCt, uint256 currencyId) public view returns (int256) { return _activeBalanceByIndex(indexByName(name) - 1, currencyCt, currencyId); } function activeBalanceByNameHash(bytes32 nameHash, address currencyCt, uint256 currencyId) public view returns (int256) { return _activeBalanceByIndex(indexByNameHash(nameHash) - 1, currencyCt, currencyId); } function activeBalanceByWallet(address wallet, address currencyCt, uint256 currencyId) public view returns (int256) { return _activeBalanceByIndex(indexByWallet(wallet) - 1, currencyCt, currencyId); } function stagedBalanceByIndex(uint256 index, address currencyCt, uint256 currencyId) public view returns (int256) { require(0 < index && index <= partners.length, "Some error message when require fails [PartnerFund.sol:323]"); return _stagedBalanceByIndex(index - 1, currencyCt, currencyId); } function stagedBalanceByName(string memory name, address currencyCt, uint256 currencyId) public view returns (int256) { return _stagedBalanceByIndex(indexByName(name) - 1, currencyCt, currencyId); } function stagedBalanceByNameHash(bytes32 nameHash, address currencyCt, uint256 currencyId) public view returns (int256) { return _stagedBalanceByIndex(indexByNameHash(nameHash) - 1, currencyCt, currencyId); } function stagedBalanceByWallet(address wallet, address currencyCt, uint256 currencyId) public view returns (int256) { return _stagedBalanceByIndex(indexByWallet(wallet) - 1, currencyCt, currencyId); } function partnersCount() public view returns (uint256) { return partners.length; } function registerByName(string memory name, uint256 fee, address wallet, bool partnerCanUpdate, bool operatorCanUpdate) public onlyOperator { require(bytes(name).length > 0, "Some error message when require fails [PartnerFund.sol:392]"); bytes32 nameHash = hashName(name); _registerPartnerByNameHash(nameHash, fee, wallet, partnerCanUpdate, operatorCanUpdate); emit RegisterPartnerByNameEvent(name, fee, wallet); } function registerByNameHash(bytes32 nameHash, uint256 fee, address wallet, bool partnerCanUpdate, bool operatorCanUpdate) public onlyOperator { _registerPartnerByNameHash(nameHash, fee, wallet, partnerCanUpdate, operatorCanUpdate); emit RegisterPartnerByNameHashEvent(nameHash, fee, wallet); } function indexByNameHash(bytes32 nameHash) public view returns (uint256) { uint256 index = _indexByNameHash[nameHash]; require(0 < index, "Some error message when require fails [PartnerFund.sol:431]"); return index; } function indexByName(string memory name) public view returns (uint256) { return indexByNameHash(hashName(name)); } function indexByWallet(address wallet) public view returns (uint256) { uint256 index = _indexByWallet[wallet]; require(0 < index, "Some error message when require fails [PartnerFund.sol:455]"); return index; } function isRegisteredByName(string memory name) public view returns (bool) { return (0 < _indexByNameHash[hashName(name)]); } function isRegisteredByNameHash(bytes32 nameHash) public view returns (bool) { return (0 < _indexByNameHash[nameHash]); } function isRegisteredByWallet(address wallet) public view returns (bool) { return (0 < _indexByWallet[wallet]); } function feeByIndex(uint256 index) public view returns (uint256) { require(0 < index && index <= partners.length, "Some error message when require fails [PartnerFund.sol:501]"); return _partnerFeeByIndex(index - 1); } function feeByName(string memory name) public view returns (uint256) { return _partnerFeeByIndex(indexByName(name) - 1); } function feeByNameHash(bytes32 nameHash) public view returns (uint256) { return _partnerFeeByIndex(indexByNameHash(nameHash) - 1); } function feeByWallet(address wallet) public view returns (uint256) { return _partnerFeeByIndex(indexByWallet(wallet) - 1); } function setFeeByIndex(uint256 index, uint256 newFee) public { require(0 < index && index <= partners.length, "Some error message when require fails [PartnerFund.sol:549]"); uint256 oldFee = _setPartnerFeeByIndex(index - 1, newFee); emit SetFeeByIndexEvent(index, oldFee, newFee); } function setFeeByName(string memory name, uint256 newFee) public { uint256 oldFee = _setPartnerFeeByIndex(indexByName(name) - 1, newFee); emit SetFeeByNameEvent(name, oldFee, newFee); } function setFeeByNameHash(bytes32 nameHash, uint256 newFee) public { uint256 oldFee = _setPartnerFeeByIndex(indexByNameHash(nameHash) - 1, newFee); emit SetFeeByNameHashEvent(nameHash, oldFee, newFee); } function setFeeByWallet(address wallet, uint256 newFee) public { uint256 oldFee = _setPartnerFeeByIndex(indexByWallet(wallet) - 1, newFee); emit SetFeeByWalletEvent(wallet, oldFee, newFee); } function walletByIndex(uint256 index) public view returns (address) { require(0 < index && index <= partners.length, "Some error message when require fails [PartnerFund.sol:606]"); return partners[index - 1].wallet; } function walletByName(string memory name) public view returns (address) { return partners[indexByName(name) - 1].wallet; } function walletByNameHash(bytes32 nameHash) public view returns (address) { return partners[indexByNameHash(nameHash) - 1].wallet; } function setWalletByIndex(uint256 index, address newWallet) public { require(0 < index && index <= partners.length, "Some error message when require fails [PartnerFund.sol:642]"); address oldWallet = _setPartnerWalletByIndex(index - 1, newWallet); emit SetPartnerWalletByIndexEvent(index, oldWallet, newWallet); } function setWalletByName(string memory name, address newWallet) public { address oldWallet = _setPartnerWalletByIndex(indexByName(name) - 1, newWallet); emit SetPartnerWalletByNameEvent(name, oldWallet, newWallet); } function setWalletByNameHash(bytes32 nameHash, address newWallet) public { address oldWallet = _setPartnerWalletByIndex(indexByNameHash(nameHash) - 1, newWallet); emit SetPartnerWalletByNameHashEvent(nameHash, oldWallet, newWallet); } function setWalletByWallet(address oldWallet, address newWallet) public { _setPartnerWalletByIndex(indexByWallet(oldWallet) - 1, newWallet); emit SetPartnerWalletByWalletEvent(oldWallet, newWallet); } function stage(int256 amount, address currencyCt, uint256 currencyId) public { uint256 index = indexByWallet(msg.sender); require(amount.isPositiveInt256(), "Some error message when require fails [PartnerFund.sol:701]"); amount = amount.clampMax(partners[index - 1].active.get(currencyCt, currencyId)); partners[index - 1].active.sub(amount, currencyCt, currencyId); partners[index - 1].staged.add(amount, currencyCt, currencyId); partners[index - 1].txHistory.addDeposit(amount, currencyCt, currencyId); partners[index - 1].fullBalanceHistory.push( FullBalanceHistory( partners[index - 1].txHistory.depositsCount() - 1, partners[index - 1].active.get(currencyCt, currencyId), block.number ) ); emit StageEvent(msg.sender, amount, currencyCt, currencyId); } function withdraw(int256 amount, address currencyCt, uint256 currencyId, string memory standard) public { uint256 index = indexByWallet(msg.sender); require(amount.isPositiveInt256(), "Some error message when require fails [PartnerFund.sol:736]"); amount = amount.clampMax(partners[index - 1].staged.get(currencyCt, currencyId)); partners[index - 1].staged.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, "Some error message when require fails [PartnerFund.sol:754]"); } emit WithdrawEvent(msg.sender, amount, currencyCt, currencyId); } function _receiveEthersTo(uint256 index, int256 amount) private { require(index < partners.length, "Some error message when require fails [PartnerFund.sol:769]"); partners[index].active.add(amount, address(0), 0); partners[index].txHistory.addDeposit(amount, address(0), 0); partners[index].fullBalanceHistory.push( FullBalanceHistory( partners[index].txHistory.depositsCount() - 1, partners[index].active.get(address(0), 0), block.number ) ); emit ReceiveEvent(msg.sender, amount, address(0), 0); } function _receiveTokensTo(uint256 index, int256 amount, address currencyCt, uint256 currencyId, string memory standard) private { require(index < partners.length, "Some error message when require fails [PartnerFund.sol:794]"); require(amount.isNonZeroPositiveInt256(), "Some error message when require fails [PartnerFund.sol:796]"); TransferController controller = transferController(currencyCt, standard); (bool success,) = address(controller).delegatecall( abi.encodeWithSelector( controller.getReceiveSignature(), msg.sender, this, uint256(amount), currencyCt, currencyId ) ); require(success, "Some error message when require fails [PartnerFund.sol:805]"); partners[index].active.add(amount, currencyCt, currencyId); partners[index].txHistory.addDeposit(amount, currencyCt, currencyId); partners[index].fullBalanceHistory.push( FullBalanceHistory( partners[index].txHistory.depositsCount() - 1, partners[index].active.get(currencyCt, currencyId), block.number ) ); emit ReceiveEvent(msg.sender, amount, currencyCt, currencyId); } function _depositByIndices(uint256 partnerIndex, uint256 depositIndex) private view returns (int256 balance, uint256 blockNumber, address currencyCt, uint256 currencyId) { require(depositIndex < partners[partnerIndex].fullBalanceHistory.length, "Some error message when require fails [PartnerFund.sol:830]"); FullBalanceHistory storage entry = partners[partnerIndex].fullBalanceHistory[depositIndex]; (,, currencyCt, currencyId) = partners[partnerIndex].txHistory.deposit(entry.listIndex); balance = entry.balance; blockNumber = entry.blockNumber; } function _depositsCountByIndex(uint256 index) private view returns (uint256) { return partners[index].fullBalanceHistory.length; } function _activeBalanceByIndex(uint256 index, address currencyCt, uint256 currencyId) private view returns (int256) { return partners[index].active.get(currencyCt, currencyId); } function _stagedBalanceByIndex(uint256 index, address currencyCt, uint256 currencyId) private view returns (int256) { return partners[index].staged.get(currencyCt, currencyId); } function _registerPartnerByNameHash(bytes32 nameHash, uint256 fee, address wallet, bool partnerCanUpdate, bool operatorCanUpdate) private { require(0 == _indexByNameHash[nameHash], "Some error message when require fails [PartnerFund.sol:871]"); require(partnerCanUpdate || operatorCanUpdate, "Some error message when require fails [PartnerFund.sol:874]"); partners.length++; uint256 index = partners.length; partners[index - 1].nameHash = nameHash; partners[index - 1].fee = fee; partners[index - 1].wallet = wallet; partners[index - 1].partnerCanUpdate = partnerCanUpdate; partners[index - 1].operatorCanUpdate = operatorCanUpdate; partners[index - 1].index = index; _indexByNameHash[nameHash] = index; _indexByWallet[wallet] = index; } function _setPartnerFeeByIndex(uint256 index, uint256 fee) private returns (uint256) { uint256 oldFee = partners[index].fee; if (isOperator()) require(partners[index].operatorCanUpdate, "Some error message when require fails [PartnerFund.sol:906]"); else { require(msg.sender == partners[index].wallet, "Some error message when require fails [PartnerFund.sol:910]"); require(partners[index].partnerCanUpdate, "Some error message when require fails [PartnerFund.sol:913]"); } partners[index].fee = fee; return oldFee; } function _setPartnerWalletByIndex(uint256 index, address newWallet) private returns (address) { address oldWallet = partners[index].wallet; if (oldWallet == address(0)) require(isOperator(), "Some error message when require fails [PartnerFund.sol:931]"); else if (isOperator()) require(partners[index].operatorCanUpdate, "Some error message when require fails [PartnerFund.sol:935]"); else { require(msg.sender == oldWallet, "Some error message when require fails [PartnerFund.sol:939]"); require(partners[index].partnerCanUpdate, "Some error message when require fails [PartnerFund.sol:942]"); require(partners[index].operatorCanUpdate || newWallet != address(0), "Some error message when require fails [PartnerFund.sol:945]"); } partners[index].wallet = newWallet; if (oldWallet != address(0)) _indexByWallet[oldWallet] = 0; if (newWallet != address(0)) _indexByWallet[newWallet] = index; return oldWallet; } function _partnerFeeByIndex(uint256 index) private view returns (uint256) { return partners[index].fee; } } library DriipSettlementTypesLib { enum SettlementRole {Origin, Target} struct SettlementParty { uint256 nonce; address wallet; uint256 doneBlockNumber; } struct Settlement { string settledKind; bytes32 settledHash; SettlementParty origin; SettlementParty target; } } contract DriipSettlementState is Ownable, Servable, CommunityVotable, Upgradable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; string constant public INIT_SETTLEMENT_ACTION = "init_settlement"; string constant public COMPLETE_SETTLEMENT_ACTION = "complete_settlement"; string constant public SET_MAX_NONCE_ACTION = "set_max_nonce"; string constant public ADD_SETTLED_AMOUNT_ACTION = "add_settled_amount"; string constant public SET_TOTAL_FEE_ACTION = "set_total_fee"; uint256 public maxDriipNonce; DriipSettlementTypesLib.Settlement[] public settlements; mapping(address => uint256[]) public walletSettlementIndices; mapping(address => mapping(uint256 => uint256)) public walletNonceSettlementIndex; mapping(address => mapping(address => mapping(uint256 => uint256))) public walletCurrencyMaxNonce; mapping(address => mapping(address => mapping(uint256 => mapping(uint256 => int256)))) public walletCurrencyBlockNumberSettledAmount; mapping(address => mapping(address => mapping(uint256 => uint256[]))) public walletCurrencySettledBlockNumbers; mapping(address => mapping(address => mapping(address => mapping(address => mapping(uint256 => MonetaryTypesLib.NoncedAmount))))) public totalFeesMap; event InitSettlementEvent(DriipSettlementTypesLib.Settlement settlement); event CompleteSettlementPartyEvent(address wallet, uint256 nonce, DriipSettlementTypesLib.SettlementRole settlementRole, uint256 doneBlockNumber); event SetMaxDriipNonceEvent(uint256 maxDriipNonce); event UpdateMaxDriipNonceFromCommunityVoteEvent(uint256 maxDriipNonce); event SetMaxNonceByWalletAndCurrencyEvent(address wallet, MonetaryTypesLib.Currency currency, uint256 maxNonce); event AddSettledAmountEvent(address wallet, int256 amount, MonetaryTypesLib.Currency currency, uint256 blockNumber); event SetTotalFeeEvent(address wallet, Beneficiary beneficiary, address destination, MonetaryTypesLib.Currency currency, MonetaryTypesLib.NoncedAmount totalFee); event UpgradeSettlementEvent(DriipSettlementTypesLib.Settlement settlement); event UpgradeSettledAmountEvent(address wallet, int256 amount, MonetaryTypesLib.Currency currency, uint256 blockNumber); constructor(address deployer) Ownable(deployer) public { } function settlementsCount() public view returns (uint256) { return settlements.length; } function settlementsCountByWallet(address wallet) public view returns (uint256) { return walletSettlementIndices[wallet].length; } function settlementByWalletAndIndex(address wallet, uint256 index) public view returns (DriipSettlementTypesLib.Settlement memory) { require(walletSettlementIndices[wallet].length > index, "Index out of bounds [DriipSettlementState.sol:114]"); return settlements[walletSettlementIndices[wallet][index] - 1]; } function settlementByWalletAndNonce(address wallet, uint256 nonce) public view returns (DriipSettlementTypesLib.Settlement memory) { require(0 != walletNonceSettlementIndex[wallet][nonce], "No settlement found for wallet and nonce [DriipSettlementState.sol:127]"); return settlements[walletNonceSettlementIndex[wallet][nonce] - 1]; } function initSettlement(string memory settledKind, bytes32 settledHash, address originWallet, uint256 originNonce, address targetWallet, uint256 targetNonce) public onlyEnabledServiceAction(INIT_SETTLEMENT_ACTION) { if ( 0 == walletNonceSettlementIndex[originWallet][originNonce] && 0 == walletNonceSettlementIndex[targetWallet][targetNonce] ) { settlements.length++; uint256 index = settlements.length - 1; settlements[index].settledKind = settledKind; settlements[index].settledHash = settledHash; settlements[index].origin.nonce = originNonce; settlements[index].origin.wallet = originWallet; settlements[index].target.nonce = targetNonce; settlements[index].target.wallet = targetWallet; emit InitSettlementEvent(settlements[index]); index++; walletSettlementIndices[originWallet].push(index); walletSettlementIndices[targetWallet].push(index); walletNonceSettlementIndex[originWallet][originNonce] = index; walletNonceSettlementIndex[targetWallet][targetNonce] = index; } } function completeSettlement(address wallet, uint256 nonce, DriipSettlementTypesLib.SettlementRole settlementRole, bool done) public onlyEnabledServiceAction(COMPLETE_SETTLEMENT_ACTION) { uint256 index = walletNonceSettlementIndex[wallet][nonce]; require(0 != index, "No settlement found for wallet and nonce [DriipSettlementState.sol:188]"); DriipSettlementTypesLib.SettlementParty storage party = DriipSettlementTypesLib.SettlementRole.Origin == settlementRole ? settlements[index - 1].origin : settlements[index - 1].target; party.doneBlockNumber = done ? block.number : 0; emit CompleteSettlementPartyEvent(wallet, nonce, settlementRole, party.doneBlockNumber); } function isSettlementPartyDone(address wallet, uint256 nonce) public view returns (bool) { uint256 index = walletNonceSettlementIndex[wallet][nonce]; if (0 == index) return false; return ( wallet == settlements[index - 1].origin.wallet ? 0 != settlements[index - 1].origin.doneBlockNumber : 0 != settlements[index - 1].target.doneBlockNumber ); } function isSettlementPartyDone(address wallet, uint256 nonce, DriipSettlementTypesLib.SettlementRole settlementRole) public view returns (bool) { uint256 index = walletNonceSettlementIndex[wallet][nonce]; if (0 == index) return false; DriipSettlementTypesLib.SettlementParty storage settlementParty = DriipSettlementTypesLib.SettlementRole.Origin == settlementRole ? settlements[index - 1].origin : settlements[index - 1].target; require(wallet == settlementParty.wallet, "Wallet has wrong settlement role [DriipSettlementState.sol:252]"); return 0 != settlementParty.doneBlockNumber; } function settlementPartyDoneBlockNumber(address wallet, uint256 nonce) public view returns (uint256) { uint256 index = walletNonceSettlementIndex[wallet][nonce]; require(0 != index, "No settlement found for wallet and nonce [DriipSettlementState.sol:271]"); return ( wallet == settlements[index - 1].origin.wallet ? settlements[index - 1].origin.doneBlockNumber : settlements[index - 1].target.doneBlockNumber ); } function settlementPartyDoneBlockNumber(address wallet, uint256 nonce, DriipSettlementTypesLib.SettlementRole settlementRole) public view returns (uint256) { uint256 index = walletNonceSettlementIndex[wallet][nonce]; require(0 != index, "No settlement found for wallet and nonce [DriipSettlementState.sol:296]"); DriipSettlementTypesLib.SettlementParty storage settlementParty = DriipSettlementTypesLib.SettlementRole.Origin == settlementRole ? settlements[index - 1].origin : settlements[index - 1].target; require(wallet == settlementParty.wallet, "Wallet has wrong settlement role [DriipSettlementState.sol:304]"); return settlementParty.doneBlockNumber; } function setMaxDriipNonce(uint256 _maxDriipNonce) public onlyEnabledServiceAction(SET_MAX_NONCE_ACTION) { maxDriipNonce = _maxDriipNonce; emit SetMaxDriipNonceEvent(maxDriipNonce); } function updateMaxDriipNonceFromCommunityVote() public { uint256 _maxDriipNonce = communityVote.getMaxDriipNonce(); if (0 == _maxDriipNonce) return; maxDriipNonce = _maxDriipNonce; emit UpdateMaxDriipNonceFromCommunityVoteEvent(maxDriipNonce); } 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 maxNonce) public onlyEnabledServiceAction(SET_MAX_NONCE_ACTION) { walletCurrencyMaxNonce[wallet][currency.ct][currency.id] = maxNonce; emit SetMaxNonceByWalletAndCurrencyEvent(wallet, currency, maxNonce); } function settledAmountByBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency, uint256 blockNumber) public view returns (int256) { uint256 settledBlockNumber = _walletSettledBlockNumber(wallet, currency, blockNumber); return walletCurrencyBlockNumberSettledAmount[wallet][currency.ct][currency.id][settledBlockNumber]; } function addSettledAmountByBlockNumber(address wallet, int256 amount, MonetaryTypesLib.Currency memory currency, uint256 blockNumber) public onlyEnabledServiceAction(ADD_SETTLED_AMOUNT_ACTION) { uint256 settledBlockNumber = _walletSettledBlockNumber(wallet, currency, blockNumber); walletCurrencyBlockNumberSettledAmount[wallet][currency.ct][currency.id][settledBlockNumber] = walletCurrencyBlockNumberSettledAmount[wallet][currency.ct][currency.id][settledBlockNumber].add(amount); walletCurrencySettledBlockNumbers[wallet][currency.ct][currency.id].push(block.number); emit AddSettledAmountEvent(wallet, amount, currency, blockNumber); } function totalFee(address wallet, Beneficiary beneficiary, address destination, MonetaryTypesLib.Currency memory currency) public view returns (MonetaryTypesLib.NoncedAmount memory) { return totalFeesMap[wallet][address(beneficiary)][destination][currency.ct][currency.id]; } function setTotalFee(address wallet, Beneficiary beneficiary, address destination, MonetaryTypesLib.Currency memory currency, MonetaryTypesLib.NoncedAmount memory _totalFee) public onlyEnabledServiceAction(SET_TOTAL_FEE_ACTION) { totalFeesMap[wallet][address(beneficiary)][destination][currency.ct][currency.id] = _totalFee; emit SetTotalFeeEvent(wallet, beneficiary, destination, currency, _totalFee); } function upgradeSettlement(DriipSettlementTypesLib.Settlement memory settlement) public onlyWhenUpgrading { require( 0 == walletNonceSettlementIndex[settlement.origin.wallet][settlement.origin.nonce], "Settlement exists for origin wallet and nonce [DriipSettlementState.sol:443]" ); require( 0 == walletNonceSettlementIndex[settlement.target.wallet][settlement.target.nonce], "Settlement exists for target wallet and nonce [DriipSettlementState.sol:447]" ); settlements.push(settlement); uint256 index = settlements.length; walletSettlementIndices[settlement.origin.wallet].push(index); walletSettlementIndices[settlement.target.wallet].push(index); walletNonceSettlementIndex[settlement.origin.wallet][settlement.origin.nonce] = index; walletNonceSettlementIndex[settlement.target.wallet][settlement.target.nonce] = index; emit UpgradeSettlementEvent(settlement); } function upgradeSettledAmount(address wallet, int256 amount, MonetaryTypesLib.Currency memory currency, uint256 blockNumber) public onlyWhenUpgrading { require(0 == walletCurrencyBlockNumberSettledAmount[wallet][currency.ct][currency.id][blockNumber], "[DriipSettlementState.sol:479]"); walletCurrencyBlockNumberSettledAmount[wallet][currency.ct][currency.id][blockNumber] = amount; walletCurrencySettledBlockNumbers[wallet][currency.ct][currency.id].push(blockNumber); emit UpgradeSettledAmountEvent(wallet, amount, currency, blockNumber); } function _walletSettledBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency, uint256 blockNumber) private view returns (uint256) { for (uint256 i = walletCurrencySettledBlockNumbers[wallet][currency.ct][currency.id].length; i > 0; i--) if (walletCurrencySettledBlockNumbers[wallet][currency.ct][currency.id][i - 1] <= blockNumber) return walletCurrencySettledBlockNumbers[wallet][currency.ct][currency.id][i - 1]; return 0; } } library BalanceTrackerLib { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; function fungibleActiveRecordByBlockNumber(BalanceTracker self, address wallet, MonetaryTypesLib.Currency memory currency, uint256 _blockNumber) internal view returns (int256 amount, uint256 blockNumber) { (int256 depositedAmount, uint256 depositedBlockNumber) = self.fungibleRecordByBlockNumber( wallet, self.depositedBalanceType(), currency.ct, currency.id, _blockNumber ); (int256 settledAmount, uint256 settledBlockNumber) = self.fungibleRecordByBlockNumber( wallet, self.settledBalanceType(), currency.ct, currency.id, _blockNumber ); amount = depositedAmount.add(settledAmount); blockNumber = depositedBlockNumber.clampMin(settledBlockNumber); } function fungibleActiveBalanceAmountByBlockNumber(BalanceTracker self, address wallet, MonetaryTypesLib.Currency memory currency, uint256 blockNumber) internal view returns (int256) { (int256 amount,) = fungibleActiveRecordByBlockNumber(self, wallet, currency, blockNumber); return amount; } function fungibleActiveDeltaBalanceAmountByBlockNumbers(BalanceTracker self, address wallet, MonetaryTypesLib.Currency memory currency, uint256 fromBlockNumber, uint256 toBlockNumber) internal view returns (int256) { return fungibleActiveBalanceAmountByBlockNumber(self, wallet, currency, toBlockNumber) - fungibleActiveBalanceAmountByBlockNumber(self, wallet, currency, fromBlockNumber); } function fungibleActiveRecord(BalanceTracker self, address wallet, MonetaryTypesLib.Currency memory currency) internal view returns (int256 amount, uint256 blockNumber) { (int256 depositedAmount, uint256 depositedBlockNumber) = self.lastFungibleRecord( wallet, self.depositedBalanceType(), currency.ct, currency.id ); (int256 settledAmount, uint256 settledBlockNumber) = self.lastFungibleRecord( wallet, self.settledBalanceType(), currency.ct, currency.id ); amount = depositedAmount.add(settledAmount); blockNumber = depositedBlockNumber.clampMin(settledBlockNumber); } function fungibleActiveBalanceAmount(BalanceTracker self, address wallet, MonetaryTypesLib.Currency memory currency) internal view returns (int256) { return self.get(wallet, self.depositedBalanceType(), currency.ct, currency.id).add( self.get(wallet, self.settledBalanceType(), currency.ct, currency.id) ); } } contract DriipSettlementByPayment is Ownable, Configurable, Validatable, ClientFundable, BalanceTrackable, CommunityVotable, FraudChallengable, WalletLockable, PartnerBenefactorable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; using BalanceTrackerLib for BalanceTracker; DriipSettlementChallengeState public driipSettlementChallengeState; DriipSettlementState public driipSettlementState; RevenueFund public revenueFund; event SettlePaymentEvent(address wallet, PaymentTypesLib.Payment payment, string standard); event SettlePaymentByProxyEvent(address proxy, address wallet, PaymentTypesLib.Payment payment, string standard); event SetDriipSettlementChallengeStateEvent(DriipSettlementChallengeState oldDriipSettlementChallengeState, DriipSettlementChallengeState newDriipSettlementChallengeState); event SetDriipSettlementStateEvent(DriipSettlementState oldDriipSettlementState, DriipSettlementState newDriipSettlementState); event SetRevenueFundEvent(RevenueFund oldRevenueFund, RevenueFund newRevenueFund); event StageFeesEvent(address wallet, int256 deltaAmount, int256 cumulativeAmount, address currencyCt, uint256 currencyId); constructor(address deployer) Ownable(deployer) public { } function setDriipSettlementChallengeState(DriipSettlementChallengeState newDriipSettlementChallengeState) public onlyDeployer notNullAddress(address(newDriipSettlementChallengeState)) { DriipSettlementChallengeState oldDriipSettlementChallengeState = driipSettlementChallengeState; driipSettlementChallengeState = newDriipSettlementChallengeState; emit SetDriipSettlementChallengeStateEvent(oldDriipSettlementChallengeState, driipSettlementChallengeState); } function setDriipSettlementState(DriipSettlementState newDriipSettlementState) public onlyDeployer notNullAddress(address(newDriipSettlementState)) { DriipSettlementState oldDriipSettlementState = driipSettlementState; driipSettlementState = newDriipSettlementState; emit SetDriipSettlementStateEvent(oldDriipSettlementState, driipSettlementState); } function setRevenueFund(RevenueFund newRevenueFund) public onlyDeployer notNullAddress(address(newRevenueFund)) { RevenueFund oldRevenueFund = revenueFund; revenueFund = newRevenueFund; emit SetRevenueFundEvent(oldRevenueFund, revenueFund); } function settlementsCount() public view returns (uint256) { return driipSettlementState.settlementsCount(); } function settlementsCountByWallet(address wallet) public view returns (uint256) { return driipSettlementState.settlementsCountByWallet(wallet); } function settlementByWalletAndIndex(address wallet, uint256 index) public view returns (DriipSettlementTypesLib.Settlement memory) { return driipSettlementState.settlementByWalletAndIndex(wallet, index); } function settlementByWalletAndNonce(address wallet, uint256 nonce) public view returns (DriipSettlementTypesLib.Settlement memory) { return driipSettlementState.settlementByWalletAndNonce(wallet, nonce); } function settlePayment(PaymentTypesLib.Payment memory payment, string memory standard) public { _settlePayment(msg.sender, payment, standard); emit SettlePaymentEvent(msg.sender, payment, standard); } function settlePaymentByProxy(address wallet, PaymentTypesLib.Payment memory payment, string memory standard) public onlyOperator { _settlePayment(wallet, payment, standard); emit SettlePaymentByProxyEvent(msg.sender, wallet, payment, standard); } function _settlePayment(address wallet, PaymentTypesLib.Payment memory payment, string memory standard) private onlySealedPayment(payment) onlyPaymentParty(payment, wallet) { require( !fraudChallenge.isFraudulentPaymentHash(payment.seals.operator.hash), "Payment deemed fraudulent [DriipSettlementByPayment.sol:190]" ); require( !communityVote.isDoubleSpenderWallet(wallet), "Wallet deemed double spender [DriipSettlementByPayment.sol:194]" ); require(!walletLocker.isLocked(wallet), "Wallet found locked [DriipSettlementByPayment.sol:200]"); require( payment.seals.operator.hash == driipSettlementChallengeState.proposalChallengedHash(wallet, payment.currency), "Payment not challenged [DriipSettlementByPayment.sol:203]" ); (DriipSettlementTypesLib.SettlementRole settlementRole, uint256 nonce) = _getSettlementRoleNonce(payment, wallet); require( driipSettlementChallengeState.hasProposal(wallet, nonce, payment.currency), "No proposal found [DriipSettlementByPayment.sol:212]" ); require( !driipSettlementChallengeState.hasProposalTerminated(wallet, payment.currency), "Proposal found terminated [DriipSettlementByPayment.sol:218]" ); require( driipSettlementChallengeState.hasProposalExpired(wallet, payment.currency), "Proposal found not expired [DriipSettlementByPayment.sol:224]" ); require( SettlementChallengeTypesLib.Status.Qualified == driipSettlementChallengeState.proposalStatus(wallet, payment.currency), "Proposal found not qualified [DriipSettlementByPayment.sol:230]" ); require(configuration.isOperationalModeNormal(), "Not normal operational mode [DriipSettlementByPayment.sol:236]"); require(communityVote.isDataAvailable(), "Data not available [DriipSettlementByPayment.sol:237]"); driipSettlementState.initSettlement( PaymentTypesLib.PAYMENT_KIND(), payment.seals.operator.hash, payment.sender.wallet, payment.sender.nonce, payment.recipient.wallet, payment.recipient.nonce ); require( !driipSettlementState.isSettlementPartyDone(wallet, nonce, settlementRole), "Settlement party already done [DriipSettlementByPayment.sol:247]" ); _settle(wallet, payment, standard, nonce, settlementRole); driipSettlementChallengeState.terminateProposal(wallet, payment.currency, false); } function _settle(address wallet, PaymentTypesLib.Payment memory payment, string memory standard, uint256 nonce, DriipSettlementTypesLib.SettlementRole settlementRole) private { (int256 correctedCurrentBalanceAmount, int settleAmount, NahmiiTypesLib.OriginFigure[] memory totalFees) = _paymentPartyProperties(payment, wallet); uint256 maxNonce = driipSettlementState.maxNonceByWalletAndCurrency(wallet, payment.currency); if (maxNonce < nonce) { driipSettlementState.setMaxNonceByWalletAndCurrency(wallet, payment.currency, nonce); clientFund.updateSettledBalance( wallet, correctedCurrentBalanceAmount, payment.currency.ct, payment.currency.id, standard, block.number ); driipSettlementState.addSettledAmountByBlockNumber(wallet, settleAmount, payment.currency, payment.blockNumber); clientFund.stage( wallet, driipSettlementChallengeState.proposalStageAmount(wallet, payment.currency), payment.currency.ct, payment.currency.id, standard ); if (address(0) != address(revenueFund)) _stageFees(wallet, totalFees, revenueFund, nonce, standard); driipSettlementState.completeSettlement( wallet, nonce, settlementRole, true ); } } function _getSettlementRoleNonce(PaymentTypesLib.Payment memory payment, address wallet) private view returns (DriipSettlementTypesLib.SettlementRole settlementRole, uint256 nonce) { if (validator.isPaymentSender(payment, wallet)) { settlementRole = DriipSettlementTypesLib.SettlementRole.Origin; nonce = payment.sender.nonce; } else { settlementRole = DriipSettlementTypesLib.SettlementRole.Target; nonce = payment.recipient.nonce; } } function _paymentPartyProperties(PaymentTypesLib.Payment memory payment, address wallet) private view returns (int256 correctedPaymentBalanceAmount, int settleAmount, NahmiiTypesLib.OriginFigure[] memory totalFees) { if (validator.isPaymentSender(payment, wallet)) { correctedPaymentBalanceAmount = payment.sender.balances.current; totalFees = payment.sender.fees.total; } else { correctedPaymentBalanceAmount = payment.recipient.balances.current; totalFees = payment.recipient.fees.total; } int256 deltaActiveBalanceAmount = balanceTracker.fungibleActiveDeltaBalanceAmountByBlockNumbers( wallet, payment.currency, payment.blockNumber, block.number ); int256 deltaSettledBalanceAmount = driipSettlementState.settledAmountByBlockNumber( wallet, payment.currency, payment.blockNumber ); settleAmount = correctedPaymentBalanceAmount.sub( balanceTracker.fungibleActiveBalanceAmountByBlockNumber( wallet, payment.currency, payment.blockNumber ) ).sub(deltaSettledBalanceAmount); correctedPaymentBalanceAmount = correctedPaymentBalanceAmount .add(deltaActiveBalanceAmount) .sub(deltaSettledBalanceAmount); } function _stageFees(address wallet, NahmiiTypesLib.OriginFigure[] memory fees, Beneficiary protocolBeneficiary, uint256 nonce, string memory standard) private { for (uint256 i = 0; i < fees.length; i++) { Beneficiary beneficiary; if (0 == fees[i].originId) beneficiary = protocolBeneficiary; else if ( 0 < partnerBenefactor.registeredBeneficiariesCount() && fees[i].originId <= partnerBenefactor.registeredBeneficiariesCount() ) beneficiary = partnerBenefactor.beneficiaries(fees[i].originId.sub(1)); if (address(0) == address(beneficiary)) continue; address destination = address(fees[i].originId); if (driipSettlementState.totalFee(wallet, beneficiary, destination, fees[i].figure.currency).nonce < nonce) { int256 deltaAmount = fees[i].figure.amount.sub(driipSettlementState.totalFee(wallet, beneficiary, destination, fees[i].figure.currency).amount); if (deltaAmount.isNonZeroPositiveInt256()) { driipSettlementState.setTotalFee(wallet, beneficiary, destination, fees[i].figure.currency, MonetaryTypesLib.NoncedAmount(nonce, fees[i].figure.amount)); clientFund.transferToBeneficiary( wallet, beneficiary, deltaAmount, fees[i].figure.currency.ct, fees[i].figure.currency.id, standard ); emit StageFeesEvent( wallet, deltaAmount, fees[i].figure.amount, fees[i].figure.currency.ct, fees[i].figure.currency.id ); } } } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":false,"inputs":[{"internalType":"contract FraudChallenge","name":"newFraudChallenge","type":"address"}],"name":"setFraudChallenge","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract Validator","name":"newValidator","type":"address"}],"name":"setValidator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"balanceTracker","outputs":[{"internalType":"contract BalanceTracker","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"walletLockerFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"driipSettlementState","outputs":[{"internalType":"contract DriipSettlementState","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"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":"validator","outputs":[{"internalType":"contract Validator","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"fraudChallenge","outputs":[{"internalType":"contract FraudChallenge","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"balanceTrackerFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract DriipSettlementState","name":"newDriipSettlementState","type":"address"}],"name":"setDriipSettlementState","outputs":[],"payable":false,"stateMutability":"nonpayable","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 PartnerBenefactor","name":"newPartnerBenefactor","type":"address"}],"name":"setPartnerBenefactor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract BalanceTracker","name":"newBalanceTracker","type":"address"}],"name":"setBalanceTracker","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"freezeWalletLocker","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract Configuration","name":"newConfiguration","type":"address"}],"name":"setConfiguration","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":[],"name":"disableSelfDestruction","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract WalletLocker","name":"newWalletLocker","type":"address"}],"name":"setWalletLocker","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"partnerBenefactor","outputs":[{"internalType":"contract PartnerBenefactor","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"settlementsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"communityVoteFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"revenueFund","outputs":[{"internalType":"contract RevenueFund","name":"","type":"address"}],"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":"wallet","type":"address"},{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"wallet","type":"address"},{"components":[{"internalType":"int256","name":"current","type":"int256"},{"internalType":"int256","name":"previous","type":"int256"}],"internalType":"struct NahmiiTypesLib.CurrentPreviousInt256","name":"balances","type":"tuple"},{"components":[{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"}],"internalType":"struct MonetaryTypesLib.Figure","name":"single","type":"tuple"},{"components":[{"internalType":"uint256","name":"originId","type":"uint256"},{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"}],"internalType":"struct MonetaryTypesLib.Figure","name":"figure","type":"tuple"}],"internalType":"struct NahmiiTypesLib.OriginFigure[]","name":"total","type":"tuple[]"}],"internalType":"struct NahmiiTypesLib.SingleFigureTotalOriginFigures","name":"fees","type":"tuple"},{"internalType":"string","name":"data","type":"string"}],"internalType":"struct PaymentTypesLib.PaymentSenderParty","name":"sender","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"wallet","type":"address"},{"components":[{"internalType":"int256","name":"current","type":"int256"},{"internalType":"int256","name":"previous","type":"int256"}],"internalType":"struct NahmiiTypesLib.CurrentPreviousInt256","name":"balances","type":"tuple"},{"components":[{"components":[{"internalType":"uint256","name":"originId","type":"uint256"},{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"}],"internalType":"struct MonetaryTypesLib.Figure","name":"figure","type":"tuple"}],"internalType":"struct NahmiiTypesLib.OriginFigure[]","name":"total","type":"tuple[]"}],"internalType":"struct NahmiiTypesLib.TotalOriginFigures","name":"fees","type":"tuple"}],"internalType":"struct PaymentTypesLib.PaymentRecipientParty","name":"recipient","type":"tuple"},{"components":[{"internalType":"int256","name":"single","type":"int256"},{"internalType":"int256","name":"total","type":"int256"}],"internalType":"struct NahmiiTypesLib.SingleTotalInt256","name":"transfers","type":"tuple"},{"components":[{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct NahmiiTypesLib.Signature","name":"signature","type":"tuple"}],"internalType":"struct NahmiiTypesLib.Seal","name":"wallet","type":"tuple"},{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct NahmiiTypesLib.Signature","name":"signature","type":"tuple"}],"internalType":"struct NahmiiTypesLib.Seal","name":"operator","type":"tuple"}],"internalType":"struct NahmiiTypesLib.WalletOperatorSeal","name":"seals","type":"tuple"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"data","type":"string"}],"internalType":"struct PaymentTypesLib.Operator","name":"operator","type":"tuple"}],"internalType":"struct PaymentTypesLib.Payment","name":"payment","type":"tuple"},{"internalType":"string","name":"standard","type":"string"}],"name":"settlePaymentByProxy","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":[],"name":"freezeBalanceTracker","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":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"settlementByWalletAndIndex","outputs":[{"components":[{"internalType":"string","name":"settledKind","type":"string"},{"internalType":"bytes32","name":"settledHash","type":"bytes32"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"doneBlockNumber","type":"uint256"}],"internalType":"struct DriipSettlementTypesLib.SettlementParty","name":"origin","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"doneBlockNumber","type":"uint256"}],"internalType":"struct DriipSettlementTypesLib.SettlementParty","name":"target","type":"tuple"}],"internalType":"struct DriipSettlementTypesLib.Settlement","name":"","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"settlementByWalletAndNonce","outputs":[{"components":[{"internalType":"string","name":"settledKind","type":"string"},{"internalType":"bytes32","name":"settledHash","type":"bytes32"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"doneBlockNumber","type":"uint256"}],"internalType":"struct DriipSettlementTypesLib.SettlementParty","name":"origin","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"doneBlockNumber","type":"uint256"}],"internalType":"struct DriipSettlementTypesLib.SettlementParty","name":"target","type":"tuple"}],"internalType":"struct DriipSettlementTypesLib.Settlement","name":"","type":"tuple"}],"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":[{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"wallet","type":"address"},{"components":[{"internalType":"int256","name":"current","type":"int256"},{"internalType":"int256","name":"previous","type":"int256"}],"internalType":"struct NahmiiTypesLib.CurrentPreviousInt256","name":"balances","type":"tuple"},{"components":[{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"}],"internalType":"struct MonetaryTypesLib.Figure","name":"single","type":"tuple"},{"components":[{"internalType":"uint256","name":"originId","type":"uint256"},{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"}],"internalType":"struct MonetaryTypesLib.Figure","name":"figure","type":"tuple"}],"internalType":"struct NahmiiTypesLib.OriginFigure[]","name":"total","type":"tuple[]"}],"internalType":"struct NahmiiTypesLib.SingleFigureTotalOriginFigures","name":"fees","type":"tuple"},{"internalType":"string","name":"data","type":"string"}],"internalType":"struct PaymentTypesLib.PaymentSenderParty","name":"sender","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"wallet","type":"address"},{"components":[{"internalType":"int256","name":"current","type":"int256"},{"internalType":"int256","name":"previous","type":"int256"}],"internalType":"struct NahmiiTypesLib.CurrentPreviousInt256","name":"balances","type":"tuple"},{"components":[{"components":[{"internalType":"uint256","name":"originId","type":"uint256"},{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"}],"internalType":"struct MonetaryTypesLib.Figure","name":"figure","type":"tuple"}],"internalType":"struct NahmiiTypesLib.OriginFigure[]","name":"total","type":"tuple[]"}],"internalType":"struct NahmiiTypesLib.TotalOriginFigures","name":"fees","type":"tuple"}],"internalType":"struct PaymentTypesLib.PaymentRecipientParty","name":"recipient","type":"tuple"},{"components":[{"internalType":"int256","name":"single","type":"int256"},{"internalType":"int256","name":"total","type":"int256"}],"internalType":"struct NahmiiTypesLib.SingleTotalInt256","name":"transfers","type":"tuple"},{"components":[{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct NahmiiTypesLib.Signature","name":"signature","type":"tuple"}],"internalType":"struct NahmiiTypesLib.Seal","name":"wallet","type":"tuple"},{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct NahmiiTypesLib.Signature","name":"signature","type":"tuple"}],"internalType":"struct NahmiiTypesLib.Seal","name":"operator","type":"tuple"}],"internalType":"struct NahmiiTypesLib.WalletOperatorSeal","name":"seals","type":"tuple"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"data","type":"string"}],"internalType":"struct PaymentTypesLib.Operator","name":"operator","type":"tuple"}],"internalType":"struct PaymentTypesLib.Payment","name":"payment","type":"tuple"},{"internalType":"string","name":"standard","type":"string"}],"name":"settlePayment","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":"walletLocker","outputs":[{"internalType":"contract WalletLocker","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract RevenueFund","name":"newRevenueFund","type":"address"}],"name":"setRevenueFund","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"settlementsCountByWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"address","name":"wallet","type":"address"},{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"wallet","type":"address"},{"components":[{"internalType":"int256","name":"current","type":"int256"},{"internalType":"int256","name":"previous","type":"int256"}],"internalType":"struct NahmiiTypesLib.CurrentPreviousInt256","name":"balances","type":"tuple"},{"components":[{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"}],"internalType":"struct MonetaryTypesLib.Figure","name":"single","type":"tuple"},{"components":[{"internalType":"uint256","name":"originId","type":"uint256"},{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"}],"internalType":"struct MonetaryTypesLib.Figure","name":"figure","type":"tuple"}],"internalType":"struct NahmiiTypesLib.OriginFigure[]","name":"total","type":"tuple[]"}],"internalType":"struct NahmiiTypesLib.SingleFigureTotalOriginFigures","name":"fees","type":"tuple"},{"internalType":"string","name":"data","type":"string"}],"internalType":"struct PaymentTypesLib.PaymentSenderParty","name":"sender","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"wallet","type":"address"},{"components":[{"internalType":"int256","name":"current","type":"int256"},{"internalType":"int256","name":"previous","type":"int256"}],"internalType":"struct NahmiiTypesLib.CurrentPreviousInt256","name":"balances","type":"tuple"},{"components":[{"components":[{"internalType":"uint256","name":"originId","type":"uint256"},{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"}],"internalType":"struct MonetaryTypesLib.Figure","name":"figure","type":"tuple"}],"internalType":"struct NahmiiTypesLib.OriginFigure[]","name":"total","type":"tuple[]"}],"internalType":"struct NahmiiTypesLib.TotalOriginFigures","name":"fees","type":"tuple"}],"internalType":"struct PaymentTypesLib.PaymentRecipientParty","name":"recipient","type":"tuple"},{"components":[{"internalType":"int256","name":"single","type":"int256"},{"internalType":"int256","name":"total","type":"int256"}],"internalType":"struct NahmiiTypesLib.SingleTotalInt256","name":"transfers","type":"tuple"},{"components":[{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct NahmiiTypesLib.Signature","name":"signature","type":"tuple"}],"internalType":"struct NahmiiTypesLib.Seal","name":"wallet","type":"tuple"},{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct NahmiiTypesLib.Signature","name":"signature","type":"tuple"}],"internalType":"struct NahmiiTypesLib.Seal","name":"operator","type":"tuple"}],"internalType":"struct NahmiiTypesLib.WalletOperatorSeal","name":"seals","type":"tuple"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"data","type":"string"}],"internalType":"struct PaymentTypesLib.Operator","name":"operator","type":"tuple"}],"indexed":false,"internalType":"struct PaymentTypesLib.Payment","name":"payment","type":"tuple"},{"indexed":false,"internalType":"string","name":"standard","type":"string"}],"name":"SettlePaymentEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"proxy","type":"address"},{"indexed":false,"internalType":"address","name":"wallet","type":"address"},{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"wallet","type":"address"},{"components":[{"internalType":"int256","name":"current","type":"int256"},{"internalType":"int256","name":"previous","type":"int256"}],"internalType":"struct NahmiiTypesLib.CurrentPreviousInt256","name":"balances","type":"tuple"},{"components":[{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"}],"internalType":"struct MonetaryTypesLib.Figure","name":"single","type":"tuple"},{"components":[{"internalType":"uint256","name":"originId","type":"uint256"},{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"}],"internalType":"struct MonetaryTypesLib.Figure","name":"figure","type":"tuple"}],"internalType":"struct NahmiiTypesLib.OriginFigure[]","name":"total","type":"tuple[]"}],"internalType":"struct NahmiiTypesLib.SingleFigureTotalOriginFigures","name":"fees","type":"tuple"},{"internalType":"string","name":"data","type":"string"}],"internalType":"struct PaymentTypesLib.PaymentSenderParty","name":"sender","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"wallet","type":"address"},{"components":[{"internalType":"int256","name":"current","type":"int256"},{"internalType":"int256","name":"previous","type":"int256"}],"internalType":"struct NahmiiTypesLib.CurrentPreviousInt256","name":"balances","type":"tuple"},{"components":[{"components":[{"internalType":"uint256","name":"originId","type":"uint256"},{"components":[{"internalType":"int256","name":"amount","type":"int256"},{"components":[{"internalType":"address","name":"ct","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct MonetaryTypesLib.Currency","name":"currency","type":"tuple"}],"internalType":"struct MonetaryTypesLib.Figure","name":"figure","type":"tuple"}],"internalType":"struct NahmiiTypesLib.OriginFigure[]","name":"total","type":"tuple[]"}],"internalType":"struct NahmiiTypesLib.TotalOriginFigures","name":"fees","type":"tuple"}],"internalType":"struct PaymentTypesLib.PaymentRecipientParty","name":"recipient","type":"tuple"},{"components":[{"internalType":"int256","name":"single","type":"int256"},{"internalType":"int256","name":"total","type":"int256"}],"internalType":"struct NahmiiTypesLib.SingleTotalInt256","name":"transfers","type":"tuple"},{"components":[{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct NahmiiTypesLib.Signature","name":"signature","type":"tuple"}],"internalType":"struct NahmiiTypesLib.Seal","name":"wallet","type":"tuple"},{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct NahmiiTypesLib.Signature","name":"signature","type":"tuple"}],"internalType":"struct NahmiiTypesLib.Seal","name":"operator","type":"tuple"}],"internalType":"struct NahmiiTypesLib.WalletOperatorSeal","name":"seals","type":"tuple"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"data","type":"string"}],"internalType":"struct PaymentTypesLib.Operator","name":"operator","type":"tuple"}],"indexed":false,"internalType":"struct PaymentTypesLib.Payment","name":"payment","type":"tuple"},{"indexed":false,"internalType":"string","name":"standard","type":"string"}],"name":"SettlePaymentByProxyEvent","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":"contract DriipSettlementState","name":"oldDriipSettlementState","type":"address"},{"indexed":false,"internalType":"contract DriipSettlementState","name":"newDriipSettlementState","type":"address"}],"name":"SetDriipSettlementStateEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract RevenueFund","name":"oldRevenueFund","type":"address"},{"indexed":false,"internalType":"contract RevenueFund","name":"newRevenueFund","type":"address"}],"name":"SetRevenueFundEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"int256","name":"deltaAmount","type":"int256"},{"indexed":false,"internalType":"int256","name":"cumulativeAmount","type":"int256"},{"indexed":false,"internalType":"address","name":"currencyCt","type":"address"},{"indexed":false,"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"StageFeesEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract PartnerBenefactor","name":"oldPartnerBenefactor","type":"address"},{"indexed":false,"internalType":"contract PartnerBenefactor","name":"newPartnerBenefactor","type":"address"}],"name":"SetPartnerBenefactorEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract WalletLocker","name":"oldWalletLocker","type":"address"},{"indexed":false,"internalType":"contract WalletLocker","name":"newWalletLocker","type":"address"}],"name":"SetWalletLockerEvent","type":"event"},{"anonymous":false,"inputs":[],"name":"FreezeWalletLockerEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract FraudChallenge","name":"oldFraudChallenge","type":"address"},{"indexed":false,"internalType":"contract FraudChallenge","name":"newFraudChallenge","type":"address"}],"name":"SetFraudChallengeEvent","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 BalanceTracker","name":"oldBalanceTracker","type":"address"},{"indexed":false,"internalType":"contract BalanceTracker","name":"newBalanceTracker","type":"address"}],"name":"SetBalanceTrackerEvent","type":"event"},{"anonymous":false,"inputs":[],"name":"FreezeBalanceTrackerEvent","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 Validator","name":"oldValidator","type":"address"},{"indexed":false,"internalType":"contract Validator","name":"newValidator","type":"address"}],"name":"SetValidatorEvent","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
60806040523480156200001157600080fd5b50604051620048a8380380620048a88339810160408190526200003491620000b3565b80806001600160a01b0381166200004a57600080fd5b6001600160a01b0381163014156200006157600080fd5b5060008054610100600160a81b0319166101006001600160a01b0393909316928302179055600180546001600160a01b03191690911790555062000108565b8051620000ad81620000ee565b92915050565b600060208284031215620000c657600080fd5b6000620000d48484620000a0565b949350505050565b60006001600160a01b038216620000ad565b620000f981620000dc565b81146200010557600080fd5b50565b61479080620001186000396000f3fe608060405234801561001057600080fd5b50600436106101ee5760003560e01c806301370d06146101f35780631327d3d814610208578063191390921461021b578063240625d81461023957806325c844411461024e5780632738a112146102565780632aa1c9d91461025e5780632f013a00146102715780633a5381b5146102795780633bd7857f146102815780633e59b70614610289578063404e896f146102915780634476d23b146102a457806351d7cd61146102b9578063570ca735146102c15780635736db99146102c9578063598b75ad146102dc5780635dc60def146102ef578063627f09c3146102f7578063670732a71461030a5780636c70bee91461031257806370327ea11461031a578063892860b2146103225780638aa96f26146103355780638c6913bc1461033d5780638e9d6cbd1461035257806395ff296d1461035a5780639621473514610362578063b0c8e20514610375578063b3ab15fb14610388578063b52d470a1461039b578063b71ded2f146103a3578063bf24e7d0146103b6578063c0ffe1b4146103be578063d2f08936146103de578063d5f39488146103f1578063dd3056ca146103f9578063e754476f1461040c578063e86ab8f614610414578063e8ae41e314610427578063f152dd381461042f578063f345fb4414610442575b600080fd5b6102066102013660046134c2565b610455565b005b6102066102163660046134c2565b6104f6565b610223610587565b604051610230919061441c565b60405180910390f35b610241610596565b6040516102309190614400565b6102236105a6565b6102066105b5565b61020661026c3660046134c2565b61061b565b6102416106a2565b6102236106ab565b6102236106ba565b6102416106c9565b61020661029f3660046134c2565b6106d9565b6102ac610753565b604051610230919061400d565b610223610767565b6102ac610776565b6102066102d73660046134c2565b610785565b6102066102ea3660046134c2565b610816565b6102066108da565b6102066103053660046134c2565b610929565b6102066109ba565b610223610a09565b610206610a18565b6102066103303660046134c2565b610a7b565b610223610b36565b610345610b45565b604051610230919061440e565b610241610bc7565b610223610bd7565b6102066103703660046133b3565b610be6565b6102066103833660046133d1565b610c9c565b6102066103963660046133b3565b610ced565b610206610d90565b6102066103b13660046134c2565b610ddf565b610223610e70565b6103d16103cc36600461344c565b610e7f565b60405161023091906145ca565b6103d16103ec36600461344c565b610f16565b6102ac610f50565b61020661040736600461359e565b610f64565b610223610fae565b6102066104223660046134c2565b610fbd565b610223611078565b61020661043d3660046134c2565b611087565b6103456104503660046133b3565b611101565b61045d61118a565b61046657600080fd5b806001600160a01b03811661047a57600080fd5b60075482906001600160a01b0390811690821681146104f057600780546001600160a01b038681166001600160a01b03198316179092556040519116907f07998fa7be97abe2427246ae4688298c89d6196bbffdf0997b9495a8d27bc673906104e6908390889061442a565b60405180910390a1505b50505050565b6104fe61118a565b61050757600080fd5b806001600160a01b03811661051b57600080fd5b60035482906001600160a01b0390811690821681146104f057600380546001600160a01b038681166001600160a01b03198316179092556040519116907f1882af944a16549c3d4f60e3cd26f158b0c7aac3222cf32971fc21375ce05f60906104e6908390889061442a565b6005546001600160a01b031681565b600854600160a01b900460ff1681565b600b546001600160a01b031681565b336105be610753565b6001600160a01b0316146105d157600080fd5b60005460ff16156105e157600080fd5b7f787a5d936e74f4b564b9153575886059829c78cd9927b1be5e0d976b317ef73633604051610610919061401b565b60405180910390a133ff5b61062361118a565b61062c57600080fd5b806001600160a01b03811661064057600080fd5b600a80546001600160a01b038481166001600160a01b031983161792839055604051918116927f4f7125332801996cdeaabf9cff1ac89ddf4b52c673558936affe853ab64a88da92610695928592169061442a565b60405180910390a1505050565b60005460ff1681565b6003546001600160a01b031681565b6007546001600160a01b031681565b600554600160a01b900460ff1681565b6106e161118a565b6106ea57600080fd5b806001600160a01b0381166106fe57600080fd5b600b80546001600160a01b038481166001600160a01b031983161792839055604051918116927f6d4735156f5fb1047cfcd4a9edf19e3291aec19d53916f8fee650ca3c2d7391092610695928592169061442a565b60005461010090046001600160a01b031690565b600a546001600160a01b031681565b6001546001600160a01b031681565b61078d61118a565b61079657600080fd5b806001600160a01b0381166107aa57600080fd5b60095482906001600160a01b0390811690821681146104f057600980546001600160a01b038681166001600160a01b03198316179092556040519116907febf60ff5929740b0a97ee47e911fae91589cc49afdca90ec269737058e7fab91906104e6908390889061442a565b61081e61118a565b61082757600080fd5b806001600160a01b03811661083b57600080fd5b60055482906001600160a01b0390811690821681146104f057600554600160a01b900460ff16156108875760405162461bcd60e51b815260040161087e906144c9565b60405180910390fd5b600580546001600160a01b038681166001600160a01b03198316179092556040519116907fb2a91d3a71b0c5bc7c083153b3474378e489506ba98bd4ddb1b9056fdc594bb5906104e6908390889061442a565b6108e261118a565b6108eb57600080fd5b6008805460ff60a01b1916600160a01b1790556040517f56ec8900b9c4bf84f4b715a53068ca06961dd49084c07b481931e2c2045346e690600090a1565b61093161118a565b61093a57600080fd5b806001600160a01b03811661094e57600080fd5b60025482906001600160a01b0390811690821681146104f057600280546001600160a01b038681166001600160a01b03198316179092556040519116907f634f61bf00e14adedce330c80c2823e16e184f189ebe853e1ddecc4a268477ff906104e6908390889061442a565b6109c261118a565b6109cb57600080fd5b6006805460ff60a01b1916600160a01b1790556040517fc1668d45f18667fb6eadfbcacfd5cdcc7dd4ecdfc9b0ab8786cfdbad86bb83d890600090a1565b6002546001600160a01b031681565b33610a21610753565b6001600160a01b031614610a3457600080fd5b6000805460ff191660011790556040517fd5a2a04a775c741c2ca0dc46ea7ce4835190e1aaf1ca018def0e82568ec3361690610a7190339061401b565b60405180910390a1565b610a8361118a565b610a8c57600080fd5b806001600160a01b038116610aa057600080fd5b60085482906001600160a01b0390811690821681146104f057600854600160a01b900460ff1615610ae35760405162461bcd60e51b815260040161087e90614589565b600880546001600160a01b038681166001600160a01b03198316179092556040519116907fa44d361e26327b72a7ccbeae801b3c5cd7677ea4fa74168b289e273c46bfecfc906104e6908390889061442a565b6009546001600160a01b031681565b600b546040805163231a44ef60e21b815290516000926001600160a01b031691638c6913bc916004808301926020929190829003018186803b158015610b8a57600080fd5b505afa158015610b9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bc291908101906134a4565b905090565b600654600160a01b900460ff1681565b600c546001600160a01b031681565b610bee61118a565b610bf757600080fd5b806001600160a01b038116610c0b57600080fd5b6001600160a01b038116301415610c2157600080fd5b6000546001600160a01b038381166101009092041614610c9857600080546001600160a01b03848116610100908102610100600160a81b03198416179093556040519290910416907f977e5fa58e458501775e0008d275006294c5249e3c08d1d0e3a9f3acad14f6e49061069590839086906140a8565b5050565b610ca46111a0565b610cad57600080fd5b610cb88383836111b1565b7f2ac9ebc2da0aa92179f0e3daa8d52d8712a3922edda87c72b050c2b089873050338484846040516106959493929190614029565b610cf56111a0565b610cfe57600080fd5b806001600160a01b038116610d1257600080fd5b6001600160a01b038116301415610d2857600080fd5b6001546001600160a01b03838116911614610c9857600180546001600160a01b038481166001600160a01b03198316179092556040519116907f9f611b789425d0d5b90b920f1b2852907dd865c80074a30b1629aaa041d1812c9061069590839086906140a8565b610d9861118a565b610da157600080fd5b6005805460ff60a01b1916600160a01b1790556040517f9c567b65fe8caab5ec7bc979a498a1322c1d4baf01a30727cbca137187560ea290600090a1565b610de761118a565b610df057600080fd5b806001600160a01b038116610e0457600080fd5b60045482906001600160a01b0390811690821681146104f057600480546001600160a01b038681166001600160a01b03198316179092556040519116907f4d96d2a04c886b313bd1e28be6324ed4c8867b3203e512756722f8be0195e16d906104e6908390889061442a565b6006546001600160a01b031681565b610e87612bf4565b600b5460405163303ff86d60e21b81526001600160a01b039091169063c0ffe1b490610eb99086908690600401614360565b60006040518083038186803b158015610ed157600080fd5b505afa158015610ee5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f0d91908101906135fb565b90505b92915050565b610f1e612bf4565b600b54604051636978449b60e11b81526001600160a01b039091169063d2f0893690610eb99086908690600401614360565b60005461010090046001600160a01b031681565b610f6f3383836111b1565b7fb6d612c8f6da6a2956a25a735b6e54de99363dfdb50a02565ab53b1adc65b3d6338383604051610fa293929190614074565b60405180910390a15050565b6004546001600160a01b031681565b610fc561118a565b610fce57600080fd5b806001600160a01b038116610fe257600080fd5b60065482906001600160a01b0390811690821681146104f057600654600160a01b900460ff16156110255760405162461bcd60e51b815260040161087e90614509565b600680546001600160a01b038681166001600160a01b03198316179092556040519116907f624c4d4225a45f5bf8a9755adba1ef9be3464a9970b05a371fb6cca0c0caf204906104e6908390889061442a565b6008546001600160a01b031681565b61108f61118a565b61109857600080fd5b806001600160a01b0381166110ac57600080fd5b600c80546001600160a01b038481166001600160a01b031983161792839055604051918116927f0e0d0aee1efbecb32fba4a76ecc4cae4c9ed1c3ea3459ea8460c53ff4cb09bcf92610695928592169061442a565b600b54604051633cd17ed160e21b81526000916001600160a01b03169063f345fb449061113290859060040161400d565b60206040518083038186803b15801561114a57600080fd5b505afa15801561115e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061118291908101906134a4565b90505b919050565b60005461010090046001600160a01b0316331490565b6001546001600160a01b0316331490565b60035460405163273f8b6560e11b815283916001600160a01b031690634e7f16ca906111e1908490600401614599565b60206040518083038186803b1580156111f957600080fd5b505afa15801561120d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112319190810190613486565b61124d5760405162461bcd60e51b815260040161087e90614579565b60035460405163f59d1a7560e01b8152849186916001600160a01b039091169063f59d1a759061128390859085906004016145aa565b60206040518083038186803b15801561129b57600080fd5b505afa1580156112af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112d39190810190613486565b6112ef5760405162461bcd60e51b815260040161087e906144d9565b60075460a086015160200151516040516310c7a6c160e31b81526001600160a01b039092169163863d3608916113279160040161440e565b60206040518083038186803b15801561133f57600080fd5b505afa158015611353573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113779190810190613486565b156113945760405162461bcd60e51b815260040161087e90614519565b600654604051639243c9db60e01b81526001600160a01b0390911690639243c9db906113c490899060040161400d565b60206040518083038186803b1580156113dc57600080fd5b505afa1580156113f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114149190810190613486565b156114315760405162461bcd60e51b815260040161087e906144f9565b600854604051631293efbb60e21b81526001600160a01b0390911690634a4fbeec9061146190899060040161400d565b60206040518083038186803b15801561147957600080fd5b505afa15801561148d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114b19190810190613486565b156114ce5760405162461bcd60e51b815260040161087e90614539565b600a54602086015160405163da473c5760e01b81526001600160a01b039092169163da473c5791611504918a91906004016142f5565b60206040518083038186803b15801561151c57600080fd5b505afa158015611530573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061155491908101906134a4565b60a086015160200151511461157b5760405162461bcd60e51b815260040161087e90614549565b6000806115888789611ba8565b600a5460208a0151604051636543ade160e01b81529395509193506001600160a01b031691636543ade1916115c3918c9186916004016143d8565b60206040518083038186803b1580156115db57600080fd5b505afa1580156115ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116139190810190613486565b61162f5760405162461bcd60e51b815260040161087e90614559565b600a546020880151604051637ff81c3760e01b81526001600160a01b0390921691637ff81c3791611665918c91906004016142f5565b60206040518083038186803b15801561167d57600080fd5b505afa158015611691573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116b59190810190613486565b156116d25760405162461bcd60e51b815260040161087e906144e9565b600a546020880151604051635482c73560e01b81526001600160a01b0390921691635482c73591611708918c91906004016142f5565b60206040518083038186803b15801561172057600080fd5b505afa158015611734573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117589190810190613486565b6117745760405162461bcd60e51b815260040161087e906144a9565b600a54602088015160405163b6e2fc3360e01b81526001600160a01b039092169163b6e2fc33916117aa918c91906004016142f5565b60206040518083038186803b1580156117c257600080fd5b505afa1580156117d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117fa91908101906134fe565b600181111561180557fe5b156118225760405162461bcd60e51b815260040161087e90614569565b600260009054906101000a90046001600160a01b03166001600160a01b031663f71e860f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561187057600080fd5b505afa158015611884573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118a89190810190613486565b6118c45760405162461bcd60e51b815260040161087e90614529565b600660009054906101000a90046001600160a01b03166001600160a01b031663994e20766040518163ffffffff1660e01b815260040160206040518083038186803b15801561191257600080fd5b505afa158015611926573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061194a9190810190613486565b6119665760405162461bcd60e51b815260040161087e906144b9565b600b60009054906101000a90046001600160a01b03166001600160a01b0316638772531373b99f3f4aacb6e1197a623919103b99f4b41aaef0635174abe96040518163ffffffff1660e01b815260040160006040518083038186803b1580156119ce57600080fd5b505af41580156119e2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a0a919081019061354c565b60a08a0151602090810151516040808d015180840151905160608f015194850151945192516001600160e01b031960e089901b168152611a539695929391929190600401614445565b600060405180830381600087803b158015611a6d57600080fd5b505af1158015611a81573d6000803e3d6000fd5b5050600b546040516309f0ac8560e41b81526001600160a01b039091169250639f0ac8509150611ab9908b908590879060040161437b565b60206040518083038186803b158015611ad157600080fd5b505afa158015611ae5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b099190810190613486565b15611b265760405162461bcd60e51b815260040161087e90614499565b611b338888888486611c57565b600a54602088015160405163524ad18360e11b81526001600160a01b039092169163a495a30691611b6c918c9190600090600401614310565b600060405180830381600087803b158015611b8657600080fd5b505af1158015611b9a573d6000803e3d6000fd5b505050505050505050505050565b60035460405163d308b9db60e01b815260009182916001600160a01b039091169063d308b9db90611bdf90879087906004016145aa565b60206040518083038186803b158015611bf757600080fd5b505afa158015611c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611c2f9190810190613486565b15611c44575050604082015151600090611c50565b50506060820151516001905b9250929050565b6000806060611c668789611feb565b600b5460208b0151604051633858654b60e01b81529497509295509093506000926001600160a01b0390911691633858654b91611ca7918d916004016142f5565b60206040518083038186803b158015611cbf57600080fd5b505afa158015611cd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611cf791908101906134a4565b905085811015611fe057600b546020890151604051630284774760e31b81526001600160a01b0390921691631423ba3891611d39918d91908b90600401614338565b600060405180830381600087803b158015611d5357600080fd5b505af1158015611d67573d6000803e3d6000fd5b5050600480546020808d0151805191015160405163325d23a960e11b81526001600160a01b0390931695506364ba47529450611dad938f938b9392918f91439101614235565b600060405180830381600087803b158015611dc757600080fd5b505af1158015611ddb573d6000803e3d6000fd5b5050600b5460208b015160c08c015160405163fb721b5360e01b81526001600160a01b03909316945063fb721b539350611e1d928e92899290916004016142c0565b600060405180830381600087803b158015611e3757600080fd5b505af1158015611e4b573d6000803e3d6000fd5b505060048054600a5460208d0151604051633007230f60e11b81526001600160a01b03938416965063ad468df995508f94929093169263600e461e92611e959286929091016142f5565b60206040518083038186803b158015611ead57600080fd5b505afa158015611ec1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611ee591908101906134a4565b6020808d015180519101516040516001600160e01b031960e087901b168152611f1694939291908e906004016141e3565b600060405180830381600087803b158015611f3057600080fd5b505af1158015611f44573d6000803e3d6000fd5b5050600c546001600160a01b0316159150611f76905057600c54611f76908a9084906001600160a01b0316898b6121d9565b600b5460405163f8eabcc160e01b81526001600160a01b039091169063f8eabcc190611fad908c908a908a906001906004016143a3565b600060405180830381600087803b158015611fc757600080fd5b505af1158015611fdb573d6000803e3d6000fd5b505050505b505050505050505050565b60035460405163d308b9db60e01b815260009182916060916001600160a01b03169063d308b9db9061202390889088906004016145aa565b60206040518083038186803b15801561203b57600080fd5b505afa15801561204f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506120739190810190613486565b1561209657506040808501519081015151606090910151602001519092506120ab565b50606080850151604081015151910151519092505b602085015160c08601516005546000926120da926001600160a01b03909216918891904363ffffffff61288116565b600b54602088015160c089015160405163bc8dd4cd60e01b81529394506000936001600160a01b039093169263bc8dd4cd9261211a928b92600401614338565b60206040518083038186803b15801561213257600080fd5b505afa158015612146573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061216a91908101906134a4565b602088015160c08901516005549293506121b89284926121ac9261219f926001600160a01b0316918c9163ffffffff6128a816565b889063ffffffff6128c416565b9063ffffffff6128c416565b93506121ce816121ac878563ffffffff6128fe16565b945050509250925092565b60005b84518110156128795760008582815181106121f357fe5b6020026020010151600001516000141561220e5750836123f7565b600960009054906101000a90046001600160a01b03166001600160a01b03166367299f366040518163ffffffff1660e01b815260040160206040518083038186803b15801561225c57600080fd5b505afa158015612270573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061229491908101906134a4565b600010801561233f5750600960009054906101000a90046001600160a01b03166001600160a01b03166367299f366040518163ffffffff1660e01b815260040160206040518083038186803b1580156122ec57600080fd5b505afa158015612300573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061232491908101906134a4565b86838151811061233057fe5b60200260200101516000015111155b156123f75760095486516001600160a01b039091169063efeb5e5890612388906001908a908790811061236e57fe5b60200260200101516000015161293190919063ffffffff16565b6040518263ffffffff1660e01b81526004016123a4919061440e565b60206040518083038186803b1580156123bc57600080fd5b505afa1580156123d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506123f491908101906134e0565b90505b6001600160a01b03811661240b5750612871565b600086838151811061241957fe5b602002602001015160000151905084600b60009054906101000a90046001600160a01b03166001600160a01b0316636e17226a8a85858c898151811061245b57fe5b602002602001015160200151602001516040518563ffffffff1660e01b815260040161248a949392919061410c565b604080518083038186803b1580156124a157600080fd5b505afa1580156124b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124d99190810190613580565b51101561286e5760006125c4600b60009054906101000a90046001600160a01b03166001600160a01b0316636e17226a8b86868d8a8151811061251857fe5b602002602001015160200151602001516040518563ffffffff1660e01b8152600401612547949392919061410c565b604080518083038186803b15801561255e57600080fd5b505afa158015612572573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125969190810190613580565b602001518986815181106125a657fe5b602002602001015160200151600001516128c490919063ffffffff16565b6040516351750e5360e11b8152909150732fcb98529d58669e229c453de4b4705bb6b2d4149063a2ea1ca6906125fe90849060040161440e565b60206040518083038186803b15801561261657600080fd5b505af415801561262a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061264e9190810190613486565b1561286c57600b60009054906101000a90046001600160a01b03166001600160a01b0316637657768c8a85858c898151811061268657fe5b6020026020010151602001516020015160405180604001604052808d81526020018f8c815181106126b357fe5b602002602001015160200151600001518152506040518663ffffffff1660e01b81526004016126e6959493929190614141565b600060405180830381600087803b15801561270057600080fd5b505af1158015612714573d6000803e3d6000fd5b50505050600460009054906101000a90046001600160a01b03166001600160a01b031663158a03428a85848c898151811061274b57fe5b60200260200101516020015160200151600001518d8a8151811061276b57fe5b60200260200101516020015160200151602001518b6040518763ffffffff1660e01b81526004016127a196959493929190614183565b600060405180830381600087803b1580156127bb57600080fd5b505af11580156127cf573d6000803e3d6000fd5b505050507f64fcac3c2b1ccc98d3039b49f7668a97654165a070c78fa3163859e4d5d0978089828a878151811061280257fe5b602002602001015160200151600001518b888151811061281e57fe5b60200260200101516020015160200151600001518c898151811061283e57fe5b602002602001015160200151602001516020015160405161286395949392919061428b565b60405180910390a15b505b50505b6001016121dc565b505050505050565b600061288f868686866128a8565b61289b878787866128a8565b0390505b95945050505050565b6000806128b78686868661293d565b509150505b949350505050565b60008082121580156128d857508282840313155b806128ef57506000821280156128ef575082828403135b6128f857600080fd5b50900390565b60008282018183128015906129135750838112155b80612928575060008312801561292857508381125b610f0d57600080fd5b6000828211156128f857fe5b600080600080876001600160a01b031663a246138c888a6001600160a01b031663ded113106040518163ffffffff1660e01b815260040160206040518083038186803b15801561298c57600080fd5b505afa1580156129a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129c491908101906134a4565b895160208b01516040516001600160e01b031960e087901b1681526129f194939291908c906004016140ca565b604080518083038186803b158015612a0857600080fd5b505afa158015612a1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a40919081019061351c565b91509150600080896001600160a01b031663a246138c8a8c6001600160a01b0316634652ec746040518163ffffffff1660e01b815260040160206040518083038186803b158015612a9057600080fd5b505afa158015612aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612ac891908101906134a4565b8b5160208d01516040516001600160e01b031960e087901b168152612af594939291908e906004016140ca565b604080518083038186803b158015612b0c57600080fd5b505afa158015612b20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612b44919081019061351c565b9092509050612b59848363ffffffff6128fe16565b60405163a682d5ad60e01b8152909650730ff948c236c8d4dfcd0168bf243314c8ff8ec9679063a682d5ad90612b9590869085906004016145db565b60206040518083038186803b158015612bad57600080fd5b505af4158015612bc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612be591908101906134a4565b94505050505094509492505050565b604080516080810182526060815260006020820152908101612c14612c26565b8152602001612c21612c26565b905290565b60405180606001604052806000815260200160006001600160a01b03168152602001600081525090565b8035610f1081614708565b8051610f1081614708565b600082601f830112612c7757600080fd5b8135612c8a612c858261460f565b6145e9565b91508181835260208401935060208101905083856080840282011115612caf57600080fd5b60005b83811015612cdd5781612cc58882612ef7565b84525060209092019160809190910190600101612cb2565b5050505092915050565b8051610f108161471c565b8035610f1081614725565b8051610f1081614725565b8035610f108161472e565b8051610f108161472e565b8051610f1081614737565b600082601f830112612d3a57600080fd5b8135612d48612c858261462f565b91508082526020830160208301858383011115612d6457600080fd5b612d6f8382846146b9565b50505092915050565b600082601f830112612d8957600080fd5b8151612d97612c858261462f565b91508082526020830160208301858383011115612db357600080fd5b612d6f8382846146c5565b600060408284031215612dd057600080fd5b612dda60406145e9565b90506000612de88484612c50565b8252506020612df984848301612cf2565b60208301525092915050565b600060408284031215612e1757600080fd5b612e2160406145e9565b90506000612de88484612cf2565b600060608284031215612e4157600080fd5b612e4b60406145e9565b90506000612e598484612cf2565b8252506020612df984848301612dbe565b600060408284031215612e7c57600080fd5b612e8660406145e9565b90506000612e948484612cfd565b8252506020612df984848301612cfd565b600060408284031215612eb757600080fd5b612ec160406145e9565b90506000612ecf8484612cf2565b82525060208201356001600160401b03811115612eeb57600080fd5b612df984828501612d29565b600060808284031215612f0957600080fd5b612f1360406145e9565b90506000612f218484612cf2565b8252506020612df984848301612e2f565b600060a08284031215612f4457600080fd5b612f4e60806145e9565b90506000612f5c8484612cf2565b8252506020612f6d84848301612c50565b6020830152506040612f8184828501612e05565b60408301525060808201356001600160401b03811115612fa057600080fd5b612fac84828501613323565b60608301525092915050565b600060c08284031215612fca57600080fd5b612fd460a06145e9565b90506000612fe28484612cf2565b8252506020612ff384848301612c50565b602083015250604061300784828501612e05565b60408301525060808201356001600160401b0381111561302657600080fd5b613032848285016132d1565b60608301525060a08201356001600160401b0381111561305157600080fd5b61305d84828501612d29565b60808301525092915050565b6000610220828403121561307c57600080fd5b6130876101006145e9565b905060006130958484612cf2565b82525060206130a684848301612dbe565b60208301525060608201356001600160401b038111156130c557600080fd5b6130d184828501612fb8565b60408301525060808201356001600160401b038111156130f057600080fd5b6130fc84828501612f32565b60608301525060a061311084828501612e05565b60808301525060e06131248482850161336c565b60a0830152506101e061313984828501612cf2565b60c0830152506102008201356001600160401b0381111561315957600080fd5b61316584828501612ea5565b60e08301525092915050565b60006080828403121561318357600080fd5b61318d60406145e9565b9050600061319b8484612cf2565b8252506020612df984848301613282565b6000606082840312156131be57600080fd5b6131c860606145e9565b905060006131d68484612cfd565b82525060206131e784848301612c5b565b60208301525060406131fb84828501612cfd565b60408301525092915050565b6000610100828403121561321a57600080fd5b61322460806145e9565b82519091506001600160401b0381111561323d57600080fd5b61324984828501612d78565b825250602061325a84848301612cfd565b602083015250604061326e848285016131ac565b60408301525060a0612fac848285016131ac565b60006060828403121561329457600080fd5b61329e60606145e9565b905060006132ac8484612cf2565b82525060206132bd84848301612cf2565b60208301525060406131fb848285016133a8565b6000608082840312156132e357600080fd5b6132ed60406145e9565b905060006132fb8484612e2f565b82525060608201356001600160401b0381111561331757600080fd5b612df984828501612c66565b60006020828403121561333557600080fd5b61333f60206145e9565b905081356001600160401b0381111561335757600080fd5b61336384828501612c66565b82525092915050565b6000610100828403121561337f57600080fd5b61338960406145e9565b905060006133978484613171565b8252506080612df984848301613171565b8035610f1081614744565b6000602082840312156133c557600080fd5b60006128bc8484612c50565b6000806000606084860312156133e657600080fd5b60006133f28686612c50565b93505060208401356001600160401b0381111561340e57600080fd5b61341a86828701613069565b92505060408401356001600160401b0381111561343657600080fd5b61344286828701612d29565b9150509250925092565b6000806040838503121561345f57600080fd5b600061346b8585612c50565b925050602061347c85828601612cf2565b9150509250929050565b60006020828403121561349857600080fd5b60006128bc8484612ce7565b6000602082840312156134b657600080fd5b60006128bc8484612cfd565b6000602082840312156134d457600080fd5b60006128bc8484612d08565b6000602082840312156134f257600080fd5b60006128bc8484612d13565b60006020828403121561351057600080fd5b60006128bc8484612d1e565b6000806040838503121561352f57600080fd5b600061353b8585612cfd565b925050602061347c85828601612cfd565b60006020828403121561355e57600080fd5b81516001600160401b0381111561357457600080fd5b6128bc84828501612d78565b60006040828403121561359257600080fd5b60006128bc8484612e6a565b600080604083850312156135b157600080fd5b82356001600160401b038111156135c757600080fd5b6135d385828601613069565b92505060208301356001600160401b038111156135ef57600080fd5b61347c85828601612d29565b60006020828403121561360d57600080fd5b81516001600160401b0381111561362357600080fd5b6128bc84828501613207565b600061363b8383613d1c565b505060800190565b61364c816146a3565b82525050565b61364c81614669565b60006136668261465c565b6136708185614660565b935061367b83614656565b8060005b838110156136a9578151613693888261362f565b975061369e83614656565b92505060010161367f565b509495945050505050565b61364c81614674565b61364c81614679565b61364c8161467c565b61364c816146ae565b60006136e38261465c565b6136ed8185614660565b93506136fd8185602086016146c5565b613706816146f1565b9093019392505050565b600061371d604083614660565b7f536574746c656d656e7420706172747920616c726561647920646f6e65205b4481527f72696970536574746c656d656e7442795061796d656e742e736f6c3a3234375d602082015260400192915050565b600061377c603d83614660565b7f50726f706f73616c20666f756e64206e6f742065787069726564205b4472696981527f70536574746c656d656e7442795061796d656e742e736f6c3a3232345d000000602082015260400192915050565b60006137db603583614660565b7f44617461206e6f7420617661696c61626c65205b4472696970536574746c656d815274656e7442795061796d656e742e736f6c3a3233375d60581b602082015260400192915050565b6000613832603083614660565b7f42616c616e636520747261636b65722066726f7a656e205b42616c616e63655481526f7261636b61626c652e736f6c3a34335d60801b602082015260400192915050565b6000613884602d83614660565b7f57616c6c6574206e6f74207061796d656e74207061727479205b56616c69646181526c7461626c652e736f6c3a37305d60981b602082015260400192915050565b60006138d3603c83614660565b7f50726f706f73616c20666f756e64207465726d696e61746564205b447269697081527b536574746c656d656e7442795061796d656e742e736f6c3a3231385d60201b602082015260400192915050565b6000613931603f83614660565b7f57616c6c6574206465656d656420646f75626c65207370656e646572205b447281527f696970536574746c656d656e7442795061796d656e742e736f6c3a3139345d00602082015260400192915050565b6000613990602f83614660565b7f436f6d6d756e69747920766f74652066726f7a656e205b436f6d6d756e69747981526e566f7461626c652e736f6c3a34315d60881b602082015260400192915050565b60006139e1603c83614660565b7f5061796d656e74206465656d6564206672617564756c656e74205b447269697081527b536574746c656d656e7442795061796d656e742e736f6c3a3139305d60201b602082015260400192915050565b6000613a3f603e83614660565b7f4e6f74206e6f726d616c206f7065726174696f6e616c206d6f6465205b44726981527f6970536574746c656d656e7442795061796d656e742e736f6c3a3233365d0000602082015260400192915050565b6000613a9e603683614660565b7f57616c6c657420666f756e64206c6f636b6564205b4472696970536574746c658152756d656e7442795061796d656e742e736f6c3a3230305d60501b602082015260400192915050565b6000613af6603983614660565b7f5061796d656e74206e6f74206368616c6c656e676564205b4472696970536574815278746c656d656e7442795061796d656e742e736f6c3a3230335d60381b602082015260400192915050565b6000613b51603483614660565b7f4e6f2070726f706f73616c20666f756e64205b4472696970536574746c656d658152736e7442795061796d656e742e736f6c3a3231325d60601b602082015260400192915050565b6000613ba7603f83614660565b7f50726f706f73616c20666f756e64206e6f74207175616c6966696564205b447281527f696970536574746c656d656e7442795061796d656e742e736f6c3a3233305d00602082015260400192915050565b6000613c06602e83614660565b7f5061796d656e74207365616c73206e6f742067656e75696e65205b56616c696481526d617461626c652e736f6c3a36355d60901b602082015260400192915050565b6000613c56602c83614660565b7f57616c6c6574206c6f636b65722066726f7a656e205b57616c6c65744c6f636b81526b61626c652e736f6c3a34335d60a01b602082015260400192915050565b80516040830190613ca88482613652565b5060208201516104f060208501826136bd565b80516040830190613ca884826136bd565b80516060830190613cdd84826136bd565b5060208201516104f06020850182613c97565b80516000906040840190613d0485826136bd565b506020830151848203602086015261289f82826136d8565b80516080830190613d2d84826136bd565b5060208201516104f06020850182613ccc565b805160009060a0840190613d5485826136bd565b506020830151613d676020860182613652565b506040830151613d7a6040860182613cbb565b506060830151848203608086015261289f8282613fc7565b805160009060c0840190613da685826136bd565b506020830151613db96020860182613652565b506040830151613dcc6040860182613cbb565b5060608301518482036080860152613de48282613f9b565b915050608083015184820360a086015261289f82826136d8565b8051600090610220840190613e1385826136bd565b506020830151613e266020860182613c97565b5060408301518482036060860152613e3e8282613d92565b91505060608301518482036080860152613e588282613d40565b9150506080830151613e6d60a0860182613cbb565b5060a0830151613e8060e0860182613fdf565b5060c0830151613e946101e08601826136bd565b5060e083015184820361020086015261289f8282613cf0565b80516080830190613ebe84826136bd565b5060208201516104f06020850182613f64565b80516060830190613ee284826136bd565b506020820151613ef56020850182613652565b5060408201516104f060408501826136bd565b805161010080845260009190840190613f2182826136d8565b9150506020830151613f3660208601826136bd565b506040830151613f496040860182613ed1565b506060830151613f5c60a0860182613ed1565b509392505050565b80516060830190613f7584826136bd565b506020820151613f8860208501826136bd565b5060408201516104f06040850182614004565b80516000906080840190613faf8582613ccc565b506020830151848203606086015261289f828261365b565b805160208084526000919084019061289f828261365b565b8051610100830190613ff18482613ead565b5060208201516104f06080850182613ead565b61364c8161469d565b60208101610f108284613652565b60208101610f108284613643565b608081016140378287613643565b6140446020830186613652565b81810360408301526140568185613dfe565b9050818103606083015261406a81846136d8565b9695505050505050565b606081016140828286613643565b81810360208301526140948185613dfe565b9050818103604083015261289f81846136d8565b604081016140b68285613652565b6140c36020830184613652565b9392505050565b60a081016140d88288613652565b6140e560208301876136bd565b6140f26040830186613652565b6140ff60608301856136bd565b61406a60808301846136bd565b60a0810161411a8287613652565b61412760208301866136c6565b6141346040830185613652565b61289f6060830184613c97565b60e0810161414f8288613652565b61415c60208301876136c6565b6141696040830186613652565b6141766060830185613c97565b61406a60a0830184613cbb565b60c081016141918289613652565b61419e60208301886136c6565b6141ab60408301876136bd565b6141b86060830186613652565b6141c560808301856136bd565b81810360a08301526141d781846136d8565b98975050505050505050565b60a081016141f18288613652565b6141fe60208301876136bd565b61420b6040830186613652565b61421860608301856136bd565b818103608083015261422a81846136d8565b979650505050505050565b60c081016142438289613652565b61425060208301886136bd565b61425d6040830187613652565b61426a60608301866136bd565b818103608083015261427c81856136d8565b905061422a60a08301846136bd565b60a081016142998288613652565b6142a660208301876136bd565b6142b360408301866136bd565b6140ff6060830185613652565b60a081016142ce8287613652565b6142db60208301866136bd565b6142e86040830185613c97565b61289f60808301846136bd565b606081016143038285613652565b6140c36020830184613c97565b6080810161431e8286613652565b61432b6020830185613c97565b6128bc60608301846136b4565b608081016143468286613652565b6143536020830185613c97565b6128bc60608301846136bd565b6040810161436e8285613652565b6140c360208301846136bd565b606081016143898286613652565b61439660208301856136bd565b6128bc60408301846136cf565b608081016143b18287613652565b6143be60208301866136bd565b6143cb60408301856136cf565b61289f60608301846136b4565b608081016143e68286613652565b6143f360208301856136bd565b6128bc6040830184613c97565b60208101610f1082846136b4565b60208101610f1082846136bd565b60208101610f1082846136c6565b6040810161443882856136c6565b6140c360208301846136c6565b60c0808252810161445681896136d8565b905061446560208301886136bd565b6144726040830187613652565b61447f60608301866136bd565b61448c6080830185613652565b61422a60a08301846136bd565b6020808252810161118281613710565b602080825281016111828161376f565b60208082528101611182816137ce565b6020808252810161118281613825565b6020808252810161118281613877565b60208082528101611182816138c6565b6020808252810161118281613924565b6020808252810161118281613983565b60208082528101611182816139d4565b6020808252810161118281613a32565b6020808252810161118281613a91565b6020808252810161118281613ae9565b6020808252810161118281613b44565b6020808252810161118281613b9a565b6020808252810161118281613bf9565b6020808252810161118281613c49565b60208082528101610f0d8184613dfe565b604080825281016145bb8185613dfe565b90506140c36020830184613652565b60208082528101610f0d8184613f08565b6040810161436e82856136bd565b6040518181016001600160401b038111828210171561460757600080fd5b604052919050565b60006001600160401b0382111561462557600080fd5b5060209081020190565b60006001600160401b0382111561464557600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b600061118282614691565b151590565b90565b600061118282614669565b80611185816146fb565b6001600160a01b031690565b60ff1690565b60006111828261467c565b600061118282614687565b82818337506000910152565b60005b838110156146e05781810151838201526020016146c8565b838111156104f05750506000910152565b601f01601f191690565b6002811061470557fe5b50565b61471181614669565b811461470557600080fd5b61471181614674565b61471181614679565b6147118161467c565b6002811061470557600080fd5b6147118161469d56fea365627a7a7231582024448d33b6dd20e2fca9b1c67e91baa5019c153e77804bf494e2ddeabfed11b36c6578706572696d656e74616cf564736f6c634300050b0040000000000000000000000000f05179bac3d1fbef58a2fcd7ad0f769840027cc6
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101ee5760003560e01c806301370d06146101f35780631327d3d814610208578063191390921461021b578063240625d81461023957806325c844411461024e5780632738a112146102565780632aa1c9d91461025e5780632f013a00146102715780633a5381b5146102795780633bd7857f146102815780633e59b70614610289578063404e896f146102915780634476d23b146102a457806351d7cd61146102b9578063570ca735146102c15780635736db99146102c9578063598b75ad146102dc5780635dc60def146102ef578063627f09c3146102f7578063670732a71461030a5780636c70bee91461031257806370327ea11461031a578063892860b2146103225780638aa96f26146103355780638c6913bc1461033d5780638e9d6cbd1461035257806395ff296d1461035a5780639621473514610362578063b0c8e20514610375578063b3ab15fb14610388578063b52d470a1461039b578063b71ded2f146103a3578063bf24e7d0146103b6578063c0ffe1b4146103be578063d2f08936146103de578063d5f39488146103f1578063dd3056ca146103f9578063e754476f1461040c578063e86ab8f614610414578063e8ae41e314610427578063f152dd381461042f578063f345fb4414610442575b600080fd5b6102066102013660046134c2565b610455565b005b6102066102163660046134c2565b6104f6565b610223610587565b604051610230919061441c565b60405180910390f35b610241610596565b6040516102309190614400565b6102236105a6565b6102066105b5565b61020661026c3660046134c2565b61061b565b6102416106a2565b6102236106ab565b6102236106ba565b6102416106c9565b61020661029f3660046134c2565b6106d9565b6102ac610753565b604051610230919061400d565b610223610767565b6102ac610776565b6102066102d73660046134c2565b610785565b6102066102ea3660046134c2565b610816565b6102066108da565b6102066103053660046134c2565b610929565b6102066109ba565b610223610a09565b610206610a18565b6102066103303660046134c2565b610a7b565b610223610b36565b610345610b45565b604051610230919061440e565b610241610bc7565b610223610bd7565b6102066103703660046133b3565b610be6565b6102066103833660046133d1565b610c9c565b6102066103963660046133b3565b610ced565b610206610d90565b6102066103b13660046134c2565b610ddf565b610223610e70565b6103d16103cc36600461344c565b610e7f565b60405161023091906145ca565b6103d16103ec36600461344c565b610f16565b6102ac610f50565b61020661040736600461359e565b610f64565b610223610fae565b6102066104223660046134c2565b610fbd565b610223611078565b61020661043d3660046134c2565b611087565b6103456104503660046133b3565b611101565b61045d61118a565b61046657600080fd5b806001600160a01b03811661047a57600080fd5b60075482906001600160a01b0390811690821681146104f057600780546001600160a01b038681166001600160a01b03198316179092556040519116907f07998fa7be97abe2427246ae4688298c89d6196bbffdf0997b9495a8d27bc673906104e6908390889061442a565b60405180910390a1505b50505050565b6104fe61118a565b61050757600080fd5b806001600160a01b03811661051b57600080fd5b60035482906001600160a01b0390811690821681146104f057600380546001600160a01b038681166001600160a01b03198316179092556040519116907f1882af944a16549c3d4f60e3cd26f158b0c7aac3222cf32971fc21375ce05f60906104e6908390889061442a565b6005546001600160a01b031681565b600854600160a01b900460ff1681565b600b546001600160a01b031681565b336105be610753565b6001600160a01b0316146105d157600080fd5b60005460ff16156105e157600080fd5b7f787a5d936e74f4b564b9153575886059829c78cd9927b1be5e0d976b317ef73633604051610610919061401b565b60405180910390a133ff5b61062361118a565b61062c57600080fd5b806001600160a01b03811661064057600080fd5b600a80546001600160a01b038481166001600160a01b031983161792839055604051918116927f4f7125332801996cdeaabf9cff1ac89ddf4b52c673558936affe853ab64a88da92610695928592169061442a565b60405180910390a1505050565b60005460ff1681565b6003546001600160a01b031681565b6007546001600160a01b031681565b600554600160a01b900460ff1681565b6106e161118a565b6106ea57600080fd5b806001600160a01b0381166106fe57600080fd5b600b80546001600160a01b038481166001600160a01b031983161792839055604051918116927f6d4735156f5fb1047cfcd4a9edf19e3291aec19d53916f8fee650ca3c2d7391092610695928592169061442a565b60005461010090046001600160a01b031690565b600a546001600160a01b031681565b6001546001600160a01b031681565b61078d61118a565b61079657600080fd5b806001600160a01b0381166107aa57600080fd5b60095482906001600160a01b0390811690821681146104f057600980546001600160a01b038681166001600160a01b03198316179092556040519116907febf60ff5929740b0a97ee47e911fae91589cc49afdca90ec269737058e7fab91906104e6908390889061442a565b61081e61118a565b61082757600080fd5b806001600160a01b03811661083b57600080fd5b60055482906001600160a01b0390811690821681146104f057600554600160a01b900460ff16156108875760405162461bcd60e51b815260040161087e906144c9565b60405180910390fd5b600580546001600160a01b038681166001600160a01b03198316179092556040519116907fb2a91d3a71b0c5bc7c083153b3474378e489506ba98bd4ddb1b9056fdc594bb5906104e6908390889061442a565b6108e261118a565b6108eb57600080fd5b6008805460ff60a01b1916600160a01b1790556040517f56ec8900b9c4bf84f4b715a53068ca06961dd49084c07b481931e2c2045346e690600090a1565b61093161118a565b61093a57600080fd5b806001600160a01b03811661094e57600080fd5b60025482906001600160a01b0390811690821681146104f057600280546001600160a01b038681166001600160a01b03198316179092556040519116907f634f61bf00e14adedce330c80c2823e16e184f189ebe853e1ddecc4a268477ff906104e6908390889061442a565b6109c261118a565b6109cb57600080fd5b6006805460ff60a01b1916600160a01b1790556040517fc1668d45f18667fb6eadfbcacfd5cdcc7dd4ecdfc9b0ab8786cfdbad86bb83d890600090a1565b6002546001600160a01b031681565b33610a21610753565b6001600160a01b031614610a3457600080fd5b6000805460ff191660011790556040517fd5a2a04a775c741c2ca0dc46ea7ce4835190e1aaf1ca018def0e82568ec3361690610a7190339061401b565b60405180910390a1565b610a8361118a565b610a8c57600080fd5b806001600160a01b038116610aa057600080fd5b60085482906001600160a01b0390811690821681146104f057600854600160a01b900460ff1615610ae35760405162461bcd60e51b815260040161087e90614589565b600880546001600160a01b038681166001600160a01b03198316179092556040519116907fa44d361e26327b72a7ccbeae801b3c5cd7677ea4fa74168b289e273c46bfecfc906104e6908390889061442a565b6009546001600160a01b031681565b600b546040805163231a44ef60e21b815290516000926001600160a01b031691638c6913bc916004808301926020929190829003018186803b158015610b8a57600080fd5b505afa158015610b9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bc291908101906134a4565b905090565b600654600160a01b900460ff1681565b600c546001600160a01b031681565b610bee61118a565b610bf757600080fd5b806001600160a01b038116610c0b57600080fd5b6001600160a01b038116301415610c2157600080fd5b6000546001600160a01b038381166101009092041614610c9857600080546001600160a01b03848116610100908102610100600160a81b03198416179093556040519290910416907f977e5fa58e458501775e0008d275006294c5249e3c08d1d0e3a9f3acad14f6e49061069590839086906140a8565b5050565b610ca46111a0565b610cad57600080fd5b610cb88383836111b1565b7f2ac9ebc2da0aa92179f0e3daa8d52d8712a3922edda87c72b050c2b089873050338484846040516106959493929190614029565b610cf56111a0565b610cfe57600080fd5b806001600160a01b038116610d1257600080fd5b6001600160a01b038116301415610d2857600080fd5b6001546001600160a01b03838116911614610c9857600180546001600160a01b038481166001600160a01b03198316179092556040519116907f9f611b789425d0d5b90b920f1b2852907dd865c80074a30b1629aaa041d1812c9061069590839086906140a8565b610d9861118a565b610da157600080fd5b6005805460ff60a01b1916600160a01b1790556040517f9c567b65fe8caab5ec7bc979a498a1322c1d4baf01a30727cbca137187560ea290600090a1565b610de761118a565b610df057600080fd5b806001600160a01b038116610e0457600080fd5b60045482906001600160a01b0390811690821681146104f057600480546001600160a01b038681166001600160a01b03198316179092556040519116907f4d96d2a04c886b313bd1e28be6324ed4c8867b3203e512756722f8be0195e16d906104e6908390889061442a565b6006546001600160a01b031681565b610e87612bf4565b600b5460405163303ff86d60e21b81526001600160a01b039091169063c0ffe1b490610eb99086908690600401614360565b60006040518083038186803b158015610ed157600080fd5b505afa158015610ee5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f0d91908101906135fb565b90505b92915050565b610f1e612bf4565b600b54604051636978449b60e11b81526001600160a01b039091169063d2f0893690610eb99086908690600401614360565b60005461010090046001600160a01b031681565b610f6f3383836111b1565b7fb6d612c8f6da6a2956a25a735b6e54de99363dfdb50a02565ab53b1adc65b3d6338383604051610fa293929190614074565b60405180910390a15050565b6004546001600160a01b031681565b610fc561118a565b610fce57600080fd5b806001600160a01b038116610fe257600080fd5b60065482906001600160a01b0390811690821681146104f057600654600160a01b900460ff16156110255760405162461bcd60e51b815260040161087e90614509565b600680546001600160a01b038681166001600160a01b03198316179092556040519116907f624c4d4225a45f5bf8a9755adba1ef9be3464a9970b05a371fb6cca0c0caf204906104e6908390889061442a565b6008546001600160a01b031681565b61108f61118a565b61109857600080fd5b806001600160a01b0381166110ac57600080fd5b600c80546001600160a01b038481166001600160a01b031983161792839055604051918116927f0e0d0aee1efbecb32fba4a76ecc4cae4c9ed1c3ea3459ea8460c53ff4cb09bcf92610695928592169061442a565b600b54604051633cd17ed160e21b81526000916001600160a01b03169063f345fb449061113290859060040161400d565b60206040518083038186803b15801561114a57600080fd5b505afa15801561115e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061118291908101906134a4565b90505b919050565b60005461010090046001600160a01b0316331490565b6001546001600160a01b0316331490565b60035460405163273f8b6560e11b815283916001600160a01b031690634e7f16ca906111e1908490600401614599565b60206040518083038186803b1580156111f957600080fd5b505afa15801561120d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112319190810190613486565b61124d5760405162461bcd60e51b815260040161087e90614579565b60035460405163f59d1a7560e01b8152849186916001600160a01b039091169063f59d1a759061128390859085906004016145aa565b60206040518083038186803b15801561129b57600080fd5b505afa1580156112af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112d39190810190613486565b6112ef5760405162461bcd60e51b815260040161087e906144d9565b60075460a086015160200151516040516310c7a6c160e31b81526001600160a01b039092169163863d3608916113279160040161440e565b60206040518083038186803b15801561133f57600080fd5b505afa158015611353573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113779190810190613486565b156113945760405162461bcd60e51b815260040161087e90614519565b600654604051639243c9db60e01b81526001600160a01b0390911690639243c9db906113c490899060040161400d565b60206040518083038186803b1580156113dc57600080fd5b505afa1580156113f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114149190810190613486565b156114315760405162461bcd60e51b815260040161087e906144f9565b600854604051631293efbb60e21b81526001600160a01b0390911690634a4fbeec9061146190899060040161400d565b60206040518083038186803b15801561147957600080fd5b505afa15801561148d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114b19190810190613486565b156114ce5760405162461bcd60e51b815260040161087e90614539565b600a54602086015160405163da473c5760e01b81526001600160a01b039092169163da473c5791611504918a91906004016142f5565b60206040518083038186803b15801561151c57600080fd5b505afa158015611530573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061155491908101906134a4565b60a086015160200151511461157b5760405162461bcd60e51b815260040161087e90614549565b6000806115888789611ba8565b600a5460208a0151604051636543ade160e01b81529395509193506001600160a01b031691636543ade1916115c3918c9186916004016143d8565b60206040518083038186803b1580156115db57600080fd5b505afa1580156115ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116139190810190613486565b61162f5760405162461bcd60e51b815260040161087e90614559565b600a546020880151604051637ff81c3760e01b81526001600160a01b0390921691637ff81c3791611665918c91906004016142f5565b60206040518083038186803b15801561167d57600080fd5b505afa158015611691573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116b59190810190613486565b156116d25760405162461bcd60e51b815260040161087e906144e9565b600a546020880151604051635482c73560e01b81526001600160a01b0390921691635482c73591611708918c91906004016142f5565b60206040518083038186803b15801561172057600080fd5b505afa158015611734573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117589190810190613486565b6117745760405162461bcd60e51b815260040161087e906144a9565b600a54602088015160405163b6e2fc3360e01b81526001600160a01b039092169163b6e2fc33916117aa918c91906004016142f5565b60206040518083038186803b1580156117c257600080fd5b505afa1580156117d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117fa91908101906134fe565b600181111561180557fe5b156118225760405162461bcd60e51b815260040161087e90614569565b600260009054906101000a90046001600160a01b03166001600160a01b031663f71e860f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561187057600080fd5b505afa158015611884573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118a89190810190613486565b6118c45760405162461bcd60e51b815260040161087e90614529565b600660009054906101000a90046001600160a01b03166001600160a01b031663994e20766040518163ffffffff1660e01b815260040160206040518083038186803b15801561191257600080fd5b505afa158015611926573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061194a9190810190613486565b6119665760405162461bcd60e51b815260040161087e906144b9565b600b60009054906101000a90046001600160a01b03166001600160a01b0316638772531373b99f3f4aacb6e1197a623919103b99f4b41aaef0635174abe96040518163ffffffff1660e01b815260040160006040518083038186803b1580156119ce57600080fd5b505af41580156119e2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a0a919081019061354c565b60a08a0151602090810151516040808d015180840151905160608f015194850151945192516001600160e01b031960e089901b168152611a539695929391929190600401614445565b600060405180830381600087803b158015611a6d57600080fd5b505af1158015611a81573d6000803e3d6000fd5b5050600b546040516309f0ac8560e41b81526001600160a01b039091169250639f0ac8509150611ab9908b908590879060040161437b565b60206040518083038186803b158015611ad157600080fd5b505afa158015611ae5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b099190810190613486565b15611b265760405162461bcd60e51b815260040161087e90614499565b611b338888888486611c57565b600a54602088015160405163524ad18360e11b81526001600160a01b039092169163a495a30691611b6c918c9190600090600401614310565b600060405180830381600087803b158015611b8657600080fd5b505af1158015611b9a573d6000803e3d6000fd5b505050505050505050505050565b60035460405163d308b9db60e01b815260009182916001600160a01b039091169063d308b9db90611bdf90879087906004016145aa565b60206040518083038186803b158015611bf757600080fd5b505afa158015611c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611c2f9190810190613486565b15611c44575050604082015151600090611c50565b50506060820151516001905b9250929050565b6000806060611c668789611feb565b600b5460208b0151604051633858654b60e01b81529497509295509093506000926001600160a01b0390911691633858654b91611ca7918d916004016142f5565b60206040518083038186803b158015611cbf57600080fd5b505afa158015611cd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611cf791908101906134a4565b905085811015611fe057600b546020890151604051630284774760e31b81526001600160a01b0390921691631423ba3891611d39918d91908b90600401614338565b600060405180830381600087803b158015611d5357600080fd5b505af1158015611d67573d6000803e3d6000fd5b5050600480546020808d0151805191015160405163325d23a960e11b81526001600160a01b0390931695506364ba47529450611dad938f938b9392918f91439101614235565b600060405180830381600087803b158015611dc757600080fd5b505af1158015611ddb573d6000803e3d6000fd5b5050600b5460208b015160c08c015160405163fb721b5360e01b81526001600160a01b03909316945063fb721b539350611e1d928e92899290916004016142c0565b600060405180830381600087803b158015611e3757600080fd5b505af1158015611e4b573d6000803e3d6000fd5b505060048054600a5460208d0151604051633007230f60e11b81526001600160a01b03938416965063ad468df995508f94929093169263600e461e92611e959286929091016142f5565b60206040518083038186803b158015611ead57600080fd5b505afa158015611ec1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611ee591908101906134a4565b6020808d015180519101516040516001600160e01b031960e087901b168152611f1694939291908e906004016141e3565b600060405180830381600087803b158015611f3057600080fd5b505af1158015611f44573d6000803e3d6000fd5b5050600c546001600160a01b0316159150611f76905057600c54611f76908a9084906001600160a01b0316898b6121d9565b600b5460405163f8eabcc160e01b81526001600160a01b039091169063f8eabcc190611fad908c908a908a906001906004016143a3565b600060405180830381600087803b158015611fc757600080fd5b505af1158015611fdb573d6000803e3d6000fd5b505050505b505050505050505050565b60035460405163d308b9db60e01b815260009182916060916001600160a01b03169063d308b9db9061202390889088906004016145aa565b60206040518083038186803b15801561203b57600080fd5b505afa15801561204f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506120739190810190613486565b1561209657506040808501519081015151606090910151602001519092506120ab565b50606080850151604081015151910151519092505b602085015160c08601516005546000926120da926001600160a01b03909216918891904363ffffffff61288116565b600b54602088015160c089015160405163bc8dd4cd60e01b81529394506000936001600160a01b039093169263bc8dd4cd9261211a928b92600401614338565b60206040518083038186803b15801561213257600080fd5b505afa158015612146573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061216a91908101906134a4565b602088015160c08901516005549293506121b89284926121ac9261219f926001600160a01b0316918c9163ffffffff6128a816565b889063ffffffff6128c416565b9063ffffffff6128c416565b93506121ce816121ac878563ffffffff6128fe16565b945050509250925092565b60005b84518110156128795760008582815181106121f357fe5b6020026020010151600001516000141561220e5750836123f7565b600960009054906101000a90046001600160a01b03166001600160a01b03166367299f366040518163ffffffff1660e01b815260040160206040518083038186803b15801561225c57600080fd5b505afa158015612270573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061229491908101906134a4565b600010801561233f5750600960009054906101000a90046001600160a01b03166001600160a01b03166367299f366040518163ffffffff1660e01b815260040160206040518083038186803b1580156122ec57600080fd5b505afa158015612300573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061232491908101906134a4565b86838151811061233057fe5b60200260200101516000015111155b156123f75760095486516001600160a01b039091169063efeb5e5890612388906001908a908790811061236e57fe5b60200260200101516000015161293190919063ffffffff16565b6040518263ffffffff1660e01b81526004016123a4919061440e565b60206040518083038186803b1580156123bc57600080fd5b505afa1580156123d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506123f491908101906134e0565b90505b6001600160a01b03811661240b5750612871565b600086838151811061241957fe5b602002602001015160000151905084600b60009054906101000a90046001600160a01b03166001600160a01b0316636e17226a8a85858c898151811061245b57fe5b602002602001015160200151602001516040518563ffffffff1660e01b815260040161248a949392919061410c565b604080518083038186803b1580156124a157600080fd5b505afa1580156124b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124d99190810190613580565b51101561286e5760006125c4600b60009054906101000a90046001600160a01b03166001600160a01b0316636e17226a8b86868d8a8151811061251857fe5b602002602001015160200151602001516040518563ffffffff1660e01b8152600401612547949392919061410c565b604080518083038186803b15801561255e57600080fd5b505afa158015612572573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125969190810190613580565b602001518986815181106125a657fe5b602002602001015160200151600001516128c490919063ffffffff16565b6040516351750e5360e11b8152909150732fcb98529d58669e229c453de4b4705bb6b2d4149063a2ea1ca6906125fe90849060040161440e565b60206040518083038186803b15801561261657600080fd5b505af415801561262a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061264e9190810190613486565b1561286c57600b60009054906101000a90046001600160a01b03166001600160a01b0316637657768c8a85858c898151811061268657fe5b6020026020010151602001516020015160405180604001604052808d81526020018f8c815181106126b357fe5b602002602001015160200151600001518152506040518663ffffffff1660e01b81526004016126e6959493929190614141565b600060405180830381600087803b15801561270057600080fd5b505af1158015612714573d6000803e3d6000fd5b50505050600460009054906101000a90046001600160a01b03166001600160a01b031663158a03428a85848c898151811061274b57fe5b60200260200101516020015160200151600001518d8a8151811061276b57fe5b60200260200101516020015160200151602001518b6040518763ffffffff1660e01b81526004016127a196959493929190614183565b600060405180830381600087803b1580156127bb57600080fd5b505af11580156127cf573d6000803e3d6000fd5b505050507f64fcac3c2b1ccc98d3039b49f7668a97654165a070c78fa3163859e4d5d0978089828a878151811061280257fe5b602002602001015160200151600001518b888151811061281e57fe5b60200260200101516020015160200151600001518c898151811061283e57fe5b602002602001015160200151602001516020015160405161286395949392919061428b565b60405180910390a15b505b50505b6001016121dc565b505050505050565b600061288f868686866128a8565b61289b878787866128a8565b0390505b95945050505050565b6000806128b78686868661293d565b509150505b949350505050565b60008082121580156128d857508282840313155b806128ef57506000821280156128ef575082828403135b6128f857600080fd5b50900390565b60008282018183128015906129135750838112155b80612928575060008312801561292857508381125b610f0d57600080fd5b6000828211156128f857fe5b600080600080876001600160a01b031663a246138c888a6001600160a01b031663ded113106040518163ffffffff1660e01b815260040160206040518083038186803b15801561298c57600080fd5b505afa1580156129a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129c491908101906134a4565b895160208b01516040516001600160e01b031960e087901b1681526129f194939291908c906004016140ca565b604080518083038186803b158015612a0857600080fd5b505afa158015612a1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a40919081019061351c565b91509150600080896001600160a01b031663a246138c8a8c6001600160a01b0316634652ec746040518163ffffffff1660e01b815260040160206040518083038186803b158015612a9057600080fd5b505afa158015612aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612ac891908101906134a4565b8b5160208d01516040516001600160e01b031960e087901b168152612af594939291908e906004016140ca565b604080518083038186803b158015612b0c57600080fd5b505afa158015612b20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612b44919081019061351c565b9092509050612b59848363ffffffff6128fe16565b60405163a682d5ad60e01b8152909650730ff948c236c8d4dfcd0168bf243314c8ff8ec9679063a682d5ad90612b9590869085906004016145db565b60206040518083038186803b158015612bad57600080fd5b505af4158015612bc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612be591908101906134a4565b94505050505094509492505050565b604080516080810182526060815260006020820152908101612c14612c26565b8152602001612c21612c26565b905290565b60405180606001604052806000815260200160006001600160a01b03168152602001600081525090565b8035610f1081614708565b8051610f1081614708565b600082601f830112612c7757600080fd5b8135612c8a612c858261460f565b6145e9565b91508181835260208401935060208101905083856080840282011115612caf57600080fd5b60005b83811015612cdd5781612cc58882612ef7565b84525060209092019160809190910190600101612cb2565b5050505092915050565b8051610f108161471c565b8035610f1081614725565b8051610f1081614725565b8035610f108161472e565b8051610f108161472e565b8051610f1081614737565b600082601f830112612d3a57600080fd5b8135612d48612c858261462f565b91508082526020830160208301858383011115612d6457600080fd5b612d6f8382846146b9565b50505092915050565b600082601f830112612d8957600080fd5b8151612d97612c858261462f565b91508082526020830160208301858383011115612db357600080fd5b612d6f8382846146c5565b600060408284031215612dd057600080fd5b612dda60406145e9565b90506000612de88484612c50565b8252506020612df984848301612cf2565b60208301525092915050565b600060408284031215612e1757600080fd5b612e2160406145e9565b90506000612de88484612cf2565b600060608284031215612e4157600080fd5b612e4b60406145e9565b90506000612e598484612cf2565b8252506020612df984848301612dbe565b600060408284031215612e7c57600080fd5b612e8660406145e9565b90506000612e948484612cfd565b8252506020612df984848301612cfd565b600060408284031215612eb757600080fd5b612ec160406145e9565b90506000612ecf8484612cf2565b82525060208201356001600160401b03811115612eeb57600080fd5b612df984828501612d29565b600060808284031215612f0957600080fd5b612f1360406145e9565b90506000612f218484612cf2565b8252506020612df984848301612e2f565b600060a08284031215612f4457600080fd5b612f4e60806145e9565b90506000612f5c8484612cf2565b8252506020612f6d84848301612c50565b6020830152506040612f8184828501612e05565b60408301525060808201356001600160401b03811115612fa057600080fd5b612fac84828501613323565b60608301525092915050565b600060c08284031215612fca57600080fd5b612fd460a06145e9565b90506000612fe28484612cf2565b8252506020612ff384848301612c50565b602083015250604061300784828501612e05565b60408301525060808201356001600160401b0381111561302657600080fd5b613032848285016132d1565b60608301525060a08201356001600160401b0381111561305157600080fd5b61305d84828501612d29565b60808301525092915050565b6000610220828403121561307c57600080fd5b6130876101006145e9565b905060006130958484612cf2565b82525060206130a684848301612dbe565b60208301525060608201356001600160401b038111156130c557600080fd5b6130d184828501612fb8565b60408301525060808201356001600160401b038111156130f057600080fd5b6130fc84828501612f32565b60608301525060a061311084828501612e05565b60808301525060e06131248482850161336c565b60a0830152506101e061313984828501612cf2565b60c0830152506102008201356001600160401b0381111561315957600080fd5b61316584828501612ea5565b60e08301525092915050565b60006080828403121561318357600080fd5b61318d60406145e9565b9050600061319b8484612cf2565b8252506020612df984848301613282565b6000606082840312156131be57600080fd5b6131c860606145e9565b905060006131d68484612cfd565b82525060206131e784848301612c5b565b60208301525060406131fb84828501612cfd565b60408301525092915050565b6000610100828403121561321a57600080fd5b61322460806145e9565b82519091506001600160401b0381111561323d57600080fd5b61324984828501612d78565b825250602061325a84848301612cfd565b602083015250604061326e848285016131ac565b60408301525060a0612fac848285016131ac565b60006060828403121561329457600080fd5b61329e60606145e9565b905060006132ac8484612cf2565b82525060206132bd84848301612cf2565b60208301525060406131fb848285016133a8565b6000608082840312156132e357600080fd5b6132ed60406145e9565b905060006132fb8484612e2f565b82525060608201356001600160401b0381111561331757600080fd5b612df984828501612c66565b60006020828403121561333557600080fd5b61333f60206145e9565b905081356001600160401b0381111561335757600080fd5b61336384828501612c66565b82525092915050565b6000610100828403121561337f57600080fd5b61338960406145e9565b905060006133978484613171565b8252506080612df984848301613171565b8035610f1081614744565b6000602082840312156133c557600080fd5b60006128bc8484612c50565b6000806000606084860312156133e657600080fd5b60006133f28686612c50565b93505060208401356001600160401b0381111561340e57600080fd5b61341a86828701613069565b92505060408401356001600160401b0381111561343657600080fd5b61344286828701612d29565b9150509250925092565b6000806040838503121561345f57600080fd5b600061346b8585612c50565b925050602061347c85828601612cf2565b9150509250929050565b60006020828403121561349857600080fd5b60006128bc8484612ce7565b6000602082840312156134b657600080fd5b60006128bc8484612cfd565b6000602082840312156134d457600080fd5b60006128bc8484612d08565b6000602082840312156134f257600080fd5b60006128bc8484612d13565b60006020828403121561351057600080fd5b60006128bc8484612d1e565b6000806040838503121561352f57600080fd5b600061353b8585612cfd565b925050602061347c85828601612cfd565b60006020828403121561355e57600080fd5b81516001600160401b0381111561357457600080fd5b6128bc84828501612d78565b60006040828403121561359257600080fd5b60006128bc8484612e6a565b600080604083850312156135b157600080fd5b82356001600160401b038111156135c757600080fd5b6135d385828601613069565b92505060208301356001600160401b038111156135ef57600080fd5b61347c85828601612d29565b60006020828403121561360d57600080fd5b81516001600160401b0381111561362357600080fd5b6128bc84828501613207565b600061363b8383613d1c565b505060800190565b61364c816146a3565b82525050565b61364c81614669565b60006136668261465c565b6136708185614660565b935061367b83614656565b8060005b838110156136a9578151613693888261362f565b975061369e83614656565b92505060010161367f565b509495945050505050565b61364c81614674565b61364c81614679565b61364c8161467c565b61364c816146ae565b60006136e38261465c565b6136ed8185614660565b93506136fd8185602086016146c5565b613706816146f1565b9093019392505050565b600061371d604083614660565b7f536574746c656d656e7420706172747920616c726561647920646f6e65205b4481527f72696970536574746c656d656e7442795061796d656e742e736f6c3a3234375d602082015260400192915050565b600061377c603d83614660565b7f50726f706f73616c20666f756e64206e6f742065787069726564205b4472696981527f70536574746c656d656e7442795061796d656e742e736f6c3a3232345d000000602082015260400192915050565b60006137db603583614660565b7f44617461206e6f7420617661696c61626c65205b4472696970536574746c656d815274656e7442795061796d656e742e736f6c3a3233375d60581b602082015260400192915050565b6000613832603083614660565b7f42616c616e636520747261636b65722066726f7a656e205b42616c616e63655481526f7261636b61626c652e736f6c3a34335d60801b602082015260400192915050565b6000613884602d83614660565b7f57616c6c6574206e6f74207061796d656e74207061727479205b56616c69646181526c7461626c652e736f6c3a37305d60981b602082015260400192915050565b60006138d3603c83614660565b7f50726f706f73616c20666f756e64207465726d696e61746564205b447269697081527b536574746c656d656e7442795061796d656e742e736f6c3a3231385d60201b602082015260400192915050565b6000613931603f83614660565b7f57616c6c6574206465656d656420646f75626c65207370656e646572205b447281527f696970536574746c656d656e7442795061796d656e742e736f6c3a3139345d00602082015260400192915050565b6000613990602f83614660565b7f436f6d6d756e69747920766f74652066726f7a656e205b436f6d6d756e69747981526e566f7461626c652e736f6c3a34315d60881b602082015260400192915050565b60006139e1603c83614660565b7f5061796d656e74206465656d6564206672617564756c656e74205b447269697081527b536574746c656d656e7442795061796d656e742e736f6c3a3139305d60201b602082015260400192915050565b6000613a3f603e83614660565b7f4e6f74206e6f726d616c206f7065726174696f6e616c206d6f6465205b44726981527f6970536574746c656d656e7442795061796d656e742e736f6c3a3233365d0000602082015260400192915050565b6000613a9e603683614660565b7f57616c6c657420666f756e64206c6f636b6564205b4472696970536574746c658152756d656e7442795061796d656e742e736f6c3a3230305d60501b602082015260400192915050565b6000613af6603983614660565b7f5061796d656e74206e6f74206368616c6c656e676564205b4472696970536574815278746c656d656e7442795061796d656e742e736f6c3a3230335d60381b602082015260400192915050565b6000613b51603483614660565b7f4e6f2070726f706f73616c20666f756e64205b4472696970536574746c656d658152736e7442795061796d656e742e736f6c3a3231325d60601b602082015260400192915050565b6000613ba7603f83614660565b7f50726f706f73616c20666f756e64206e6f74207175616c6966696564205b447281527f696970536574746c656d656e7442795061796d656e742e736f6c3a3233305d00602082015260400192915050565b6000613c06602e83614660565b7f5061796d656e74207365616c73206e6f742067656e75696e65205b56616c696481526d617461626c652e736f6c3a36355d60901b602082015260400192915050565b6000613c56602c83614660565b7f57616c6c6574206c6f636b65722066726f7a656e205b57616c6c65744c6f636b81526b61626c652e736f6c3a34335d60a01b602082015260400192915050565b80516040830190613ca88482613652565b5060208201516104f060208501826136bd565b80516040830190613ca884826136bd565b80516060830190613cdd84826136bd565b5060208201516104f06020850182613c97565b80516000906040840190613d0485826136bd565b506020830151848203602086015261289f82826136d8565b80516080830190613d2d84826136bd565b5060208201516104f06020850182613ccc565b805160009060a0840190613d5485826136bd565b506020830151613d676020860182613652565b506040830151613d7a6040860182613cbb565b506060830151848203608086015261289f8282613fc7565b805160009060c0840190613da685826136bd565b506020830151613db96020860182613652565b506040830151613dcc6040860182613cbb565b5060608301518482036080860152613de48282613f9b565b915050608083015184820360a086015261289f82826136d8565b8051600090610220840190613e1385826136bd565b506020830151613e266020860182613c97565b5060408301518482036060860152613e3e8282613d92565b91505060608301518482036080860152613e588282613d40565b9150506080830151613e6d60a0860182613cbb565b5060a0830151613e8060e0860182613fdf565b5060c0830151613e946101e08601826136bd565b5060e083015184820361020086015261289f8282613cf0565b80516080830190613ebe84826136bd565b5060208201516104f06020850182613f64565b80516060830190613ee284826136bd565b506020820151613ef56020850182613652565b5060408201516104f060408501826136bd565b805161010080845260009190840190613f2182826136d8565b9150506020830151613f3660208601826136bd565b506040830151613f496040860182613ed1565b506060830151613f5c60a0860182613ed1565b509392505050565b80516060830190613f7584826136bd565b506020820151613f8860208501826136bd565b5060408201516104f06040850182614004565b80516000906080840190613faf8582613ccc565b506020830151848203606086015261289f828261365b565b805160208084526000919084019061289f828261365b565b8051610100830190613ff18482613ead565b5060208201516104f06080850182613ead565b61364c8161469d565b60208101610f108284613652565b60208101610f108284613643565b608081016140378287613643565b6140446020830186613652565b81810360408301526140568185613dfe565b9050818103606083015261406a81846136d8565b9695505050505050565b606081016140828286613643565b81810360208301526140948185613dfe565b9050818103604083015261289f81846136d8565b604081016140b68285613652565b6140c36020830184613652565b9392505050565b60a081016140d88288613652565b6140e560208301876136bd565b6140f26040830186613652565b6140ff60608301856136bd565b61406a60808301846136bd565b60a0810161411a8287613652565b61412760208301866136c6565b6141346040830185613652565b61289f6060830184613c97565b60e0810161414f8288613652565b61415c60208301876136c6565b6141696040830186613652565b6141766060830185613c97565b61406a60a0830184613cbb565b60c081016141918289613652565b61419e60208301886136c6565b6141ab60408301876136bd565b6141b86060830186613652565b6141c560808301856136bd565b81810360a08301526141d781846136d8565b98975050505050505050565b60a081016141f18288613652565b6141fe60208301876136bd565b61420b6040830186613652565b61421860608301856136bd565b818103608083015261422a81846136d8565b979650505050505050565b60c081016142438289613652565b61425060208301886136bd565b61425d6040830187613652565b61426a60608301866136bd565b818103608083015261427c81856136d8565b905061422a60a08301846136bd565b60a081016142998288613652565b6142a660208301876136bd565b6142b360408301866136bd565b6140ff6060830185613652565b60a081016142ce8287613652565b6142db60208301866136bd565b6142e86040830185613c97565b61289f60808301846136bd565b606081016143038285613652565b6140c36020830184613c97565b6080810161431e8286613652565b61432b6020830185613c97565b6128bc60608301846136b4565b608081016143468286613652565b6143536020830185613c97565b6128bc60608301846136bd565b6040810161436e8285613652565b6140c360208301846136bd565b606081016143898286613652565b61439660208301856136bd565b6128bc60408301846136cf565b608081016143b18287613652565b6143be60208301866136bd565b6143cb60408301856136cf565b61289f60608301846136b4565b608081016143e68286613652565b6143f360208301856136bd565b6128bc6040830184613c97565b60208101610f1082846136b4565b60208101610f1082846136bd565b60208101610f1082846136c6565b6040810161443882856136c6565b6140c360208301846136c6565b60c0808252810161445681896136d8565b905061446560208301886136bd565b6144726040830187613652565b61447f60608301866136bd565b61448c6080830185613652565b61422a60a08301846136bd565b6020808252810161118281613710565b602080825281016111828161376f565b60208082528101611182816137ce565b6020808252810161118281613825565b6020808252810161118281613877565b60208082528101611182816138c6565b6020808252810161118281613924565b6020808252810161118281613983565b60208082528101611182816139d4565b6020808252810161118281613a32565b6020808252810161118281613a91565b6020808252810161118281613ae9565b6020808252810161118281613b44565b6020808252810161118281613b9a565b6020808252810161118281613bf9565b6020808252810161118281613c49565b60208082528101610f0d8184613dfe565b604080825281016145bb8185613dfe565b90506140c36020830184613652565b60208082528101610f0d8184613f08565b6040810161436e82856136bd565b6040518181016001600160401b038111828210171561460757600080fd5b604052919050565b60006001600160401b0382111561462557600080fd5b5060209081020190565b60006001600160401b0382111561464557600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b600061118282614691565b151590565b90565b600061118282614669565b80611185816146fb565b6001600160a01b031690565b60ff1690565b60006111828261467c565b600061118282614687565b82818337506000910152565b60005b838110156146e05781810151838201526020016146c8565b838111156104f05750506000910152565b601f01601f191690565b6002811061470557fe5b50565b61471181614669565b811461470557600080fd5b61471181614674565b61471181614679565b6147118161467c565b6002811061470557600080fd5b6147118161469d56fea365627a7a7231582024448d33b6dd20e2fca9b1c67e91baa5019c153e77804bf494e2ddeabfed11b36c6578706572696d656e74616cf564736f6c634300050b0040
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
Libraries Used
PaymentTypesLib : 0xb99f3f4aacb6e1197a623919103b99f4b41aaef0SafeMathIntLib : 0x2fcb98529d58669e229c453de4b4705bb6b2d414SafeMathUintLib : 0x0ff948c236c8d4dfcd0168bf243314c8ff8ec967
Swarm Source
bzzr://24448d33b6dd20e2fca9b1c67e91baa5019c153e77804bf494e2ddeabfed11b3
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 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.