Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 1,206 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transfer | 21181827 | 96 days ago | IN | 0 ETH | 0.00070493 | ||||
Transfer | 21178454 | 97 days ago | IN | 0.0001 ETH | 0.00058926 | ||||
Transfer | 21174859 | 97 days ago | IN | 0 ETH | 0.00058028 | ||||
Transfer | 21174810 | 97 days ago | IN | 0 ETH | 0.00048676 | ||||
Transfer | 21174754 | 97 days ago | IN | 0 ETH | 0.00059449 | ||||
Start Challenge ... | 20046057 | 255 days ago | IN | 0 ETH | 0.002515 | ||||
Start Challenge ... | 20003673 | 261 days ago | IN | 0 ETH | 0.0049045 | ||||
Start Challenge ... | 20003618 | 261 days ago | IN | 0 ETH | 0.00483159 | ||||
Start Challenge ... | 19989728 | 263 days ago | IN | 0 ETH | 0.00760607 | ||||
Start Challenge ... | 19988579 | 263 days ago | IN | 0 ETH | 0.00389531 | ||||
Start Challenge ... | 14990854 | 975 days ago | IN | 0 ETH | 0.01071935 | ||||
Start Challenge ... | 14990834 | 975 days ago | IN | 0 ETH | 0.0129635 | ||||
Start Challenge ... | 14990727 | 975 days ago | IN | 0 ETH | 0.01568167 | ||||
Start Challenge ... | 14990088 | 975 days ago | IN | 0 ETH | 0.01254198 | ||||
Start Challenge ... | 14990070 | 975 days ago | IN | 0 ETH | 0.00847354 | ||||
Start Challenge ... | 14990058 | 975 days ago | IN | 0 ETH | 0.00847354 | ||||
Start Challenge ... | 14990050 | 975 days ago | IN | 0 ETH | 0.00847354 | ||||
Start Challenge ... | 14984467 | 976 days ago | IN | 0 ETH | 0.01271031 | ||||
Start Challenge ... | 14984456 | 976 days ago | IN | 0 ETH | 0.01271031 | ||||
Start Challenge ... | 14984086 | 976 days ago | IN | 0 ETH | 0.01311999 | ||||
Start Challenge ... | 14983875 | 976 days ago | IN | 0 ETH | 0.03111234 | ||||
Start Challenge ... | 14969691 | 978 days ago | IN | 0 ETH | 0.02394295 | ||||
Start Challenge ... | 14963502 | 979 days ago | IN | 0 ETH | 0.03235235 | ||||
Start Challenge ... | 14963475 | 979 days ago | IN | 0 ETH | 0.01498355 | ||||
Start Challenge ... | 14963114 | 979 days ago | IN | 0 ETH | 0.01941213 |
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 Source Code Verified (Exact Match)
Contract Name:
DriipSettlementChallengeByPayment
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]"); _; } } contract ConfigurableOperational is Configurable { modifier onlyOperationalModeNormal() { require(configuration.isOperationalModeNormal(), "Operational mode is not normal [ConfigurableOperational.sol:22]"); _; } } 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 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 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]"); _; } } 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 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 AccrualBeneficiary is Beneficiary { event CloseAccrualPeriodEvent(); function closeAccrualPeriod(MonetaryTypesLib.Currency[] memory) public { emit CloseAccrualPeriodEvent(); } } 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 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; } } contract SecurityBond is Ownable, Configurable, 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 REWARD_ACTION = "reward"; string constant public DEPRIVE_ACTION = "deprive"; struct FractionalReward { uint256 fraction; uint256 nonce; uint256 unlockTime; } struct AbsoluteReward { int256 amount; uint256 nonce; uint256 unlockTime; } FungibleBalanceLib.Balance private deposited; TxHistoryLib.TxHistory private txHistory; CurrenciesLib.Currencies private inUseCurrencies; mapping(address => FractionalReward) public fractionalRewardByWallet; mapping(address => mapping(address => mapping(uint256 => AbsoluteReward))) public absoluteRewardByWallet; mapping(address => mapping(address => mapping(uint256 => uint256))) public claimNonceByWalletCurrency; mapping(address => FungibleBalanceLib.Balance) private stagedByWallet; mapping(address => uint256) public nonceByWallet; event ReceiveEvent(address from, int256 amount, address currencyCt, uint256 currencyId); event RewardFractionalEvent(address wallet, uint256 fraction, uint256 unlockTimeoutInSeconds); event RewardAbsoluteEvent(address wallet, int256 amount, address currencyCt, uint256 currencyId, uint256 unlockTimeoutInSeconds); event DepriveFractionalEvent(address wallet); event DepriveAbsoluteEvent(address wallet, address currencyCt, uint256 currencyId); event ClaimAndTransferToBeneficiaryEvent(address from, Beneficiary beneficiary, 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) Servable() public { } function() external payable { receiveEthersTo(msg.sender, ""); } function receiveEthersTo(address wallet, string memory) public payable { int256 amount = SafeMathIntLib.toNonZeroInt256(msg.value); deposited.add(amount, address(0), 0); txHistory.addDeposit(amount, address(0), 0); inUseCurrencies.add(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 [SecurityBond.sol:145]"); 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 [SecurityBond.sol:154]"); deposited.add(amount, currencyCt, currencyId); txHistory.addDeposit(amount, currencyCt, currencyId); inUseCurrencies.add(currencyCt, currencyId); emit ReceiveEvent(wallet, amount, currencyCt, currencyId); } 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 depositedBalance(address currencyCt, uint256 currencyId) public view returns (int256) { return deposited.get(currencyCt, currencyId); } function depositedFractionalBalance(address currencyCt, uint256 currencyId, uint256 fraction) public view returns (int256) { return deposited.get(currencyCt, currencyId) .mul(SafeMathIntLib.toInt256(fraction)) .div(ConstantsLib.PARTS_PER()); } function stagedBalance(address wallet, address currencyCt, uint256 currencyId) public view returns (int256) { return stagedByWallet[wallet].get(currencyCt, currencyId); } function inUseCurrenciesCount() public view returns (uint256) { return inUseCurrencies.count(); } function inUseCurrenciesByIndices(uint256 low, uint256 up) public view returns (MonetaryTypesLib.Currency[] memory) { return inUseCurrencies.getByIndices(low, up); } function rewardFractional(address wallet, uint256 fraction, uint256 unlockTimeoutInSeconds) public notNullAddress(wallet) onlyEnabledServiceAction(REWARD_ACTION) { fractionalRewardByWallet[wallet].fraction = fraction.clampMax(uint256(ConstantsLib.PARTS_PER())); fractionalRewardByWallet[wallet].nonce = ++nonceByWallet[wallet]; fractionalRewardByWallet[wallet].unlockTime = block.timestamp.add(unlockTimeoutInSeconds); emit RewardFractionalEvent(wallet, fraction, unlockTimeoutInSeconds); } function rewardAbsolute(address wallet, int256 amount, address currencyCt, uint256 currencyId, uint256 unlockTimeoutInSeconds) public notNullAddress(wallet) onlyEnabledServiceAction(REWARD_ACTION) { absoluteRewardByWallet[wallet][currencyCt][currencyId].amount = amount; absoluteRewardByWallet[wallet][currencyCt][currencyId].nonce = ++nonceByWallet[wallet]; absoluteRewardByWallet[wallet][currencyCt][currencyId].unlockTime = block.timestamp.add(unlockTimeoutInSeconds); emit RewardAbsoluteEvent(wallet, amount, currencyCt, currencyId, unlockTimeoutInSeconds); } function depriveFractional(address wallet) public onlyEnabledServiceAction(DEPRIVE_ACTION) { fractionalRewardByWallet[wallet].fraction = 0; fractionalRewardByWallet[wallet].nonce = ++nonceByWallet[wallet]; fractionalRewardByWallet[wallet].unlockTime = 0; emit DepriveFractionalEvent(wallet); } function depriveAbsolute(address wallet, address currencyCt, uint256 currencyId) public onlyEnabledServiceAction(DEPRIVE_ACTION) { absoluteRewardByWallet[wallet][currencyCt][currencyId].amount = 0; absoluteRewardByWallet[wallet][currencyCt][currencyId].nonce = ++nonceByWallet[wallet]; absoluteRewardByWallet[wallet][currencyCt][currencyId].unlockTime = 0; emit DepriveAbsoluteEvent(wallet, currencyCt, currencyId); } function claimAndTransferToBeneficiary(Beneficiary beneficiary, string memory balanceType, address currencyCt, uint256 currencyId, string memory standard) public { int256 claimedAmount = _claim(msg.sender, currencyCt, currencyId); deposited.sub(claimedAmount, currencyCt, currencyId); if (address(0) == currencyCt && 0 == currencyId) beneficiary.receiveEthersTo.value(uint256(claimedAmount))(msg.sender, 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 [SecurityBond.sol:350]"); beneficiary.receiveTokensTo(msg.sender, balanceType, claimedAmount, currencyCt, currencyId, standard); } emit ClaimAndTransferToBeneficiaryEvent(msg.sender, beneficiary, balanceType, claimedAmount, currencyCt, currencyId, standard); } function claimAndStage(address currencyCt, uint256 currencyId) public { int256 claimedAmount = _claim(msg.sender, currencyCt, currencyId); deposited.sub(claimedAmount, 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 [SecurityBond.sol:386]"); 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 [SecurityBond.sol:405]"); } emit WithdrawEvent(msg.sender, amount, currencyCt, currencyId, standard); } function _claim(address wallet, address currencyCt, uint256 currencyId) private returns (int256) { uint256 claimNonce = fractionalRewardByWallet[wallet].nonce.clampMin( absoluteRewardByWallet[wallet][currencyCt][currencyId].nonce ); require( claimNonce > claimNonceByWalletCurrency[wallet][currencyCt][currencyId], "Claim nonce not strictly greater than previously claimed nonce [SecurityBond.sol:425]" ); int256 claimAmount = _fractionalRewardAmountByWalletCurrency(wallet, currencyCt, currencyId).add( _absoluteRewardAmountByWalletCurrency(wallet, currencyCt, currencyId) ).clampMax( deposited.get(currencyCt, currencyId) ); require(claimAmount.isNonZeroPositiveInt256(), "Claim amount not strictly positive [SecurityBond.sol:438]"); claimNonceByWalletCurrency[wallet][currencyCt][currencyId] = claimNonce; return claimAmount; } function _fractionalRewardAmountByWalletCurrency(address wallet, address currencyCt, uint256 currencyId) private view returns (int256) { if ( claimNonceByWalletCurrency[wallet][currencyCt][currencyId] < fractionalRewardByWallet[wallet].nonce && block.timestamp >= fractionalRewardByWallet[wallet].unlockTime ) return deposited.get(currencyCt, currencyId) .mul(SafeMathIntLib.toInt256(fractionalRewardByWallet[wallet].fraction)) .div(ConstantsLib.PARTS_PER()); else return 0; } function _absoluteRewardAmountByWalletCurrency(address wallet, address currencyCt, uint256 currencyId) private view returns (int256) { if ( claimNonceByWalletCurrency[wallet][currencyCt][currencyId] < absoluteRewardByWallet[wallet][currencyCt][currencyId].nonce && block.timestamp >= absoluteRewardByWallet[wallet][currencyCt][currencyId].unlockTime ) return absoluteRewardByWallet[wallet][currencyCt][currencyId].amount.clampMax( deposited.get(currencyCt, currencyId) ); else return 0; } } contract SecurityBondable is Ownable { SecurityBond public securityBond; event SetSecurityBondEvent(SecurityBond oldSecurityBond, SecurityBond newSecurityBond); function setSecurityBond(SecurityBond newSecurityBond) public onlyDeployer notNullAddress(address(newSecurityBond)) notSameAddresses(address(newSecurityBond), address(securityBond)) { SecurityBond oldSecurityBond = securityBond; securityBond = newSecurityBond; emit SetSecurityBondEvent(oldSecurityBond, newSecurityBond); } modifier securityBondInitialized() { require(address(securityBond) != address(0), "Security bond not initialized [SecurityBondable.sol:52]"); _; } } 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]"); _; } } 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 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]"); _; } } contract DriipSettlementChallengeState is Ownable, Servable, Configurable, Upgradable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; string constant public INITIATE_PROPOSAL_ACTION = "initiate_proposal"; string constant public TERMINATE_PROPOSAL_ACTION = "terminate_proposal"; string constant public REMOVE_PROPOSAL_ACTION = "remove_proposal"; string constant public DISQUALIFY_PROPOSAL_ACTION = "disqualify_proposal"; string constant public QUALIFY_PROPOSAL_ACTION = "qualify_proposal"; SettlementChallengeTypesLib.Proposal[] public proposals; mapping(address => mapping(address => mapping(uint256 => uint256))) public proposalIndexByWalletCurrency; mapping(address => mapping(uint256 => mapping(address => mapping(uint256 => uint256)))) public proposalIndexByWalletNonceCurrency; event InitiateProposalEvent(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated, bytes32 challengedHash, string challengedKind); event TerminateProposalEvent(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated, bytes32 challengedHash, string challengedKind); event RemoveProposalEvent(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated, bytes32 challengedHash, string challengedKind); event DisqualifyProposalEvent(address challengedWallet, uint256 challengedNonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated, address challengerWallet, uint256 candidateNonce, bytes32 candidateHash, string candidateKind); event QualifyProposalEvent(address challengedWallet, uint256 challengedNonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated, address challengerWallet, uint256 candidateNonce, bytes32 candidateHash, string candidateKind); event UpgradeProposalEvent(SettlementChallengeTypesLib.Proposal proposal); constructor(address deployer) Ownable(deployer) public { } function proposalsCount() public view returns (uint256) { return proposals.length; } function initiateProposal(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency memory currency, uint256 blockNumber, bool walletInitiated, bytes32 challengedHash, string memory challengedKind) public onlyEnabledServiceAction(INITIATE_PROPOSAL_ACTION) { _initiateProposal( wallet, nonce, cumulativeTransferAmount, stageAmount, targetBalanceAmount, currency, blockNumber, walletInitiated, challengedHash, challengedKind ); emit InitiateProposalEvent( wallet, nonce, cumulativeTransferAmount, stageAmount, targetBalanceAmount, currency, blockNumber, walletInitiated, challengedHash, challengedKind ); } function terminateProposal(address wallet, MonetaryTypesLib.Currency memory currency, bool clearNonce) public onlyEnabledServiceAction(TERMINATE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; if (clearNonce) proposalIndexByWalletNonceCurrency[wallet][proposals[index - 1].nonce][currency.ct][currency.id] = 0; proposals[index - 1].terminated = true; emit TerminateProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.cumulativeTransfer, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, proposals[index - 1].challenged.hash, proposals[index - 1].challenged.kind ); } function terminateProposal(address wallet, MonetaryTypesLib.Currency memory currency, bool clearNonce, bool walletTerminated) public onlyEnabledServiceAction(TERMINATE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; require(walletTerminated == proposals[index - 1].walletInitiated, "Wallet initiation and termination mismatch [DriipSettlementChallengeState.sol:165]"); if (clearNonce) proposalIndexByWalletNonceCurrency[wallet][proposals[index - 1].nonce][currency.ct][currency.id] = 0; proposals[index - 1].terminated = true; emit TerminateProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.cumulativeTransfer, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, proposals[index - 1].challenged.hash, proposals[index - 1].challenged.kind ); } function removeProposal(address wallet, MonetaryTypesLib.Currency memory currency) public onlyEnabledServiceAction(REMOVE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; emit RemoveProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.cumulativeTransfer, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, proposals[index - 1].challenged.hash, proposals[index - 1].challenged.kind ); _removeProposal(index); } function removeProposal(address wallet, MonetaryTypesLib.Currency memory currency, bool walletTerminated) public onlyEnabledServiceAction(REMOVE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; require(walletTerminated == proposals[index - 1].walletInitiated, "Wallet initiation and termination mismatch [DriipSettlementChallengeState.sol:225]"); emit RemoveProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.cumulativeTransfer, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, proposals[index - 1].challenged.hash, proposals[index - 1].challenged.kind ); _removeProposal(index); } function disqualifyProposal(address challengedWallet, MonetaryTypesLib.Currency memory currency, address challengerWallet, uint256 blockNumber, uint256 candidateNonce, bytes32 candidateHash, string memory candidateKind) public onlyEnabledServiceAction(DISQUALIFY_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[challengedWallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:255]"); proposals[index - 1].status = SettlementChallengeTypesLib.Status.Disqualified; proposals[index - 1].expirationTime = block.timestamp.add(configuration.settlementChallengeTimeout()); proposals[index - 1].disqualification.challenger = challengerWallet; proposals[index - 1].disqualification.nonce = candidateNonce; proposals[index - 1].disqualification.blockNumber = blockNumber; proposals[index - 1].disqualification.candidate.hash = candidateHash; proposals[index - 1].disqualification.candidate.kind = candidateKind; emit DisqualifyProposalEvent( challengedWallet, proposals[index - 1].nonce, proposals[index - 1].amounts.cumulativeTransfer, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, challengerWallet, candidateNonce, candidateHash, candidateKind ); } function qualifyProposal(address wallet, MonetaryTypesLib.Currency memory currency) public onlyEnabledServiceAction(QUALIFY_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:284]"); emit QualifyProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.cumulativeTransfer, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, proposals[index - 1].disqualification.challenger, proposals[index - 1].disqualification.nonce, proposals[index - 1].disqualification.candidate.hash, proposals[index - 1].disqualification.candidate.kind ); proposals[index - 1].status = SettlementChallengeTypesLib.Status.Qualified; proposals[index - 1].expirationTime = block.timestamp.add(configuration.settlementChallengeTimeout()); delete proposals[index - 1].disqualification; } function hasProposal(address wallet, uint256 nonce, MonetaryTypesLib.Currency memory currency) public view returns (bool) { return 0 != proposalIndexByWalletNonceCurrency[wallet][nonce][currency.ct][currency.id]; } function hasProposal(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { return 0 != proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; } function hasProposalTerminated(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:342]"); return proposals[index - 1].terminated; } function hasProposalExpired(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:357]"); return block.timestamp >= proposals[index - 1].expirationTime; } function proposalNonce(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:371]"); return proposals[index - 1].nonce; } function proposalReferenceBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:385]"); return proposals[index - 1].referenceBlockNumber; } function proposalDefinitionBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:399]"); return proposals[index - 1].definitionBlockNumber; } function proposalExpirationTime(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:413]"); return proposals[index - 1].expirationTime; } function proposalStatus(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (SettlementChallengeTypesLib.Status) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:427]"); return proposals[index - 1].status; } function proposalCumulativeTransferAmount(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (int256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:441]"); return proposals[index - 1].amounts.cumulativeTransfer; } function proposalStageAmount(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (int256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:455]"); return proposals[index - 1].amounts.stage; } function proposalTargetBalanceAmount(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (int256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:469]"); return proposals[index - 1].amounts.targetBalance; } function proposalChallengedHash(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bytes32) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:483]"); return proposals[index - 1].challenged.hash; } function proposalChallengedKind(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (string memory) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:497]"); return proposals[index - 1].challenged.kind; } function proposalWalletInitiated(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:511]"); return proposals[index - 1].walletInitiated; } function proposalDisqualificationChallenger(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (address) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:525]"); return proposals[index - 1].disqualification.challenger; } function proposalDisqualificationNonce(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:539]"); return proposals[index - 1].disqualification.nonce; } function proposalDisqualificationBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:553]"); return proposals[index - 1].disqualification.blockNumber; } function proposalDisqualificationCandidateHash(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bytes32) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:567]"); return proposals[index - 1].disqualification.candidate.hash; } function proposalDisqualificationCandidateKind(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (string memory) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [DriipSettlementChallengeState.sol:581]"); return proposals[index - 1].disqualification.candidate.kind; } function upgradeProposal(SettlementChallengeTypesLib.Proposal memory proposal) public onlyWhenUpgrading { require( 0 == proposalIndexByWalletNonceCurrency[proposal.wallet][proposal.nonce][proposal.currency.ct][proposal.currency.id], "Proposal exists for wallet, nonce and currency [DriipSettlementChallengeState.sol:592]" ); proposals.push(proposal); uint256 index = proposals.length; proposalIndexByWalletCurrency[proposal.wallet][proposal.currency.ct][proposal.currency.id] = index; proposalIndexByWalletNonceCurrency[proposal.wallet][proposal.nonce][proposal.currency.ct][proposal.currency.id] = index; emit UpgradeProposalEvent(proposal); } function _initiateProposal(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency memory currency, uint256 referenceBlockNumber, bool walletInitiated, bytes32 challengedHash, string memory challengedKind) private { require( 0 == proposalIndexByWalletNonceCurrency[wallet][nonce][currency.ct][currency.id], "Existing proposal found for wallet, nonce and currency [DriipSettlementChallengeState.sol:620]" ); require(stageAmount.isPositiveInt256(), "Stage amount not positive [DriipSettlementChallengeState.sol:626]"); require(targetBalanceAmount.isPositiveInt256(), "Target balance amount not positive [DriipSettlementChallengeState.sol:627]"); uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) { index = ++(proposals.length); proposalIndexByWalletCurrency[wallet][currency.ct][currency.id] = index; } proposals[index - 1].wallet = wallet; proposals[index - 1].nonce = nonce; proposals[index - 1].referenceBlockNumber = referenceBlockNumber; proposals[index - 1].definitionBlockNumber = block.number; proposals[index - 1].expirationTime = block.timestamp.add(configuration.settlementChallengeTimeout()); proposals[index - 1].status = SettlementChallengeTypesLib.Status.Qualified; proposals[index - 1].currency = currency; proposals[index - 1].amounts.cumulativeTransfer = cumulativeTransferAmount; proposals[index - 1].amounts.stage = stageAmount; proposals[index - 1].amounts.targetBalance = targetBalanceAmount; proposals[index - 1].walletInitiated = walletInitiated; proposals[index - 1].terminated = false; proposals[index - 1].challenged.hash = challengedHash; proposals[index - 1].challenged.kind = challengedKind; proposalIndexByWalletNonceCurrency[wallet][nonce][currency.ct][currency.id] = index; } function _removeProposal(uint256 index) private { proposalIndexByWalletCurrency[proposals[index - 1].wallet][proposals[index - 1].currency.ct][proposals[index - 1].currency.id] = 0; proposalIndexByWalletNonceCurrency[proposals[index - 1].wallet][proposals[index - 1].nonce][proposals[index - 1].currency.ct][proposals[index - 1].currency.id] = 0; if (index < proposals.length) { proposals[index - 1] = proposals[proposals.length - 1]; proposalIndexByWalletCurrency[proposals[index - 1].wallet][proposals[index - 1].currency.ct][proposals[index - 1].currency.id] = index; proposalIndexByWalletNonceCurrency[proposals[index - 1].wallet][proposals[index - 1].nonce][proposals[index - 1].currency.ct][proposals[index - 1].currency.id] = index; } proposals.length--; } } contract NullSettlementChallengeState is Ownable, Servable, Configurable, BalanceTrackable, Upgradable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; string constant public INITIATE_PROPOSAL_ACTION = "initiate_proposal"; string constant public TERMINATE_PROPOSAL_ACTION = "terminate_proposal"; string constant public REMOVE_PROPOSAL_ACTION = "remove_proposal"; string constant public DISQUALIFY_PROPOSAL_ACTION = "disqualify_proposal"; SettlementChallengeTypesLib.Proposal[] public proposals; mapping(address => mapping(address => mapping(uint256 => uint256))) public proposalIndexByWalletCurrency; event InitiateProposalEvent(address wallet, uint256 nonce, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated); event TerminateProposalEvent(address wallet, uint256 nonce, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated); event RemoveProposalEvent(address wallet, uint256 nonce, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated); event DisqualifyProposalEvent(address challengedWallet, uint256 challangedNonce, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency currency, uint256 blockNumber, bool walletInitiated, address challengerWallet, uint256 candidateNonce, bytes32 candidateHash, string candidateKind); event UpgradeProposalEvent(SettlementChallengeTypesLib.Proposal proposal); constructor(address deployer) Ownable(deployer) public { } function proposalsCount() public view returns (uint256) { return proposals.length; } function initiateProposal(address wallet, uint256 nonce, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency memory currency, uint256 blockNumber, bool walletInitiated) public onlyEnabledServiceAction(INITIATE_PROPOSAL_ACTION) { _initiateProposal( wallet, nonce, stageAmount, targetBalanceAmount, currency, blockNumber, walletInitiated ); emit InitiateProposalEvent( wallet, nonce, stageAmount, targetBalanceAmount, currency, blockNumber, walletInitiated ); } function terminateProposal(address wallet, MonetaryTypesLib.Currency memory currency) public onlyEnabledServiceAction(TERMINATE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; proposals[index - 1].terminated = true; emit TerminateProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated ); } function terminateProposal(address wallet, MonetaryTypesLib.Currency memory currency, bool walletTerminated) public onlyEnabledServiceAction(TERMINATE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; require(walletTerminated == proposals[index - 1].walletInitiated, "Wallet initiation and termination mismatch [NullSettlementChallengeState.sol:145]"); proposals[index - 1].terminated = true; emit TerminateProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated ); } function removeProposal(address wallet, MonetaryTypesLib.Currency memory currency) public onlyEnabledServiceAction(REMOVE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; emit RemoveProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated ); _removeProposal(index); } function removeProposal(address wallet, MonetaryTypesLib.Currency memory currency, bool walletTerminated) public onlyEnabledServiceAction(REMOVE_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) return; require(walletTerminated == proposals[index - 1].walletInitiated, "Wallet initiation and termination mismatch [NullSettlementChallengeState.sol:199]"); emit RemoveProposalEvent( wallet, proposals[index - 1].nonce, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated ); _removeProposal(index); } function disqualifyProposal(address challengedWallet, MonetaryTypesLib.Currency memory currency, address challengerWallet, uint256 blockNumber, uint256 candidateNonce, bytes32 candidateHash, string memory candidateKind) public onlyEnabledServiceAction(DISQUALIFY_PROPOSAL_ACTION) { uint256 index = proposalIndexByWalletCurrency[challengedWallet][currency.ct][currency.id]; require(0 != index, "No settlement found for wallet and currency [NullSettlementChallengeState.sol:228]"); proposals[index - 1].status = SettlementChallengeTypesLib.Status.Disqualified; proposals[index - 1].expirationTime = block.timestamp.add(configuration.settlementChallengeTimeout()); proposals[index - 1].disqualification.challenger = challengerWallet; proposals[index - 1].disqualification.nonce = candidateNonce; proposals[index - 1].disqualification.blockNumber = blockNumber; proposals[index - 1].disqualification.candidate.hash = candidateHash; proposals[index - 1].disqualification.candidate.kind = candidateKind; emit DisqualifyProposalEvent( challengedWallet, proposals[index - 1].nonce, proposals[index - 1].amounts.stage, proposals[index - 1].amounts.targetBalance, currency, proposals[index - 1].referenceBlockNumber, proposals[index - 1].walletInitiated, challengerWallet, candidateNonce, candidateHash, candidateKind ); } function hasProposal(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { return 0 != proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; } function hasProposalTerminated(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:271]"); return proposals[index - 1].terminated; } function hasProposalExpired(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:286]"); return block.timestamp >= proposals[index - 1].expirationTime; } function proposalNonce(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:300]"); return proposals[index - 1].nonce; } function proposalReferenceBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:314]"); return proposals[index - 1].referenceBlockNumber; } function proposalDefinitionBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:328]"); return proposals[index - 1].definitionBlockNumber; } function proposalExpirationTime(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:342]"); return proposals[index - 1].expirationTime; } function proposalStatus(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (SettlementChallengeTypesLib.Status) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:356]"); return proposals[index - 1].status; } function proposalStageAmount(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (int256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:370]"); return proposals[index - 1].amounts.stage; } function proposalTargetBalanceAmount(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (int256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:384]"); return proposals[index - 1].amounts.targetBalance; } function proposalWalletInitiated(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bool) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:398]"); return proposals[index - 1].walletInitiated; } function proposalDisqualificationChallenger(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (address) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:412]"); return proposals[index - 1].disqualification.challenger; } function proposalDisqualificationBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:426]"); return proposals[index - 1].disqualification.blockNumber; } function proposalDisqualificationNonce(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (uint256) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:440]"); return proposals[index - 1].disqualification.nonce; } function proposalDisqualificationCandidateHash(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (bytes32) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:454]"); return proposals[index - 1].disqualification.candidate.hash; } function proposalDisqualificationCandidateKind(address wallet, MonetaryTypesLib.Currency memory currency) public view returns (string memory) { uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; require(0 != index, "No proposal found for wallet and currency [NullSettlementChallengeState.sol:468]"); return proposals[index - 1].disqualification.candidate.kind; } function upgradeProposal(SettlementChallengeTypesLib.Proposal memory proposal) public onlyWhenUpgrading { require( 0 == proposalIndexByWalletCurrency[proposal.wallet][proposal.currency.ct][proposal.currency.id], "Proposal exists for wallet and currency [NullSettlementChallengeState.sol:479]" ); proposals.push(proposal); uint256 index = proposals.length; proposalIndexByWalletCurrency[proposal.wallet][proposal.currency.ct][proposal.currency.id] = index; emit UpgradeProposalEvent(proposal); } function _initiateProposal(address wallet, uint256 nonce, int256 stageAmount, int256 targetBalanceAmount, MonetaryTypesLib.Currency memory currency, uint256 referenceBlockNumber, bool walletInitiated) private { require(stageAmount.isPositiveInt256(), "Stage amount not positive [NullSettlementChallengeState.sol:506]"); require(targetBalanceAmount.isPositiveInt256(), "Target balance amount not positive [NullSettlementChallengeState.sol:507]"); uint256 index = proposalIndexByWalletCurrency[wallet][currency.ct][currency.id]; if (0 == index) { index = ++(proposals.length); proposalIndexByWalletCurrency[wallet][currency.ct][currency.id] = index; } proposals[index - 1].wallet = wallet; proposals[index - 1].nonce = nonce; proposals[index - 1].referenceBlockNumber = referenceBlockNumber; proposals[index - 1].definitionBlockNumber = block.number; proposals[index - 1].expirationTime = block.timestamp.add(configuration.settlementChallengeTimeout()); proposals[index - 1].status = SettlementChallengeTypesLib.Status.Qualified; proposals[index - 1].currency = currency; proposals[index - 1].amounts.stage = stageAmount; proposals[index - 1].amounts.targetBalance = targetBalanceAmount; proposals[index - 1].walletInitiated = walletInitiated; proposals[index - 1].terminated = false; } function _removeProposal(uint256 index) private returns (bool) { proposalIndexByWalletCurrency[proposals[index - 1].wallet][proposals[index - 1].currency.ct][proposals[index - 1].currency.id] = 0; if (index < proposals.length) { proposals[index - 1] = proposals[proposals.length - 1]; proposalIndexByWalletCurrency[proposals[index - 1].wallet][proposals[index - 1].currency.ct][proposals[index - 1].currency.id] = index; } proposals.length--; } function _activeBalanceLogEntry(address wallet, address currencyCt, uint256 currencyId) private view returns (int256 amount, uint256 blockNumber) { (int256 depositedAmount, uint256 depositedBlockNumber) = balanceTracker.lastFungibleRecord( wallet, balanceTracker.depositedBalanceType(), currencyCt, currencyId ); (int256 settledAmount, uint256 settledBlockNumber) = balanceTracker.lastFungibleRecord( wallet, balanceTracker.settledBalanceType(), currencyCt, currencyId ); amount = depositedAmount.add(settledAmount); blockNumber = depositedBlockNumber > settledBlockNumber ? depositedBlockNumber : settledBlockNumber; } } 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 DriipSettlementDisputeByPayment is Ownable, Configurable, Validatable, SecurityBondable, WalletLockable, BalanceTrackable, FraudChallengable, Servable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; using BalanceTrackerLib for BalanceTracker; string constant public CHALLENGE_BY_PAYMENT_ACTION = "challenge_by_payment"; DriipSettlementChallengeState public driipSettlementChallengeState; NullSettlementChallengeState public nullSettlementChallengeState; event SetDriipSettlementChallengeStateEvent(DriipSettlementChallengeState oldDriipSettlementChallengeState, DriipSettlementChallengeState newDriipSettlementChallengeState); event SetNullSettlementChallengeStateEvent(NullSettlementChallengeState oldNullSettlementChallengeState, NullSettlementChallengeState newNullSettlementChallengeState); event ChallengeByPaymentEvent(address wallet, uint256 nonce, PaymentTypesLib.Payment payment, address challenger); 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 setNullSettlementChallengeState(NullSettlementChallengeState newNullSettlementChallengeState) public onlyDeployer notNullAddress(address(newNullSettlementChallengeState)) { NullSettlementChallengeState oldNullSettlementChallengeState = nullSettlementChallengeState; nullSettlementChallengeState = newNullSettlementChallengeState; emit SetNullSettlementChallengeStateEvent(oldNullSettlementChallengeState, nullSettlementChallengeState); } function challengeByPayment(address wallet, PaymentTypesLib.Payment memory payment, address challenger) public onlyEnabledServiceAction(CHALLENGE_BY_PAYMENT_ACTION) onlySealedPayment(payment) onlyPaymentSender(payment, wallet) { require( !fraudChallenge.isFraudulentPaymentHash(payment.seals.operator.hash), "Payment deemed fraudulent [DriipSettlementDisputeByPayment.sol:102]" ); require( driipSettlementChallengeState.hasProposal(wallet, payment.currency), "No proposal found [DriipSettlementDisputeByPayment.sol:108]" ); require( !driipSettlementChallengeState.hasProposalExpired(wallet, payment.currency), "Proposal found expired [DriipSettlementDisputeByPayment.sol:114]" ); require( payment.sender.nonce > driipSettlementChallengeState.proposalNonce(wallet, payment.currency), "Payment nonce not strictly greater than proposal nonce [DriipSettlementDisputeByPayment.sol:121]" ); require( payment.sender.nonce > driipSettlementChallengeState.proposalDisqualificationNonce(wallet, payment.currency), "Payment nonce not strictly greater than proposal disqualification nonce [DriipSettlementDisputeByPayment.sol:125]" ); require(_overrun(wallet, payment), "No overrun found [DriipSettlementDisputeByPayment.sol:131]"); _settleRewards(wallet, payment.sender.balances.current, payment.currency, challenger); driipSettlementChallengeState.disqualifyProposal( wallet, payment.currency, challenger, payment.blockNumber, payment.sender.nonce, payment.seals.operator.hash, PaymentTypesLib.PAYMENT_KIND() ); nullSettlementChallengeState.terminateProposal(wallet, payment.currency); emit ChallengeByPaymentEvent( wallet, driipSettlementChallengeState.proposalNonce(wallet, payment.currency), payment, challenger ); } function _overrun(address wallet, PaymentTypesLib.Payment memory payment) private view returns (bool) { int targetBalanceAmount = driipSettlementChallengeState.proposalTargetBalanceAmount( wallet, payment.currency ); int256 deltaBalanceAmountSinceStart = balanceTracker.fungibleActiveDeltaBalanceAmountByBlockNumbers( wallet, payment.currency, driipSettlementChallengeState.proposalReferenceBlockNumber(wallet, payment.currency), block.number ); int256 paymentCumulativeTransferAmount = payment.sender.balances.current.sub( balanceTracker.fungibleActiveBalanceAmountByBlockNumber( wallet, payment.currency, payment.blockNumber ) ); int proposalCumulativeTransferAmount = driipSettlementChallengeState.proposalCumulativeTransferAmount( wallet, payment.currency ); return targetBalanceAmount.add(deltaBalanceAmountSinceStart) < proposalCumulativeTransferAmount.sub(paymentCumulativeTransferAmount); } function _settleRewards(address wallet, int256 walletAmount, MonetaryTypesLib.Currency memory currency, address challenger) private { if (driipSettlementChallengeState.proposalWalletInitiated(wallet, currency)) _settleBalanceReward(wallet, walletAmount, currency, challenger); else _settleSecurityBondReward(wallet, walletAmount, currency, challenger); } function _settleBalanceReward(address wallet, int256 walletAmount, MonetaryTypesLib.Currency memory currency, address challenger) private { if (SettlementChallengeTypesLib.Status.Disqualified == driipSettlementChallengeState.proposalStatus( wallet, currency )) walletLocker.unlockFungibleByProxy( wallet, driipSettlementChallengeState.proposalDisqualificationChallenger( wallet, currency ), currency.ct, currency.id ); walletLocker.lockFungibleByProxy( wallet, challenger, walletAmount, currency.ct, currency.id, configuration.settlementChallengeTimeout() ); } function _settleSecurityBondReward(address wallet, int256 walletAmount, MonetaryTypesLib.Currency memory currency, address challenger) private { if (SettlementChallengeTypesLib.Status.Disqualified == driipSettlementChallengeState.proposalStatus( wallet, currency )) securityBond.depriveAbsolute( driipSettlementChallengeState.proposalDisqualificationChallenger( wallet, currency ), currency.ct, currency.id ); MonetaryTypesLib.Figure memory flatReward = _flatReward(); securityBond.rewardAbsolute( challenger, flatReward.amount, flatReward.currency.ct, flatReward.currency.id, 0 ); int256 progressiveRewardAmount = walletAmount.clampMax( securityBond.depositedFractionalBalance( currency.ct, currency.id, configuration.operatorSettlementStakeFraction() ) ); securityBond.rewardAbsolute( challenger, progressiveRewardAmount, currency.ct, currency.id, 0 ); } function _flatReward() private view returns (MonetaryTypesLib.Figure memory) { (int256 amount, address currencyCt, uint256 currencyId) = configuration.operatorSettlementStake(); return MonetaryTypesLib.Figure(amount, MonetaryTypesLib.Currency(currencyCt, currencyId)); } } 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 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 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(); } } 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; } } contract DriipSettlementChallengeByPayment is Ownable, ConfigurableOperational, Validatable, WalletLockable, BalanceTrackable { using SafeMathIntLib for int256; using SafeMathUintLib for uint256; using BalanceTrackerLib for BalanceTracker; DriipSettlementDisputeByPayment public driipSettlementDisputeByPayment; DriipSettlementChallengeState public driipSettlementChallengeState; NullSettlementChallengeState public nullSettlementChallengeState; DriipSettlementState public driipSettlementState; event SetDriipSettlementDisputeByPaymentEvent(DriipSettlementDisputeByPayment oldDriipSettlementDisputeByPayment, DriipSettlementDisputeByPayment newDriipSettlementDisputeByPayment); event SetDriipSettlementChallengeStateEvent(DriipSettlementChallengeState oldDriipSettlementChallengeState, DriipSettlementChallengeState newDriipSettlementChallengeState); event SetNullSettlementChallengeStateEvent(NullSettlementChallengeState oldNullSettlementChallengeState, NullSettlementChallengeState newNullSettlementChallengeState); event SetDriipSettlementStateEvent(DriipSettlementState oldDriipSettlementState, DriipSettlementState newDriipSettlementState); event StartChallengeFromPaymentEvent(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, address currencyCt, uint256 currencyId); event StartChallengeFromPaymentByProxyEvent(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, address currencyCt, uint256 currencyId, address proxy); event StopChallengeEvent(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, address currencyCt, uint256 currencyId); event StopChallengeByProxyEvent(address wallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, address currencyCt, uint256 currencyId, address proxy); event ChallengeByPaymentEvent(address challengedWallet, uint256 nonce, int256 cumulativeTransferAmount, int256 stageAmount, int256 targetBalanceAmount, address currencyCt, uint256 currencyId, address challengerWallet); constructor(address deployer) Ownable(deployer) public { } function setDriipSettlementDisputeByPayment(DriipSettlementDisputeByPayment newDriipSettlementDisputeByPayment) public onlyDeployer notNullAddress(address(newDriipSettlementDisputeByPayment)) { DriipSettlementDisputeByPayment oldDriipSettlementDisputeByPayment = driipSettlementDisputeByPayment; driipSettlementDisputeByPayment = newDriipSettlementDisputeByPayment; emit SetDriipSettlementDisputeByPaymentEvent(oldDriipSettlementDisputeByPayment, driipSettlementDisputeByPayment); } function setDriipSettlementChallengeState(DriipSettlementChallengeState newDriipSettlementChallengeState) public onlyDeployer notNullAddress(address(newDriipSettlementChallengeState)) { DriipSettlementChallengeState oldDriipSettlementChallengeState = driipSettlementChallengeState; driipSettlementChallengeState = newDriipSettlementChallengeState; emit SetDriipSettlementChallengeStateEvent(oldDriipSettlementChallengeState, driipSettlementChallengeState); } function setNullSettlementChallengeState(NullSettlementChallengeState newNullSettlementChallengeState) public onlyDeployer notNullAddress(address(newNullSettlementChallengeState)) { NullSettlementChallengeState oldNullSettlementChallengeState = nullSettlementChallengeState; nullSettlementChallengeState = newNullSettlementChallengeState; emit SetNullSettlementChallengeStateEvent(oldNullSettlementChallengeState, nullSettlementChallengeState); } function setDriipSettlementState(DriipSettlementState newDriipSettlementState) public onlyDeployer notNullAddress(address(newDriipSettlementState)) { DriipSettlementState oldDriipSettlementState = driipSettlementState; driipSettlementState = newDriipSettlementState; emit SetDriipSettlementStateEvent(oldDriipSettlementState, driipSettlementState); } function startChallengeFromPayment(PaymentTypesLib.Payment memory payment, int256 stageAmount) public { require(!walletLocker.isLocked(msg.sender), "Wallet found locked [DriipSettlementChallengeByPayment.sol:134]"); _startChallengeFromPayment(msg.sender, payment, stageAmount, true); emit StartChallengeFromPaymentEvent( msg.sender, driipSettlementChallengeState.proposalNonce(msg.sender, payment.currency), driipSettlementChallengeState.proposalCumulativeTransferAmount(msg.sender, payment.currency), stageAmount, driipSettlementChallengeState.proposalTargetBalanceAmount(msg.sender, payment.currency), payment.currency.ct, payment.currency.id ); } function startChallengeFromPaymentByProxy(address wallet, PaymentTypesLib.Payment memory payment, int256 stageAmount) public onlyOperator { _startChallengeFromPayment(wallet, payment, stageAmount, false); emit StartChallengeFromPaymentByProxyEvent( wallet, driipSettlementChallengeState.proposalNonce(wallet, payment.currency), driipSettlementChallengeState.proposalCumulativeTransferAmount(wallet, payment.currency), stageAmount, driipSettlementChallengeState.proposalTargetBalanceAmount(wallet, payment.currency), payment.currency.ct, payment.currency.id, msg.sender ); } function stopChallenge(address currencyCt, uint256 currencyId) public { MonetaryTypesLib.Currency memory currency = MonetaryTypesLib.Currency(currencyCt, currencyId); _stopChallenge(msg.sender, currency, true, true); emit StopChallengeEvent( msg.sender, driipSettlementChallengeState.proposalNonce(msg.sender, currency), driipSettlementChallengeState.proposalCumulativeTransferAmount(msg.sender, currency), driipSettlementChallengeState.proposalStageAmount(msg.sender, currency), driipSettlementChallengeState.proposalTargetBalanceAmount(msg.sender, currency), currencyCt, currencyId ); } function stopChallengeByProxy(address wallet, address currencyCt, uint256 currencyId) public onlyOperator { MonetaryTypesLib.Currency memory currency = MonetaryTypesLib.Currency(currencyCt, currencyId); _stopChallenge(wallet, currency, true, false); emit StopChallengeByProxyEvent( wallet, driipSettlementChallengeState.proposalNonce(wallet, currency), driipSettlementChallengeState.proposalCumulativeTransferAmount(wallet, currency), driipSettlementChallengeState.proposalStageAmount(wallet, currency), driipSettlementChallengeState.proposalTargetBalanceAmount(wallet, currency), currencyCt, currencyId, msg.sender ); } function hasProposal(address wallet, address currencyCt, uint256 currencyId) public view returns (bool) { return driipSettlementChallengeState.hasProposal( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function hasProposalTerminated(address wallet, address currencyCt, uint256 currencyId) public view returns (bool) { return driipSettlementChallengeState.hasProposalTerminated( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function hasProposalExpired(address wallet, address currencyCt, uint256 currencyId) public view returns (bool) { return driipSettlementChallengeState.hasProposalExpired( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalNonce(address wallet, address currencyCt, uint256 currencyId) public view returns (uint256) { return driipSettlementChallengeState.proposalNonce( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalReferenceBlockNumber(address wallet, address currencyCt, uint256 currencyId) public view returns (uint256) { return driipSettlementChallengeState.proposalReferenceBlockNumber( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalExpirationTime(address wallet, address currencyCt, uint256 currencyId) public view returns (uint256) { return driipSettlementChallengeState.proposalExpirationTime( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalStatus(address wallet, address currencyCt, uint256 currencyId) public view returns (SettlementChallengeTypesLib.Status) { return driipSettlementChallengeState.proposalStatus( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalStageAmount(address wallet, address currencyCt, uint256 currencyId) public view returns (int256) { return driipSettlementChallengeState.proposalStageAmount( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalTargetBalanceAmount(address wallet, address currencyCt, uint256 currencyId) public view returns (int256) { return driipSettlementChallengeState.proposalTargetBalanceAmount( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalChallengedHash(address wallet, address currencyCt, uint256 currencyId) public view returns (bytes32) { return driipSettlementChallengeState.proposalChallengedHash( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalChallengedKind(address wallet, address currencyCt, uint256 currencyId) public view returns (string memory) { return driipSettlementChallengeState.proposalChallengedKind( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalWalletInitiated(address wallet, address currencyCt, uint256 currencyId) public view returns (bool) { return driipSettlementChallengeState.proposalWalletInitiated( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalDisqualificationChallenger(address wallet, address currencyCt, uint256 currencyId) public view returns (address) { return driipSettlementChallengeState.proposalDisqualificationChallenger( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalDisqualificationBlockNumber(address wallet, address currencyCt, uint256 currencyId) public view returns (uint256) { return driipSettlementChallengeState.proposalDisqualificationBlockNumber( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalDisqualificationCandidateKind(address wallet, address currencyCt, uint256 currencyId) public view returns (string memory) { return driipSettlementChallengeState.proposalDisqualificationCandidateKind( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function proposalDisqualificationCandidateHash(address wallet, address currencyCt, uint256 currencyId) public view returns (bytes32) { return driipSettlementChallengeState.proposalDisqualificationCandidateHash( wallet, MonetaryTypesLib.Currency(currencyCt, currencyId) ); } function challengeByPayment(address wallet, PaymentTypesLib.Payment memory payment) public onlyOperationalModeNormal { driipSettlementDisputeByPayment.challengeByPayment(wallet, payment, msg.sender); emit ChallengeByPaymentEvent( wallet, driipSettlementChallengeState.proposalNonce(wallet, payment.currency), driipSettlementChallengeState.proposalCumulativeTransferAmount(wallet, payment.currency), driipSettlementChallengeState.proposalStageAmount(wallet, payment.currency), driipSettlementChallengeState.proposalTargetBalanceAmount(wallet, payment.currency), payment.currency.ct, payment.currency.id, msg.sender ); } function _startChallengeFromPayment(address wallet, PaymentTypesLib.Payment memory payment, int256 stageAmount, bool walletInitiated) private onlySealedPayment(payment) { require( block.number >= configuration.earliestSettlementBlockNumber(), "Current block number below earliest settlement block number [DriipSettlementChallengeByPayment.sol:489]" ); require( validator.isPaymentParty(payment, wallet), "Wallet is not payment party [DriipSettlementChallengeByPayment.sol:495]" ); require( !driipSettlementChallengeState.hasProposal(wallet, payment.currency) || driipSettlementChallengeState.hasProposalTerminated(wallet, payment.currency), "Overlapping driip settlement challenge proposal found [DriipSettlementChallengeByPayment.sol:501]" ); require( !nullSettlementChallengeState.hasProposal(wallet, payment.currency) || nullSettlementChallengeState.hasProposalTerminated(wallet, payment.currency), "Overlapping null settlement challenge proposal found [DriipSettlementChallengeByPayment.sol:508]" ); (uint256 nonce, int256 correctedCumulativeTransferAmount) = _paymentPartyProperties(payment, wallet); require( driipSettlementState.maxNonceByWalletAndCurrency(wallet, payment.currency) < nonce, "Wallet's nonce below highest settled nonce [DriipSettlementChallengeByPayment.sol:518]" ); driipSettlementChallengeState.initiateProposal( wallet, nonce, correctedCumulativeTransferAmount, stageAmount, balanceTracker.fungibleActiveBalanceAmount(wallet, payment.currency) .add(correctedCumulativeTransferAmount.sub(stageAmount)), payment.currency, payment.blockNumber, walletInitiated, payment.seals.operator.hash, PaymentTypesLib.PAYMENT_KIND() ); } function _stopChallenge(address wallet, MonetaryTypesLib.Currency memory currency, bool clearNonce, bool walletTerminated) private { require( driipSettlementChallengeState.hasProposal(wallet, currency), "No proposal found [DriipSettlementChallengeByPayment.sol:538]" ); require( !driipSettlementChallengeState.hasProposalTerminated(wallet, currency), "Proposal found terminated [DriipSettlementChallengeByPayment.sol:542]" ); driipSettlementChallengeState.terminateProposal(wallet, currency, clearNonce, walletTerminated); nullSettlementChallengeState.terminateProposal(wallet, currency); } function _paymentPartyProperties(PaymentTypesLib.Payment memory payment, address wallet) private view returns (uint256 nonce, int256 correctedCumulativeTransferAmount) { int256 activeBalanceAmountAtPaymentBlock = balanceTracker.fungibleActiveBalanceAmountByBlockNumber( wallet, payment.currency, payment.blockNumber ); int256 deltaSettledBalanceAmount = driipSettlementState.settledAmountByBlockNumber( wallet, payment.currency, payment.blockNumber ); if (validator.isPaymentSender(payment, wallet)) { nonce = payment.sender.nonce; correctedCumulativeTransferAmount = payment.sender.balances.current .sub(activeBalanceAmountAtPaymentBlock) .sub(deltaSettledBalanceAmount); } else { nonce = payment.recipient.nonce; correctedCumulativeTransferAmount = payment.recipient.balances.current .sub(activeBalanceAmountAtPaymentBlock) .sub(deltaSettledBalanceAmount); } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalChallengedKind","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalStatus","outputs":[{"internalType":"enum SettlementChallengeTypesLib.Status","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"driipSettlementDisputeByPayment","outputs":[{"internalType":"contract DriipSettlementDisputeByPayment","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract Validator","name":"newValidator","type":"address"}],"name":"setValidator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalTargetBalanceAmount","outputs":[{"internalType":"int256","name":"","type":"int256"}],"payable":false,"stateMutability":"view","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":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":"int256","name":"stageAmount","type":"int256"}],"name":"startChallengeFromPaymentByProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"validator","outputs":[{"internalType":"contract Validator","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"hasProposalExpired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalStageAmount","outputs":[{"internalType":"int256","name":"","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"destructor","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"hasProposalTerminated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"int256","name":"stageAmount","type":"int256"}],"name":"startChallengeFromPayment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract DriipSettlementDisputeByPayment","name":"newDriipSettlementDisputeByPayment","type":"address"}],"name":"setDriipSettlementDisputeByPayment","outputs":[],"payable":false,"stateMutability":"nonpayable","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 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":true,"inputs":[],"name":"configuration","outputs":[{"internalType":"contract Configuration","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract NullSettlementChallengeState","name":"newNullSettlementChallengeState","type":"address"}],"name":"setNullSettlementChallengeState","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalReferenceBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"disableSelfDestruction","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalWalletInitiated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract WalletLocker","name":"newWalletLocker","type":"address"}],"name":"setWalletLocker","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"}],"name":"challengeByPayment","outputs":[],"payable":false,"stateMutability":"nonpayable","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"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"stopChallengeByProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalChallengedHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalDisqualificationCandidateHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","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":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"hasProposal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"stopChallenge","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalDisqualificationCandidateKind","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalDisqualificationBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"walletLocker","outputs":[{"internalType":"contract WalletLocker","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"nullSettlementChallengeState","outputs":[{"internalType":"contract NullSettlementChallengeState","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalExpirationTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"currencyCt","type":"address"},{"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"proposalDisqualificationChallenger","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"deployer","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract DriipSettlementDisputeByPayment","name":"oldDriipSettlementDisputeByPayment","type":"address"},{"indexed":false,"internalType":"contract DriipSettlementDisputeByPayment","name":"newDriipSettlementDisputeByPayment","type":"address"}],"name":"SetDriipSettlementDisputeByPaymentEvent","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 NullSettlementChallengeState","name":"oldNullSettlementChallengeState","type":"address"},{"indexed":false,"internalType":"contract NullSettlementChallengeState","name":"newNullSettlementChallengeState","type":"address"}],"name":"SetNullSettlementChallengeStateEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract DriipSettlementState","name":"oldDriipSettlementState","type":"address"},{"indexed":false,"internalType":"contract DriipSettlementState","name":"newDriipSettlementState","type":"address"}],"name":"SetDriipSettlementStateEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"int256","name":"cumulativeTransferAmount","type":"int256"},{"indexed":false,"internalType":"int256","name":"stageAmount","type":"int256"},{"indexed":false,"internalType":"int256","name":"targetBalanceAmount","type":"int256"},{"indexed":false,"internalType":"address","name":"currencyCt","type":"address"},{"indexed":false,"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"StartChallengeFromPaymentEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"int256","name":"cumulativeTransferAmount","type":"int256"},{"indexed":false,"internalType":"int256","name":"stageAmount","type":"int256"},{"indexed":false,"internalType":"int256","name":"targetBalanceAmount","type":"int256"},{"indexed":false,"internalType":"address","name":"currencyCt","type":"address"},{"indexed":false,"internalType":"uint256","name":"currencyId","type":"uint256"},{"indexed":false,"internalType":"address","name":"proxy","type":"address"}],"name":"StartChallengeFromPaymentByProxyEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"int256","name":"cumulativeTransferAmount","type":"int256"},{"indexed":false,"internalType":"int256","name":"stageAmount","type":"int256"},{"indexed":false,"internalType":"int256","name":"targetBalanceAmount","type":"int256"},{"indexed":false,"internalType":"address","name":"currencyCt","type":"address"},{"indexed":false,"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"StopChallengeEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"int256","name":"cumulativeTransferAmount","type":"int256"},{"indexed":false,"internalType":"int256","name":"stageAmount","type":"int256"},{"indexed":false,"internalType":"int256","name":"targetBalanceAmount","type":"int256"},{"indexed":false,"internalType":"address","name":"currencyCt","type":"address"},{"indexed":false,"internalType":"uint256","name":"currencyId","type":"uint256"},{"indexed":false,"internalType":"address","name":"proxy","type":"address"}],"name":"StopChallengeByProxyEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"challengedWallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"int256","name":"cumulativeTransferAmount","type":"int256"},{"indexed":false,"internalType":"int256","name":"stageAmount","type":"int256"},{"indexed":false,"internalType":"int256","name":"targetBalanceAmount","type":"int256"},{"indexed":false,"internalType":"address","name":"currencyCt","type":"address"},{"indexed":false,"internalType":"uint256","name":"currencyId","type":"uint256"},{"indexed":false,"internalType":"address","name":"challengerWallet","type":"address"}],"name":"ChallengeByPaymentEvent","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 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 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
60806040523480156200001157600080fd5b506040516200490c3803806200490c8339810160408190526200003491620000b3565b80806001600160a01b0381166200004a57600080fd5b6001600160a01b0381163014156200006157600080fd5b5060008054610100600160a81b0319166101006001600160a01b0393909316928302179055600180546001600160a01b03191690911790555062000108565b8051620000ad81620000ee565b92915050565b600060208284031215620000c657600080fd5b6000620000d48484620000a0565b949350505050565b60006001600160a01b038216620000ad565b620000f981620000dc565b81146200010557600080fd5b50565b6147f480620001186000396000f3fe608060405234801561001057600080fd5b506004361061023b5760003560e01c8063039b9fb1146102405780630712abb0146102695780630fa6f23d146102895780631327d3d81461029e57806316987929146102b357806319139092146102d3578063240625d8146102db57806325c84441146102f05780632738a112146102f85780632aa1c9d9146103005780632f013a001461031357806334033fc11461031b5780633a5381b51461032e5780633bebdcb5146103365780633e59b70614610349578063404e896f1461035157806342cb4587146103645780634476d23b1461037757806346d1d3c41461038c5780634d3d826c1461039f5780634dc8eb79146103b257806351d7cd61146103c5578063570ca735146103cd578063598b75ad146103d55780635dc60def146103e8578063627f09c3146103f05780636c70bee9146104035780636ccb43c81461040b5780636de6a5d21461041e57806370327ea1146104315780637da5b11c14610439578063892860b21461044c578063911eb9651461045f5780639621473514610472578063972fcee0146104855780639882da6c14610498578063adfb6778146104ab578063b3ab15fb146104be578063b52d470a146104d1578063bb9357de146104d9578063c19df1e4146104ec578063ca7f47ed146104ff578063cdbf941914610512578063d5b68c6214610525578063d5f3948814610538578063e8ae41e314610540578063fa7424f214610548578063fb1a825e14610550578063fcd30b0214610563575b600080fd5b61025361024e3660046136f4565b610576565b604051610260919061450b565b60405180910390f35b61027c6102773660046136f4565b61061d565b60405161026091906144fd565b6102916106b6565b60405161026091906144d4565b6102b16102ac366004613847565b6106c5565b005b6102c66102c13660046136f4565b610766565b60405161026091906144c6565b6102916107ff565b6102e361080e565b60405161026091906144b8565b61029161081e565b6102b161082d565b6102b161030e366004613847565b610893565b6102e361091a565b6102b1610329366004613792565b610923565b610291610b16565b6102e36103443660046136f4565b610b25565b6102e3610bbe565b6102b161035f366004613847565b610bce565b6102c66103723660046136f4565b610c48565b61037f610c91565b60405161026091906141d0565b6102e361039a3660046136f4565b610ca5565b6102b16103ad3660046138e7565b610cee565b6102b16103c0366004613847565b610f7f565b610291610ff9565b61037f611008565b6102b16103e3366004613847565b611017565b6102b16110d2565b6102b16103fe366004613847565b611121565b6102916111b2565b6102b1610419366004613847565b6111c1565b6102c661042c3660046136f4565b61123b565b6102b1611284565b6102e36104473660046136f4565b6112e7565b6102b161045a366004613847565b611330565b6102b161046d366004613741565b6113eb565b6102b16104803660046136b8565b61174f565b6102b16104933660046136f4565b611805565b6102c66104a63660046136f4565b611a9d565b6102c66104b93660046136f4565b611ae6565b6102b16104cc3660046136b8565b611b2f565b6102b1611bd2565b6102e36104e73660046136f4565b611c21565b6102b16104fa3660046137db565b611c6a565b61025361050d3660046136f4565b611ee0565b6102c66105203660046136f4565b611f29565b6102c66105333660046136f4565b611f72565b61037f611fbb565b610291611fcf565b610291611fde565b6102c661055e3660046136f4565b611fed565b61037f6105713660046136f4565b612036565b6007546040805180820182526001600160a01b0385811682526020820185905291516394da13eb60e01b815260609392909216916394da13eb916105bf9188919060040161430b565b60006040518083038186803b1580156105d757600080fd5b505afa1580156105eb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261061391908101906138b3565b90505b9392505050565b6007546040805180820182526001600160a01b03858116825260208201859052915163b6e2fc3360e01b8152600093929092169163b6e2fc33916106669188919060040161430b565b60206040518083038186803b15801561067e57600080fd5b505afa158015610692573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106139190810190613865565b6006546001600160a01b031681565b6106cd6120cf565b6106d657600080fd5b806001600160a01b0381166106ea57600080fd5b60035482906001600160a01b03908116908216811461076057600380546001600160a01b038681166001600160a01b03198316179092556040519116907f1882af944a16549c3d4f60e3cd26f158b0c7aac3222cf32971fc21375ce05f609061075690839088906144e2565b60405180910390a1505b50505050565b6007546040805180820182526001600160a01b03858116825260208201859052915163c46fcd7560e01b8152600093929092169163c46fcd75916107af9188919060040161430b565b60206040518083038186803b1580156107c757600080fd5b505afa1580156107db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106139190810190613829565b6005546001600160a01b031681565b600454600160a01b900460ff1681565b6009546001600160a01b031681565b33610836610c91565b6001600160a01b03161461084957600080fd5b60005460ff161561085957600080fd5b7f787a5d936e74f4b564b9153575886059829c78cd9927b1be5e0d976b317ef7363360405161088891906141de565b60405180910390a133ff5b61089b6120cf565b6108a457600080fd5b806001600160a01b0381166108b857600080fd5b600780546001600160a01b038481166001600160a01b031983161792839055604051918116927f4f7125332801996cdeaabf9cff1ac89ddf4b52c673558936affe853ab64a88da9261090d92859216906144e2565b60405180910390a1505050565b60005460ff1681565b61092b6120e5565b61093457600080fd5b61094183838360006120f6565b6007546020830151604051632ee2ed2560e01b81527f505b0ba83acb520eb622fae274a079c14f40dd43f70fd9f1f8d2312fd4e76caf9286926001600160a01b0390911691632ee2ed259161099b9185919060040161430b565b60206040518083038186803b1580156109b357600080fd5b505afa1580156109c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109eb9190810190613829565b6007546020860151604051638ab3e96560e01b81526001600160a01b0390921691638ab3e96591610a21918a919060040161430b565b60206040518083038186803b158015610a3957600080fd5b505afa158015610a4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a719190810190613829565b600754602087015160405163c46fcd7560e01b815287926001600160a01b03169163c46fcd7591610aa6918c9160040161430b565b60206040518083038186803b158015610abe57600080fd5b505afa158015610ad2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610af69190810190613829565b602080890151805191015160405161090d979695949392919033906143a5565b6003546001600160a01b031681565b6007546040805180820182526001600160a01b038581168252602082018590529151635482c73560e01b81526000939290921691635482c73591610b6e9188919060040161430b565b60206040518083038186803b158015610b8657600080fd5b505afa158015610b9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610613919081019061380b565b600554600160a01b900460ff1681565b610bd66120cf565b610bdf57600080fd5b806001600160a01b038116610bf357600080fd5b600980546001600160a01b038481166001600160a01b031983161792839055604051918116927f6d4735156f5fb1047cfcd4a9edf19e3291aec19d53916f8fee650ca3c2d739109261090d92859216906144e2565b6007546040805180820182526001600160a01b038581168252602082018590529151633007230f60e11b8152600093929092169163600e461e916107af9188919060040161430b565b60005461010090046001600160a01b031690565b6007546040805180820182526001600160a01b038581168252602082018590529151637ff81c3760e01b81526000939290921691637ff81c3791610b6e9188919060040161430b565b60048054604051631293efbb60e21b81526001600160a01b0390911691634a4fbeec91610d1d913391016141de565b60206040518083038186803b158015610d3557600080fd5b505afa158015610d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d6d919081019061380b565b15610d935760405162461bcd60e51b8152600401610d8a9061455c565b60405180910390fd5b610da033838360016120f6565b6007546020830151604051632ee2ed2560e01b81527f1d8a75ed090cb569da62b746afdb83f0969831d5d9b9bb1a11320bc11c438c9f9233926001600160a01b0390911691632ee2ed2591610dfa918591906004016141ec565b60206040518083038186803b158015610e1257600080fd5b505afa158015610e26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e4a9190810190613829565b6007546020860151604051638ab3e96560e01b81526001600160a01b0390921691638ab3e96591610e80913391906004016141ec565b60206040518083038186803b158015610e9857600080fd5b505afa158015610eac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ed09190810190613829565b600754602087015160405163c46fcd7560e01b815287926001600160a01b03169163c46fcd7591610f059133916004016141ec565b60206040518083038186803b158015610f1d57600080fd5b505afa158015610f31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f559190810190613829565b6020808901518051910151604051610f739796959493929190614207565b60405180910390a15050565b610f876120cf565b610f9057600080fd5b806001600160a01b038116610fa457600080fd5b600680546001600160a01b038481166001600160a01b031983161792839055604051918116927f663141f76be1f253f0e608edd55c18b0816521f3b635e072c1c2f710dde6ed199261090d92859216906144e2565b6007546001600160a01b031681565b6001546001600160a01b031681565b61101f6120cf565b61102857600080fd5b806001600160a01b03811661103c57600080fd5b60055482906001600160a01b03908116908216811461076057600554600160a01b900460ff161561107f5760405162461bcd60e51b8152600401610d8a9061452c565b600580546001600160a01b038681166001600160a01b03198316179092556040519116907fb2a91d3a71b0c5bc7c083153b3474378e489506ba98bd4ddb1b9056fdc594bb59061075690839088906144e2565b6110da6120cf565b6110e357600080fd5b6004805460ff60a01b1916600160a01b1790556040517f56ec8900b9c4bf84f4b715a53068ca06961dd49084c07b481931e2c2045346e690600090a1565b6111296120cf565b61113257600080fd5b806001600160a01b03811661114657600080fd5b60025482906001600160a01b03908116908216811461076057600280546001600160a01b038681166001600160a01b03198316179092556040519116907f634f61bf00e14adedce330c80c2823e16e184f189ebe853e1ddecc4a268477ff9061075690839088906144e2565b6002546001600160a01b031681565b6111c96120cf565b6111d257600080fd5b806001600160a01b0381166111e657600080fd5b600880546001600160a01b038481166001600160a01b031983161792839055604051918116927ff21c127205310467822e10c64b2d9ffae588e019194d6af71f2bdddc0b7ef5269261090d92859216906144e2565b6007546040805180820182526001600160a01b03858116825260208201859052915163374852cb60e11b81526000939290921691636e90a596916107af9188919060040161430b565b3361128d610c91565b6001600160a01b0316146112a057600080fd5b6000805460ff191660011790556040517fd5a2a04a775c741c2ca0dc46ea7ce4835190e1aaf1ca018def0e82568ec33616906112dd9033906141de565b60405180910390a1565b6007546040805180820182526001600160a01b0385811682526020820185905291516333ca4eab60e21b8152600093929092169163cf293aac91610b6e9188919060040161430b565b6113386120cf565b61134157600080fd5b806001600160a01b03811661135557600080fd5b60045482906001600160a01b03908116908216811461076057600454600160a01b900460ff16156113985760405162461bcd60e51b8152600401610d8a906145cc565b600480546001600160a01b038681166001600160a01b03198316179092556040519116907fa44d361e26327b72a7ccbeae801b3c5cd7677ea4fa74168b289e273c46bfecfc9061075690839088906144e2565b600260009054906101000a90046001600160a01b03166001600160a01b031663f71e860f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561143957600080fd5b505afa15801561144d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611471919081019061380b565b61148d5760405162461bcd60e51b8152600401610d8a9061451c565b600654604051630eae657960e11b81526001600160a01b0390911690631d5ccaf2906114c190859085903390600401614376565b600060405180830381600087803b1580156114db57600080fd5b505af11580156114ef573d6000803e3d6000fd5b50506007546020840151604051632ee2ed2560e01b81527fffa28bfeaa617be065ef4f9cbd4448b8ac8e99c98f00741cd2d78fa4732cf9cf94508693506001600160a01b0390921691632ee2ed259161154d9185919060040161430b565b60206040518083038186803b15801561156557600080fd5b505afa158015611579573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061159d9190810190613829565b6007546020850151604051638ab3e96560e01b81526001600160a01b0390921691638ab3e965916115d39189919060040161430b565b60206040518083038186803b1580156115eb57600080fd5b505afa1580156115ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116239190810190613829565b6007546020860151604051633007230f60e11b81526001600160a01b039092169163600e461e91611659918a919060040161430b565b60206040518083038186803b15801561167157600080fd5b505afa158015611685573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116a99190810190613829565b600754602087015160405163c46fcd7560e01b81526001600160a01b039092169163c46fcd75916116df918b919060040161430b565b60206040518083038186803b1580156116f757600080fd5b505afa15801561170b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061172f9190810190613829565b6020808801518051910151604051610f73979695949392919033906143a5565b6117576120cf565b61176057600080fd5b806001600160a01b03811661177457600080fd5b6001600160a01b03811630141561178a57600080fd5b6000546001600160a01b03838116610100909204161461180157600080546001600160a01b03848116610100908102610100600160a81b03198416179093556040519290910416907f977e5fa58e458501775e0008d275006294c5249e3c08d1d0e3a9f3acad14f6e49061090d908390869061426f565b5050565b61180d6120e5565b61181657600080fd5b61181e613053565b6040518060400160405280846001600160a01b0316815260200183815250905061184c84826001600061274d565b600754604051632ee2ed2560e01b81527f55681e18b795929fa6b2ebef09244e035285788d963bf5d6e3968dc2bf8addf09186916001600160a01b0390911690632ee2ed25906118a2908490879060040161430b565b60206040518083038186803b1580156118ba57600080fd5b505afa1580156118ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118f29190810190613829565b600754604051638ab3e96560e01b81526001600160a01b0390911690638ab3e96590611924908a90889060040161430b565b60206040518083038186803b15801561193c57600080fd5b505afa158015611950573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506119749190810190613829565b600754604051633007230f60e11b81526001600160a01b039091169063600e461e906119a6908b90899060040161430b565b60206040518083038186803b1580156119be57600080fd5b505afa1580156119d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506119f69190810190613829565b60075460405163c46fcd7560e01b81526001600160a01b039091169063c46fcd7590611a28908c908a9060040161430b565b60206040518083038186803b158015611a4057600080fd5b505afa158015611a54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a789190810190613829565b888833604051611a8f9897969594939291906143a5565b60405180910390a150505050565b6007546040805180820182526001600160a01b03858116825260208201859052915163da473c5760e01b8152600093929092169163da473c57916107af9188919060040161430b565b6007546040805180820182526001600160a01b038581168252602082018590529151631b90e3c160e01b81526000939290921691631b90e3c1916107af9188919060040161430b565b611b376120e5565b611b4057600080fd5b806001600160a01b038116611b5457600080fd5b6001600160a01b038116301415611b6a57600080fd5b6001546001600160a01b0383811691161461180157600180546001600160a01b038481166001600160a01b03198316179092556040519116907f9f611b789425d0d5b90b920f1b2852907dd865c80074a30b1629aaa041d1812c9061090d908390869061426f565b611bda6120cf565b611be357600080fd5b6005805460ff60a01b1916600160a01b1790556040517f9c567b65fe8caab5ec7bc979a498a1322c1d4baf01a30727cbca137187560ea290600090a1565b6007546040805180820182526001600160a01b03858116825260208201859052915163076470a560e31b81526000939290921691633b23852891610b6e9188919060040161430b565b611c72613053565b6040518060400160405280846001600160a01b03168152602001838152509050611c9f338260018061274d565b600754604051632ee2ed2560e01b81527f46e3d3c7067c83d22286a7cf49b1ac45b28d128a51b1d4a3b9bdc3927a6da0be9133916001600160a01b0390911690632ee2ed2590611cf590849087906004016141ec565b60206040518083038186803b158015611d0d57600080fd5b505afa158015611d21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d459190810190613829565b600754604051638ab3e96560e01b81526001600160a01b0390911690638ab3e96590611d7790339088906004016141ec565b60206040518083038186803b158015611d8f57600080fd5b505afa158015611da3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611dc79190810190613829565b600754604051633007230f60e11b81526001600160a01b039091169063600e461e90611df990339089906004016141ec565b60206040518083038186803b158015611e1157600080fd5b505afa158015611e25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e499190810190613829565b60075460405163c46fcd7560e01b81526001600160a01b039091169063c46fcd7590611e7b9033908a906004016141ec565b60206040518083038186803b158015611e9357600080fd5b505afa158015611ea7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611ecb9190810190613829565b888860405161090d9796959493929190614207565b6007546040805180820182526001600160a01b03858116825260208201859052915163160ed0cd60e11b81526060939290921691632c1da19a916105bf9188919060040161430b565b6007546040805180820182526001600160a01b038581168252602082018590529151632ee2ed2560e01b81526000939290921691632ee2ed25916107af9188919060040161430b565b6007546040805180820182526001600160a01b0385811682526020820185905291516345a76a6160e11b81526000939290921691638b4ed4c2916107af9188919060040161430b565b60005461010090046001600160a01b031681565b6004546001600160a01b031681565b6008546001600160a01b031681565b6007546040805180820182526001600160a01b0385811682526020820185905291516356ec907560e01b815260009392909216916356ec9075916107af9188919060040161430b565b6007546040805180820182526001600160a01b038581168252602082018590529151635658722960e01b8152600093929092169163565872299161207f9188919060040161430b565b60206040518083038186803b15801561209757600080fd5b505afa1580156120ab573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061061391908101906136d6565b60005461010090046001600160a01b0316331490565b6001546001600160a01b0316331490565b60035460405163273f8b6560e11b815284916001600160a01b031690634e7f16ca906121269084906004016145dc565b60206040518083038186803b15801561213e57600080fd5b505afa158015612152573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612176919081019061380b565b6121925760405162461bcd60e51b8152600401610d8a906145bc565b600260009054906101000a90046001600160a01b03166001600160a01b031663b6bf41766040518163ffffffff1660e01b815260040160206040518083038186803b1580156121e057600080fd5b505afa1580156121f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506122189190810190613829565b4310156122375760405162461bcd60e51b8152600401610d8a9061453c565b60035460405163f59d1a7560e01b81526001600160a01b039091169063f59d1a759061226990879089906004016145ed565b60206040518083038186803b15801561228157600080fd5b505afa158015612295573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506122b9919081019061380b565b6122d55760405162461bcd60e51b8152600401610d8a9061457c565b600754602085015160405163076470a560e31b81526001600160a01b0390921691633b2385289161230b9189919060040161430b565b60206040518083038186803b15801561232357600080fd5b505afa158015612337573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061235b919081019061380b565b15806123e857506007546020850151604051637ff81c3760e01b81526001600160a01b0390921691637ff81c37916123989189919060040161430b565b60206040518083038186803b1580156123b057600080fd5b505afa1580156123c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506123e8919081019061380b565b6124045760405162461bcd60e51b8152600401610d8a9061456c565b600854602085015160405163076470a560e31b81526001600160a01b0390921691633b2385289161243a9189919060040161430b565b60206040518083038186803b15801561245257600080fd5b505afa158015612466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061248a919081019061380b565b158061251757506008546020850151604051637ff81c3760e01b81526001600160a01b0390921691637ff81c37916124c79189919060040161430b565b60206040518083038186803b1580156124df57600080fd5b505afa1580156124f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612517919081019061380b565b6125335760405162461bcd60e51b8152600401610d8a9061459c565b600080612540868861295c565b6009546020890151604051633858654b60e01b815293955091935084926001600160a01b0390911691633858654b9161257d918c9160040161430b565b60206040518083038186803b15801561259557600080fd5b505afa1580156125a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125cd9190810190613829565b106125ea5760405162461bcd60e51b8152600401610d8a9061458c565b6007546001600160a01b031663bb3bffe088848489612655612612838363ffffffff612b1116565b6126498f8f60200151600560009054906101000a90046001600160a01b03166001600160a01b0316612b509092919063ffffffff16565b9063ffffffff612d4d16565b8c602001518d60c001518c8f60a00151602001516000015173b99f3f4aacb6e1197a623919103b99f4b41aaef0635174abe96040518163ffffffff1660e01b815260040160006040518083038186803b1580156126b157600080fd5b505af41580156126c5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126ed91908101906138b3565b6040518b63ffffffff1660e01b81526004016127129a9998979695949392919061441c565b600060405180830381600087803b15801561272c57600080fd5b505af1158015612740573d6000803e3d6000fd5b5050505050505050505050565b60075460405163076470a560e31b81526001600160a01b0390911690633b2385289061277f908790879060040161430b565b60206040518083038186803b15801561279757600080fd5b505afa1580156127ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127cf919081019061380b565b6127eb5760405162461bcd60e51b8152600401610d8a906145ac565b600754604051637ff81c3760e01b81526001600160a01b0390911690637ff81c379061281d908790879060040161430b565b60206040518083038186803b15801561283557600080fd5b505afa158015612849573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061286d919081019061380b565b1561288a5760405162461bcd60e51b8152600401610d8a9061454c565b6007546040516335a4238360e01b81526001600160a01b03909116906335a42383906128c0908790879087908790600401614319565b600060405180830381600087803b1580156128da57600080fd5b505af11580156128ee573d6000803e3d6000fd5b5050600854604051632ce4e29b60e21b81526001600160a01b03909116925063b3938a6c9150612924908790879060040161430b565b600060405180830381600087803b15801561293e57600080fd5b505af1158015612952573d6000803e3d6000fd5b5050505050505050565b602082015160c08301516005546000928392839261298e926001600160a01b039091169187919063ffffffff612d8016565b600954602087015160c088015160405163bc8dd4cd60e01b81529394506000936001600160a01b039093169263bc8dd4cd926129ce928a9260040161434e565b60206040518083038186803b1580156129e657600080fd5b505afa1580156129fa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a1e9190810190613829565b60035460405163d308b9db60e01b81529192506001600160a01b03169063d308b9db90612a5190899089906004016145ed565b60206040518083038186803b158015612a6957600080fd5b505afa158015612a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612aa1919081019061380b565b15612ade57604080870151805191015151909450612ad7908290612acb908563ffffffff612b1116565b9063ffffffff612b1116565b9250612b08565b6060860151805160409091015151909450612b05908290612acb908563ffffffff612b1116565b92505b50509250929050565b6000808212158015612b2557508282840313155b80612b3c5750600082128015612b3c575082828403135b612b4557600080fd5b508082035b92915050565b6000610613846001600160a01b03166371f4ec5185876001600160a01b0316634652ec746040518163ffffffff1660e01b815260040160206040518083038186803b158015612b9e57600080fd5b505afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612bd69190810190613829565b865160208801516040516001600160e01b031960e087901b168152612c01949392919060040161428a565b60206040518083038186803b158015612c1957600080fd5b505afa158015612c2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c519190810190613829565b856001600160a01b03166371f4ec5186886001600160a01b031663ded113106040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9a57600080fd5b505afa158015612cae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612cd29190810190613829565b875160208901516040516001600160e01b031960e087901b168152612cfd949392919060040161428a565b60206040518083038186803b158015612d1557600080fd5b505afa158015612d29573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126499190810190613829565b6000828201818312801590612d625750838112155b80612d775750600083128015612d7757508381125b61061657600080fd5b600080612d8f86868686612d9c565b509150505b949350505050565b600080600080876001600160a01b031663a246138c888a6001600160a01b031663ded113106040518163ffffffff1660e01b815260040160206040518083038186803b158015612deb57600080fd5b505afa158015612dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612e239190810190613829565b895160208b01516040516001600160e01b031960e087901b168152612e5094939291908c906004016142bf565b604080518083038186803b158015612e6757600080fd5b505afa158015612e7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612e9f9190810190613883565b91509150600080896001600160a01b031663a246138c8a8c6001600160a01b0316634652ec746040518163ffffffff1660e01b815260040160206040518083038186803b158015612eef57600080fd5b505afa158015612f03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612f279190810190613829565b8b5160208d01516040516001600160e01b031960e087901b168152612f5494939291908e906004016142bf565b604080518083038186803b158015612f6b57600080fd5b505afa158015612f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612fa39190810190613883565b9092509050612fb8848363ffffffff612d4d16565b60405163a682d5ad60e01b8152909650730ff948c236c8d4dfcd0168bf243314c8ff8ec9679063a682d5ad90612ff4908690859060040161460d565b60206040518083038186803b15801561300c57600080fd5b505af4158015613020573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506130449190810190613829565b94505050505094509492505050565b604080518082019091526000808252602082015290565b8035612b4a8161474c565b8051612b4a8161474c565b600082601f83011261309157600080fd5b81356130a461309f8261464e565b614628565b915081818352602084019350602081019050838560808402820111156130c957600080fd5b60005b838110156130f757816130df88826132cb565b845250602090920191608091909101906001016130cc565b5050505092915050565b8051612b4a81614760565b8035612b4a81614769565b8051612b4a81614769565b8035612b4a81614772565b8051612b4a8161477b565b600082601f83011261314957600080fd5b813561315761309f8261466e565b9150808252602083016020830185838301111561317357600080fd5b61317e8382846146fd565b50505092915050565b600082601f83011261319857600080fd5b81516131a661309f8261466e565b915080825260208301602083018583830111156131c257600080fd5b61317e838284614709565b6000604082840312156131df57600080fd5b6131e96040614628565b905060006131f7848461306a565b82525060206132088484830161310c565b60208301525092915050565b60006040828403121561322657600080fd5b6132306040614628565b905060006131f7848461310c565b60006060828403121561325057600080fd5b61325a6040614628565b90506000613268848461310c565b8252506020613208848483016131cd565b60006040828403121561328b57600080fd5b6132956040614628565b905060006132a3848461310c565b82525060208201356001600160401b038111156132bf57600080fd5b61320884828501613138565b6000608082840312156132dd57600080fd5b6132e76040614628565b905060006132f5848461310c565b82525060206132088484830161323e565b600060a0828403121561331857600080fd5b6133226080614628565b90506000613330848461310c565b82525060206133418484830161306a565b602083015250604061335584828501613214565b60408301525060808201356001600160401b0381111561337457600080fd5b61338084828501613628565b60608301525092915050565b600060c0828403121561339e57600080fd5b6133a860a0614628565b905060006133b6848461310c565b82525060206133c78484830161306a565b60208301525060406133db84828501613214565b60408301525060808201356001600160401b038111156133fa57600080fd5b613406848285016135d6565b60608301525060a08201356001600160401b0381111561342557600080fd5b61343184828501613138565b60808301525092915050565b6000610220828403121561345057600080fd5b61345b610100614628565b90506000613469848461310c565b825250602061347a848483016131cd565b60208301525060608201356001600160401b0381111561349957600080fd5b6134a58482850161338c565b60408301525060808201356001600160401b038111156134c457600080fd5b6134d084828501613306565b60608301525060a06134e484828501613214565b60808301525060e06134f884828501613671565b60a0830152506101e061350d8482850161310c565b60c0830152506102008201356001600160401b0381111561352d57600080fd5b61353984828501613279565b60e08301525092915050565b60006080828403121561355757600080fd5b6135616040614628565b9050600061356f848461310c565b82525060206132088484830160006060828403121561358d57600080fd5b6135976060614628565b905060006135a5848461310c565b82525060206135b68484830161310c565b60208301525060406135ca848285016136ad565b60408301525092915050565b6000608082840312156135e857600080fd5b6135f26040614628565b90506000613600848461323e565b82525060608201356001600160401b0381111561361c57600080fd5b61320884828501613080565b60006020828403121561363a57600080fd5b6136446020614628565b905081356001600160401b0381111561365c57600080fd5b61366884828501613080565b82525092915050565b6000610100828403121561368457600080fd5b61368e6040614628565b9050600061369c8484613545565b825250608061320884848301613545565b8035612b4a81614788565b6000602082840312156136ca57600080fd5b6000612d94848461306a565b6000602082840312156136e857600080fd5b6000612d948484613075565b60008060006060848603121561370957600080fd5b6000613715868661306a565b93505060206137268682870161306a565b92505060406137378682870161310c565b9150509250925092565b6000806040838503121561375457600080fd5b6000613760858561306a565b92505060208301356001600160401b0381111561377c57600080fd5b6137888582860161343d565b9150509250929050565b6000806000606084860312156137a757600080fd5b60006137b3868661306a565b93505060208401356001600160401b038111156137cf57600080fd5b6137268682870161343d565b600080604083850312156137ee57600080fd5b60006137fa858561306a565b92505060206137888582860161310c565b60006020828403121561381d57600080fd5b6000612d948484613101565b60006020828403121561383b57600080fd5b6000612d948484613117565b60006020828403121561385957600080fd5b6000612d948484613122565b60006020828403121561387757600080fd5b6000612d94848461312d565b6000806040838503121561389657600080fd5b60006138a28585613117565b925050602061378885828601613117565b6000602082840312156138c557600080fd5b81516001600160401b038111156138db57600080fd5b612d9484828501613187565b600080604083850312156138fa57600080fd5b82356001600160401b0381111561391057600080fd5b6137fa8582860161343d565b60006139288383613f77565b505060800190565b613939816146e7565b82525050565b613939816146a8565b60006139538261469b565b61395d818561469f565b935061396883614695565b8060005b83811015613996578151613980888261391c565b975061398b83614695565b92505060010161396c565b509495945050505050565b613939816146b3565b613939816146b8565b613939816146bb565b613939816146f2565b60006139d08261469b565b6139da818561469f565b93506139ea818560208601614709565b6139f381614735565b9093019392505050565b6000613a0a603f8361469f565b7f4f7065726174696f6e616c206d6f6465206973206e6f74206e6f726d616c205b81527f436f6e666967757261626c654f7065726174696f6e616c2e736f6c3a32325d00602082015260400192915050565b6000613a6960308361469f565b7f42616c616e636520747261636b65722066726f7a656e205b42616c616e63655481526f7261636b61626c652e736f6c3a34335d60801b602082015260400192915050565b6000613abb60678361469f565b7f43757272656e7420626c6f636b206e756d6265722062656c6f77206561726c6981527f65737420736574746c656d656e7420626c6f636b206e756d626572205b44726960208201526000805160206147928339815191526040820152666f6c3a3438395d60c81b606082015260800192915050565b6000613b3e60458361469f565b7f50726f706f73616c20666f756e64207465726d696e61746564205b447269697081527f536574746c656d656e744368616c6c656e676542795061796d656e742e736f6c6020820152643a3534325d60d81b604082015260600192915050565b6000613bab603f8361469f565b7f57616c6c657420666f756e64206c6f636b6564205b4472696970536574746c6581527f6d656e744368616c6c656e676542795061796d656e742e736f6c3a3133345d00602082015260400192915050565b6000613c0a60618361469f565b7f4f7665726c617070696e6720647269697020736574746c656d656e742063686181527f6c6c656e67652070726f706f73616c20666f756e64205b44726969705365747460208201527f6c656d656e744368616c6c656e676542795061796d656e742e736f6c3a3530316040820152605d60f81b606082015260800192915050565b6000613c9960478361469f565b7f57616c6c6574206973206e6f74207061796d656e74207061727479205b44726981526000805160206147928339815191526020820152666f6c3a3439355d60c81b604082015260600192915050565b6000613cf660568361469f565b7f57616c6c65742773206e6f6e63652062656c6f7720686967686573742073657481527f746c6564206e6f6e6365205b4472696970536574746c656d656e744368616c6c602082015275656e676542795061796d656e742e736f6c3a3531385d60501b604082015260600192915050565b6000613d7460608361469f565b7f4f7665726c617070696e67206e756c6c20736574746c656d656e74206368616c81527f6c656e67652070726f706f73616c20666f756e64205b4472696970536574746c60208201527f656d656e744368616c6c656e676542795061796d656e742e736f6c3a3530385d604082015260600192915050565b6000613df9603d8361469f565b7f4e6f2070726f706f73616c20666f756e64205b4472696970536574746c656d6581527f6e744368616c6c656e676542795061796d656e742e736f6c3a3533385d000000602082015260400192915050565b6000613e58602e8361469f565b7f5061796d656e74207365616c73206e6f742067656e75696e65205b56616c696481526d617461626c652e736f6c3a36355d60901b602082015260400192915050565b6000613ea8602c8361469f565b7f57616c6c6574206c6f636b65722066726f7a656e205b57616c6c65744c6f636b81526b61626c652e736f6c3a34335d60a01b602082015260400192915050565b80516040830190613efa848261393f565b50602082015161076060208501826139aa565b80516040830190613efa84826139aa565b80516060830190613f2f84826139aa565b5060208201516107606020850182613ee9565b80516000906040840190613f5685826139aa565b5060208301518482036020860152613f6e82826139c5565b95945050505050565b80516080830190613f8884826139aa565b5060208201516107606020850182613f1e565b805160009060a0840190613faf85826139aa565b506020830151613fc2602086018261393f565b506040830151613fd56040860182613f0d565b5060608301518482036080860152613f6e828261418a565b805160009060c084019061400185826139aa565b506020830151614014602086018261393f565b5060408301516140276040860182613f0d565b506060830151848203608086015261403f828261415e565b915050608083015184820360a0860152613f6e82826139c5565b805160009061022084019061406e85826139aa565b5060208301516140816020860182613ee9565b50604083015184820360608601526140998282613fed565b915050606083015184820360808601526140b38282613f9b565b91505060808301516140c860a0860182613f0d565b5060a08301516140db60e08601826141a2565b5060c08301516140ef6101e08601826139aa565b5060e0830151848203610200860152613f6e8282613f42565b8051608083019061411984826139aa565b50602082015161076060208501828051606083019061413884826139aa565b50602082015161414b60208501826139aa565b50604082015161076060408501826141c7565b805160009060808401906141728582613f1e565b5060208301518482036060860152613f6e8282613948565b8051602080845260009190840190613f6e8282613948565b80516101008301906141b48482614108565b5060208201516107606080850182614108565b613939816146e1565b60208101612b4a828461393f565b60208101612b4a8284613930565b606081016141fa8285613930565b6106166020830184613ee9565b60e08101614215828a613930565b61422260208301896139aa565b61422f60408301886139aa565b61423c60608301876139aa565b61424960808301866139aa565b61425660a083018561393f565b61426360c08301846139aa565b98975050505050505050565b6040810161427d828561393f565b610616602083018461393f565b60808101614298828761393f565b6142a560208301866139aa565b6142b2604083018561393f565b613f6e60608301846139aa565b60a081016142cd828861393f565b6142da60208301876139aa565b6142e7604083018661393f565b6142f460608301856139aa565b61430160808301846139aa565b9695505050505050565b606081016141fa828561393f565b60a08101614327828761393f565b6143346020830186613ee9565b61434160608301856139a1565b613f6e60808301846139a1565b6080810161435c828661393f565b6143696020830185613ee9565b612d9460608301846139aa565b60608101614384828661393f565b81810360208301526143968185614059565b9050612d946040830184613930565b61010081016143b4828b61393f565b6143c1602083018a6139aa565b6143ce60408301896139aa565b6143db60608301886139aa565b6143e860808301876139aa565b6143f560a083018661393f565b61440260c08301856139aa565b61440f60e0830184613930565b9998505050505050505050565b610160810161442b828d61393f565b614438602083018c6139aa565b614445604083018b6139aa565b614452606083018a6139aa565b61445f60808301896139aa565b61446c60a0830188613ee9565b61447960e08301876139aa565b6144876101008301866139a1565b6144956101208301856139aa565b8181036101408301526144a881846139c5565b9c9b505050505050505050505050565b60208101612b4a82846139a1565b60208101612b4a82846139aa565b60208101612b4a82846139b3565b604081016144f082856139b3565b61061660208301846139b3565b60208101612b4a82846139bc565b6020808252810161061681846139c5565b60208082528101612b4a816139fd565b60208082528101612b4a81613a5c565b60208082528101612b4a81613aae565b60208082528101612b4a81613b31565b60208082528101612b4a81613b9e565b60208082528101612b4a81613bfd565b60208082528101612b4a81613c8c565b60208082528101612b4a81613ce9565b60208082528101612b4a81613d67565b60208082528101612b4a81613dec565b60208082528101612b4a81613e4b565b60208082528101612b4a81613e9b565b602080825281016106168184614059565b604080825281016145fe8185614059565b9050610616602083018461393f565b6040810161461b82856139aa565b61061660208301846139aa565b6040518181016001600160401b038111828210171561464657600080fd5b604052919050565b60006001600160401b0382111561466457600080fd5b5060209081020190565b60006001600160401b0382111561468457600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b6000612b4a826146d5565b151590565b90565b6000612b4a826146a8565b806146d08161473f565b919050565b6001600160a01b031690565b60ff1690565b6000612b4a826146bb565b6000612b4a826146c6565b82818337506000910152565b60005b8381101561472457818101518382015260200161470c565b838111156107605750506000910152565b601f01601f191690565b6002811061474957fe5b50565b614755816146a8565b811461474957600080fd5b614755816146b3565b614755816146b8565b614755816146bb565b6002811061474957600080fd5b614755816146e156fe6970536574746c656d656e744368616c6c656e676542795061796d656e742e73a365627a7a723158208377fca6c152a24ff05ca78673a209831b0e8caf71a351e7a734ab34c4fd3ad06c6578706572696d656e74616cf564736f6c634300050b0040000000000000000000000000f05179bac3d1fbef58a2fcd7ad0f769840027cc6
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061023b5760003560e01c8063039b9fb1146102405780630712abb0146102695780630fa6f23d146102895780631327d3d81461029e57806316987929146102b357806319139092146102d3578063240625d8146102db57806325c84441146102f05780632738a112146102f85780632aa1c9d9146103005780632f013a001461031357806334033fc11461031b5780633a5381b51461032e5780633bebdcb5146103365780633e59b70614610349578063404e896f1461035157806342cb4587146103645780634476d23b1461037757806346d1d3c41461038c5780634d3d826c1461039f5780634dc8eb79146103b257806351d7cd61146103c5578063570ca735146103cd578063598b75ad146103d55780635dc60def146103e8578063627f09c3146103f05780636c70bee9146104035780636ccb43c81461040b5780636de6a5d21461041e57806370327ea1146104315780637da5b11c14610439578063892860b21461044c578063911eb9651461045f5780639621473514610472578063972fcee0146104855780639882da6c14610498578063adfb6778146104ab578063b3ab15fb146104be578063b52d470a146104d1578063bb9357de146104d9578063c19df1e4146104ec578063ca7f47ed146104ff578063cdbf941914610512578063d5b68c6214610525578063d5f3948814610538578063e8ae41e314610540578063fa7424f214610548578063fb1a825e14610550578063fcd30b0214610563575b600080fd5b61025361024e3660046136f4565b610576565b604051610260919061450b565b60405180910390f35b61027c6102773660046136f4565b61061d565b60405161026091906144fd565b6102916106b6565b60405161026091906144d4565b6102b16102ac366004613847565b6106c5565b005b6102c66102c13660046136f4565b610766565b60405161026091906144c6565b6102916107ff565b6102e361080e565b60405161026091906144b8565b61029161081e565b6102b161082d565b6102b161030e366004613847565b610893565b6102e361091a565b6102b1610329366004613792565b610923565b610291610b16565b6102e36103443660046136f4565b610b25565b6102e3610bbe565b6102b161035f366004613847565b610bce565b6102c66103723660046136f4565b610c48565b61037f610c91565b60405161026091906141d0565b6102e361039a3660046136f4565b610ca5565b6102b16103ad3660046138e7565b610cee565b6102b16103c0366004613847565b610f7f565b610291610ff9565b61037f611008565b6102b16103e3366004613847565b611017565b6102b16110d2565b6102b16103fe366004613847565b611121565b6102916111b2565b6102b1610419366004613847565b6111c1565b6102c661042c3660046136f4565b61123b565b6102b1611284565b6102e36104473660046136f4565b6112e7565b6102b161045a366004613847565b611330565b6102b161046d366004613741565b6113eb565b6102b16104803660046136b8565b61174f565b6102b16104933660046136f4565b611805565b6102c66104a63660046136f4565b611a9d565b6102c66104b93660046136f4565b611ae6565b6102b16104cc3660046136b8565b611b2f565b6102b1611bd2565b6102e36104e73660046136f4565b611c21565b6102b16104fa3660046137db565b611c6a565b61025361050d3660046136f4565b611ee0565b6102c66105203660046136f4565b611f29565b6102c66105333660046136f4565b611f72565b61037f611fbb565b610291611fcf565b610291611fde565b6102c661055e3660046136f4565b611fed565b61037f6105713660046136f4565b612036565b6007546040805180820182526001600160a01b0385811682526020820185905291516394da13eb60e01b815260609392909216916394da13eb916105bf9188919060040161430b565b60006040518083038186803b1580156105d757600080fd5b505afa1580156105eb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261061391908101906138b3565b90505b9392505050565b6007546040805180820182526001600160a01b03858116825260208201859052915163b6e2fc3360e01b8152600093929092169163b6e2fc33916106669188919060040161430b565b60206040518083038186803b15801561067e57600080fd5b505afa158015610692573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106139190810190613865565b6006546001600160a01b031681565b6106cd6120cf565b6106d657600080fd5b806001600160a01b0381166106ea57600080fd5b60035482906001600160a01b03908116908216811461076057600380546001600160a01b038681166001600160a01b03198316179092556040519116907f1882af944a16549c3d4f60e3cd26f158b0c7aac3222cf32971fc21375ce05f609061075690839088906144e2565b60405180910390a1505b50505050565b6007546040805180820182526001600160a01b03858116825260208201859052915163c46fcd7560e01b8152600093929092169163c46fcd75916107af9188919060040161430b565b60206040518083038186803b1580156107c757600080fd5b505afa1580156107db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106139190810190613829565b6005546001600160a01b031681565b600454600160a01b900460ff1681565b6009546001600160a01b031681565b33610836610c91565b6001600160a01b03161461084957600080fd5b60005460ff161561085957600080fd5b7f787a5d936e74f4b564b9153575886059829c78cd9927b1be5e0d976b317ef7363360405161088891906141de565b60405180910390a133ff5b61089b6120cf565b6108a457600080fd5b806001600160a01b0381166108b857600080fd5b600780546001600160a01b038481166001600160a01b031983161792839055604051918116927f4f7125332801996cdeaabf9cff1ac89ddf4b52c673558936affe853ab64a88da9261090d92859216906144e2565b60405180910390a1505050565b60005460ff1681565b61092b6120e5565b61093457600080fd5b61094183838360006120f6565b6007546020830151604051632ee2ed2560e01b81527f505b0ba83acb520eb622fae274a079c14f40dd43f70fd9f1f8d2312fd4e76caf9286926001600160a01b0390911691632ee2ed259161099b9185919060040161430b565b60206040518083038186803b1580156109b357600080fd5b505afa1580156109c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109eb9190810190613829565b6007546020860151604051638ab3e96560e01b81526001600160a01b0390921691638ab3e96591610a21918a919060040161430b565b60206040518083038186803b158015610a3957600080fd5b505afa158015610a4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a719190810190613829565b600754602087015160405163c46fcd7560e01b815287926001600160a01b03169163c46fcd7591610aa6918c9160040161430b565b60206040518083038186803b158015610abe57600080fd5b505afa158015610ad2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610af69190810190613829565b602080890151805191015160405161090d979695949392919033906143a5565b6003546001600160a01b031681565b6007546040805180820182526001600160a01b038581168252602082018590529151635482c73560e01b81526000939290921691635482c73591610b6e9188919060040161430b565b60206040518083038186803b158015610b8657600080fd5b505afa158015610b9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610613919081019061380b565b600554600160a01b900460ff1681565b610bd66120cf565b610bdf57600080fd5b806001600160a01b038116610bf357600080fd5b600980546001600160a01b038481166001600160a01b031983161792839055604051918116927f6d4735156f5fb1047cfcd4a9edf19e3291aec19d53916f8fee650ca3c2d739109261090d92859216906144e2565b6007546040805180820182526001600160a01b038581168252602082018590529151633007230f60e11b8152600093929092169163600e461e916107af9188919060040161430b565b60005461010090046001600160a01b031690565b6007546040805180820182526001600160a01b038581168252602082018590529151637ff81c3760e01b81526000939290921691637ff81c3791610b6e9188919060040161430b565b60048054604051631293efbb60e21b81526001600160a01b0390911691634a4fbeec91610d1d913391016141de565b60206040518083038186803b158015610d3557600080fd5b505afa158015610d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d6d919081019061380b565b15610d935760405162461bcd60e51b8152600401610d8a9061455c565b60405180910390fd5b610da033838360016120f6565b6007546020830151604051632ee2ed2560e01b81527f1d8a75ed090cb569da62b746afdb83f0969831d5d9b9bb1a11320bc11c438c9f9233926001600160a01b0390911691632ee2ed2591610dfa918591906004016141ec565b60206040518083038186803b158015610e1257600080fd5b505afa158015610e26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e4a9190810190613829565b6007546020860151604051638ab3e96560e01b81526001600160a01b0390921691638ab3e96591610e80913391906004016141ec565b60206040518083038186803b158015610e9857600080fd5b505afa158015610eac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ed09190810190613829565b600754602087015160405163c46fcd7560e01b815287926001600160a01b03169163c46fcd7591610f059133916004016141ec565b60206040518083038186803b158015610f1d57600080fd5b505afa158015610f31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f559190810190613829565b6020808901518051910151604051610f739796959493929190614207565b60405180910390a15050565b610f876120cf565b610f9057600080fd5b806001600160a01b038116610fa457600080fd5b600680546001600160a01b038481166001600160a01b031983161792839055604051918116927f663141f76be1f253f0e608edd55c18b0816521f3b635e072c1c2f710dde6ed199261090d92859216906144e2565b6007546001600160a01b031681565b6001546001600160a01b031681565b61101f6120cf565b61102857600080fd5b806001600160a01b03811661103c57600080fd5b60055482906001600160a01b03908116908216811461076057600554600160a01b900460ff161561107f5760405162461bcd60e51b8152600401610d8a9061452c565b600580546001600160a01b038681166001600160a01b03198316179092556040519116907fb2a91d3a71b0c5bc7c083153b3474378e489506ba98bd4ddb1b9056fdc594bb59061075690839088906144e2565b6110da6120cf565b6110e357600080fd5b6004805460ff60a01b1916600160a01b1790556040517f56ec8900b9c4bf84f4b715a53068ca06961dd49084c07b481931e2c2045346e690600090a1565b6111296120cf565b61113257600080fd5b806001600160a01b03811661114657600080fd5b60025482906001600160a01b03908116908216811461076057600280546001600160a01b038681166001600160a01b03198316179092556040519116907f634f61bf00e14adedce330c80c2823e16e184f189ebe853e1ddecc4a268477ff9061075690839088906144e2565b6002546001600160a01b031681565b6111c96120cf565b6111d257600080fd5b806001600160a01b0381166111e657600080fd5b600880546001600160a01b038481166001600160a01b031983161792839055604051918116927ff21c127205310467822e10c64b2d9ffae588e019194d6af71f2bdddc0b7ef5269261090d92859216906144e2565b6007546040805180820182526001600160a01b03858116825260208201859052915163374852cb60e11b81526000939290921691636e90a596916107af9188919060040161430b565b3361128d610c91565b6001600160a01b0316146112a057600080fd5b6000805460ff191660011790556040517fd5a2a04a775c741c2ca0dc46ea7ce4835190e1aaf1ca018def0e82568ec33616906112dd9033906141de565b60405180910390a1565b6007546040805180820182526001600160a01b0385811682526020820185905291516333ca4eab60e21b8152600093929092169163cf293aac91610b6e9188919060040161430b565b6113386120cf565b61134157600080fd5b806001600160a01b03811661135557600080fd5b60045482906001600160a01b03908116908216811461076057600454600160a01b900460ff16156113985760405162461bcd60e51b8152600401610d8a906145cc565b600480546001600160a01b038681166001600160a01b03198316179092556040519116907fa44d361e26327b72a7ccbeae801b3c5cd7677ea4fa74168b289e273c46bfecfc9061075690839088906144e2565b600260009054906101000a90046001600160a01b03166001600160a01b031663f71e860f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561143957600080fd5b505afa15801561144d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611471919081019061380b565b61148d5760405162461bcd60e51b8152600401610d8a9061451c565b600654604051630eae657960e11b81526001600160a01b0390911690631d5ccaf2906114c190859085903390600401614376565b600060405180830381600087803b1580156114db57600080fd5b505af11580156114ef573d6000803e3d6000fd5b50506007546020840151604051632ee2ed2560e01b81527fffa28bfeaa617be065ef4f9cbd4448b8ac8e99c98f00741cd2d78fa4732cf9cf94508693506001600160a01b0390921691632ee2ed259161154d9185919060040161430b565b60206040518083038186803b15801561156557600080fd5b505afa158015611579573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061159d9190810190613829565b6007546020850151604051638ab3e96560e01b81526001600160a01b0390921691638ab3e965916115d39189919060040161430b565b60206040518083038186803b1580156115eb57600080fd5b505afa1580156115ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116239190810190613829565b6007546020860151604051633007230f60e11b81526001600160a01b039092169163600e461e91611659918a919060040161430b565b60206040518083038186803b15801561167157600080fd5b505afa158015611685573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116a99190810190613829565b600754602087015160405163c46fcd7560e01b81526001600160a01b039092169163c46fcd75916116df918b919060040161430b565b60206040518083038186803b1580156116f757600080fd5b505afa15801561170b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061172f9190810190613829565b6020808801518051910151604051610f73979695949392919033906143a5565b6117576120cf565b61176057600080fd5b806001600160a01b03811661177457600080fd5b6001600160a01b03811630141561178a57600080fd5b6000546001600160a01b03838116610100909204161461180157600080546001600160a01b03848116610100908102610100600160a81b03198416179093556040519290910416907f977e5fa58e458501775e0008d275006294c5249e3c08d1d0e3a9f3acad14f6e49061090d908390869061426f565b5050565b61180d6120e5565b61181657600080fd5b61181e613053565b6040518060400160405280846001600160a01b0316815260200183815250905061184c84826001600061274d565b600754604051632ee2ed2560e01b81527f55681e18b795929fa6b2ebef09244e035285788d963bf5d6e3968dc2bf8addf09186916001600160a01b0390911690632ee2ed25906118a2908490879060040161430b565b60206040518083038186803b1580156118ba57600080fd5b505afa1580156118ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118f29190810190613829565b600754604051638ab3e96560e01b81526001600160a01b0390911690638ab3e96590611924908a90889060040161430b565b60206040518083038186803b15801561193c57600080fd5b505afa158015611950573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506119749190810190613829565b600754604051633007230f60e11b81526001600160a01b039091169063600e461e906119a6908b90899060040161430b565b60206040518083038186803b1580156119be57600080fd5b505afa1580156119d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506119f69190810190613829565b60075460405163c46fcd7560e01b81526001600160a01b039091169063c46fcd7590611a28908c908a9060040161430b565b60206040518083038186803b158015611a4057600080fd5b505afa158015611a54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a789190810190613829565b888833604051611a8f9897969594939291906143a5565b60405180910390a150505050565b6007546040805180820182526001600160a01b03858116825260208201859052915163da473c5760e01b8152600093929092169163da473c57916107af9188919060040161430b565b6007546040805180820182526001600160a01b038581168252602082018590529151631b90e3c160e01b81526000939290921691631b90e3c1916107af9188919060040161430b565b611b376120e5565b611b4057600080fd5b806001600160a01b038116611b5457600080fd5b6001600160a01b038116301415611b6a57600080fd5b6001546001600160a01b0383811691161461180157600180546001600160a01b038481166001600160a01b03198316179092556040519116907f9f611b789425d0d5b90b920f1b2852907dd865c80074a30b1629aaa041d1812c9061090d908390869061426f565b611bda6120cf565b611be357600080fd5b6005805460ff60a01b1916600160a01b1790556040517f9c567b65fe8caab5ec7bc979a498a1322c1d4baf01a30727cbca137187560ea290600090a1565b6007546040805180820182526001600160a01b03858116825260208201859052915163076470a560e31b81526000939290921691633b23852891610b6e9188919060040161430b565b611c72613053565b6040518060400160405280846001600160a01b03168152602001838152509050611c9f338260018061274d565b600754604051632ee2ed2560e01b81527f46e3d3c7067c83d22286a7cf49b1ac45b28d128a51b1d4a3b9bdc3927a6da0be9133916001600160a01b0390911690632ee2ed2590611cf590849087906004016141ec565b60206040518083038186803b158015611d0d57600080fd5b505afa158015611d21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d459190810190613829565b600754604051638ab3e96560e01b81526001600160a01b0390911690638ab3e96590611d7790339088906004016141ec565b60206040518083038186803b158015611d8f57600080fd5b505afa158015611da3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611dc79190810190613829565b600754604051633007230f60e11b81526001600160a01b039091169063600e461e90611df990339089906004016141ec565b60206040518083038186803b158015611e1157600080fd5b505afa158015611e25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e499190810190613829565b60075460405163c46fcd7560e01b81526001600160a01b039091169063c46fcd7590611e7b9033908a906004016141ec565b60206040518083038186803b158015611e9357600080fd5b505afa158015611ea7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611ecb9190810190613829565b888860405161090d9796959493929190614207565b6007546040805180820182526001600160a01b03858116825260208201859052915163160ed0cd60e11b81526060939290921691632c1da19a916105bf9188919060040161430b565b6007546040805180820182526001600160a01b038581168252602082018590529151632ee2ed2560e01b81526000939290921691632ee2ed25916107af9188919060040161430b565b6007546040805180820182526001600160a01b0385811682526020820185905291516345a76a6160e11b81526000939290921691638b4ed4c2916107af9188919060040161430b565b60005461010090046001600160a01b031681565b6004546001600160a01b031681565b6008546001600160a01b031681565b6007546040805180820182526001600160a01b0385811682526020820185905291516356ec907560e01b815260009392909216916356ec9075916107af9188919060040161430b565b6007546040805180820182526001600160a01b038581168252602082018590529151635658722960e01b8152600093929092169163565872299161207f9188919060040161430b565b60206040518083038186803b15801561209757600080fd5b505afa1580156120ab573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061061391908101906136d6565b60005461010090046001600160a01b0316331490565b6001546001600160a01b0316331490565b60035460405163273f8b6560e11b815284916001600160a01b031690634e7f16ca906121269084906004016145dc565b60206040518083038186803b15801561213e57600080fd5b505afa158015612152573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612176919081019061380b565b6121925760405162461bcd60e51b8152600401610d8a906145bc565b600260009054906101000a90046001600160a01b03166001600160a01b031663b6bf41766040518163ffffffff1660e01b815260040160206040518083038186803b1580156121e057600080fd5b505afa1580156121f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506122189190810190613829565b4310156122375760405162461bcd60e51b8152600401610d8a9061453c565b60035460405163f59d1a7560e01b81526001600160a01b039091169063f59d1a759061226990879089906004016145ed565b60206040518083038186803b15801561228157600080fd5b505afa158015612295573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506122b9919081019061380b565b6122d55760405162461bcd60e51b8152600401610d8a9061457c565b600754602085015160405163076470a560e31b81526001600160a01b0390921691633b2385289161230b9189919060040161430b565b60206040518083038186803b15801561232357600080fd5b505afa158015612337573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061235b919081019061380b565b15806123e857506007546020850151604051637ff81c3760e01b81526001600160a01b0390921691637ff81c37916123989189919060040161430b565b60206040518083038186803b1580156123b057600080fd5b505afa1580156123c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506123e8919081019061380b565b6124045760405162461bcd60e51b8152600401610d8a9061456c565b600854602085015160405163076470a560e31b81526001600160a01b0390921691633b2385289161243a9189919060040161430b565b60206040518083038186803b15801561245257600080fd5b505afa158015612466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061248a919081019061380b565b158061251757506008546020850151604051637ff81c3760e01b81526001600160a01b0390921691637ff81c37916124c79189919060040161430b565b60206040518083038186803b1580156124df57600080fd5b505afa1580156124f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612517919081019061380b565b6125335760405162461bcd60e51b8152600401610d8a9061459c565b600080612540868861295c565b6009546020890151604051633858654b60e01b815293955091935084926001600160a01b0390911691633858654b9161257d918c9160040161430b565b60206040518083038186803b15801561259557600080fd5b505afa1580156125a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125cd9190810190613829565b106125ea5760405162461bcd60e51b8152600401610d8a9061458c565b6007546001600160a01b031663bb3bffe088848489612655612612838363ffffffff612b1116565b6126498f8f60200151600560009054906101000a90046001600160a01b03166001600160a01b0316612b509092919063ffffffff16565b9063ffffffff612d4d16565b8c602001518d60c001518c8f60a00151602001516000015173b99f3f4aacb6e1197a623919103b99f4b41aaef0635174abe96040518163ffffffff1660e01b815260040160006040518083038186803b1580156126b157600080fd5b505af41580156126c5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126ed91908101906138b3565b6040518b63ffffffff1660e01b81526004016127129a9998979695949392919061441c565b600060405180830381600087803b15801561272c57600080fd5b505af1158015612740573d6000803e3d6000fd5b5050505050505050505050565b60075460405163076470a560e31b81526001600160a01b0390911690633b2385289061277f908790879060040161430b565b60206040518083038186803b15801561279757600080fd5b505afa1580156127ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127cf919081019061380b565b6127eb5760405162461bcd60e51b8152600401610d8a906145ac565b600754604051637ff81c3760e01b81526001600160a01b0390911690637ff81c379061281d908790879060040161430b565b60206040518083038186803b15801561283557600080fd5b505afa158015612849573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061286d919081019061380b565b1561288a5760405162461bcd60e51b8152600401610d8a9061454c565b6007546040516335a4238360e01b81526001600160a01b03909116906335a42383906128c0908790879087908790600401614319565b600060405180830381600087803b1580156128da57600080fd5b505af11580156128ee573d6000803e3d6000fd5b5050600854604051632ce4e29b60e21b81526001600160a01b03909116925063b3938a6c9150612924908790879060040161430b565b600060405180830381600087803b15801561293e57600080fd5b505af1158015612952573d6000803e3d6000fd5b5050505050505050565b602082015160c08301516005546000928392839261298e926001600160a01b039091169187919063ffffffff612d8016565b600954602087015160c088015160405163bc8dd4cd60e01b81529394506000936001600160a01b039093169263bc8dd4cd926129ce928a9260040161434e565b60206040518083038186803b1580156129e657600080fd5b505afa1580156129fa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a1e9190810190613829565b60035460405163d308b9db60e01b81529192506001600160a01b03169063d308b9db90612a5190899089906004016145ed565b60206040518083038186803b158015612a6957600080fd5b505afa158015612a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612aa1919081019061380b565b15612ade57604080870151805191015151909450612ad7908290612acb908563ffffffff612b1116565b9063ffffffff612b1116565b9250612b08565b6060860151805160409091015151909450612b05908290612acb908563ffffffff612b1116565b92505b50509250929050565b6000808212158015612b2557508282840313155b80612b3c5750600082128015612b3c575082828403135b612b4557600080fd5b508082035b92915050565b6000610613846001600160a01b03166371f4ec5185876001600160a01b0316634652ec746040518163ffffffff1660e01b815260040160206040518083038186803b158015612b9e57600080fd5b505afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612bd69190810190613829565b865160208801516040516001600160e01b031960e087901b168152612c01949392919060040161428a565b60206040518083038186803b158015612c1957600080fd5b505afa158015612c2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c519190810190613829565b856001600160a01b03166371f4ec5186886001600160a01b031663ded113106040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9a57600080fd5b505afa158015612cae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612cd29190810190613829565b875160208901516040516001600160e01b031960e087901b168152612cfd949392919060040161428a565b60206040518083038186803b158015612d1557600080fd5b505afa158015612d29573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126499190810190613829565b6000828201818312801590612d625750838112155b80612d775750600083128015612d7757508381125b61061657600080fd5b600080612d8f86868686612d9c565b509150505b949350505050565b600080600080876001600160a01b031663a246138c888a6001600160a01b031663ded113106040518163ffffffff1660e01b815260040160206040518083038186803b158015612deb57600080fd5b505afa158015612dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612e239190810190613829565b895160208b01516040516001600160e01b031960e087901b168152612e5094939291908c906004016142bf565b604080518083038186803b158015612e6757600080fd5b505afa158015612e7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612e9f9190810190613883565b91509150600080896001600160a01b031663a246138c8a8c6001600160a01b0316634652ec746040518163ffffffff1660e01b815260040160206040518083038186803b158015612eef57600080fd5b505afa158015612f03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612f279190810190613829565b8b5160208d01516040516001600160e01b031960e087901b168152612f5494939291908e906004016142bf565b604080518083038186803b158015612f6b57600080fd5b505afa158015612f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612fa39190810190613883565b9092509050612fb8848363ffffffff612d4d16565b60405163a682d5ad60e01b8152909650730ff948c236c8d4dfcd0168bf243314c8ff8ec9679063a682d5ad90612ff4908690859060040161460d565b60206040518083038186803b15801561300c57600080fd5b505af4158015613020573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506130449190810190613829565b94505050505094509492505050565b604080518082019091526000808252602082015290565b8035612b4a8161474c565b8051612b4a8161474c565b600082601f83011261309157600080fd5b81356130a461309f8261464e565b614628565b915081818352602084019350602081019050838560808402820111156130c957600080fd5b60005b838110156130f757816130df88826132cb565b845250602090920191608091909101906001016130cc565b5050505092915050565b8051612b4a81614760565b8035612b4a81614769565b8051612b4a81614769565b8035612b4a81614772565b8051612b4a8161477b565b600082601f83011261314957600080fd5b813561315761309f8261466e565b9150808252602083016020830185838301111561317357600080fd5b61317e8382846146fd565b50505092915050565b600082601f83011261319857600080fd5b81516131a661309f8261466e565b915080825260208301602083018583830111156131c257600080fd5b61317e838284614709565b6000604082840312156131df57600080fd5b6131e96040614628565b905060006131f7848461306a565b82525060206132088484830161310c565b60208301525092915050565b60006040828403121561322657600080fd5b6132306040614628565b905060006131f7848461310c565b60006060828403121561325057600080fd5b61325a6040614628565b90506000613268848461310c565b8252506020613208848483016131cd565b60006040828403121561328b57600080fd5b6132956040614628565b905060006132a3848461310c565b82525060208201356001600160401b038111156132bf57600080fd5b61320884828501613138565b6000608082840312156132dd57600080fd5b6132e76040614628565b905060006132f5848461310c565b82525060206132088484830161323e565b600060a0828403121561331857600080fd5b6133226080614628565b90506000613330848461310c565b82525060206133418484830161306a565b602083015250604061335584828501613214565b60408301525060808201356001600160401b0381111561337457600080fd5b61338084828501613628565b60608301525092915050565b600060c0828403121561339e57600080fd5b6133a860a0614628565b905060006133b6848461310c565b82525060206133c78484830161306a565b60208301525060406133db84828501613214565b60408301525060808201356001600160401b038111156133fa57600080fd5b613406848285016135d6565b60608301525060a08201356001600160401b0381111561342557600080fd5b61343184828501613138565b60808301525092915050565b6000610220828403121561345057600080fd5b61345b610100614628565b90506000613469848461310c565b825250602061347a848483016131cd565b60208301525060608201356001600160401b0381111561349957600080fd5b6134a58482850161338c565b60408301525060808201356001600160401b038111156134c457600080fd5b6134d084828501613306565b60608301525060a06134e484828501613214565b60808301525060e06134f884828501613671565b60a0830152506101e061350d8482850161310c565b60c0830152506102008201356001600160401b0381111561352d57600080fd5b61353984828501613279565b60e08301525092915050565b60006080828403121561355757600080fd5b6135616040614628565b9050600061356f848461310c565b82525060206132088484830160006060828403121561358d57600080fd5b6135976060614628565b905060006135a5848461310c565b82525060206135b68484830161310c565b60208301525060406135ca848285016136ad565b60408301525092915050565b6000608082840312156135e857600080fd5b6135f26040614628565b90506000613600848461323e565b82525060608201356001600160401b0381111561361c57600080fd5b61320884828501613080565b60006020828403121561363a57600080fd5b6136446020614628565b905081356001600160401b0381111561365c57600080fd5b61366884828501613080565b82525092915050565b6000610100828403121561368457600080fd5b61368e6040614628565b9050600061369c8484613545565b825250608061320884848301613545565b8035612b4a81614788565b6000602082840312156136ca57600080fd5b6000612d94848461306a565b6000602082840312156136e857600080fd5b6000612d948484613075565b60008060006060848603121561370957600080fd5b6000613715868661306a565b93505060206137268682870161306a565b92505060406137378682870161310c565b9150509250925092565b6000806040838503121561375457600080fd5b6000613760858561306a565b92505060208301356001600160401b0381111561377c57600080fd5b6137888582860161343d565b9150509250929050565b6000806000606084860312156137a757600080fd5b60006137b3868661306a565b93505060208401356001600160401b038111156137cf57600080fd5b6137268682870161343d565b600080604083850312156137ee57600080fd5b60006137fa858561306a565b92505060206137888582860161310c565b60006020828403121561381d57600080fd5b6000612d948484613101565b60006020828403121561383b57600080fd5b6000612d948484613117565b60006020828403121561385957600080fd5b6000612d948484613122565b60006020828403121561387757600080fd5b6000612d94848461312d565b6000806040838503121561389657600080fd5b60006138a28585613117565b925050602061378885828601613117565b6000602082840312156138c557600080fd5b81516001600160401b038111156138db57600080fd5b612d9484828501613187565b600080604083850312156138fa57600080fd5b82356001600160401b0381111561391057600080fd5b6137fa8582860161343d565b60006139288383613f77565b505060800190565b613939816146e7565b82525050565b613939816146a8565b60006139538261469b565b61395d818561469f565b935061396883614695565b8060005b83811015613996578151613980888261391c565b975061398b83614695565b92505060010161396c565b509495945050505050565b613939816146b3565b613939816146b8565b613939816146bb565b613939816146f2565b60006139d08261469b565b6139da818561469f565b93506139ea818560208601614709565b6139f381614735565b9093019392505050565b6000613a0a603f8361469f565b7f4f7065726174696f6e616c206d6f6465206973206e6f74206e6f726d616c205b81527f436f6e666967757261626c654f7065726174696f6e616c2e736f6c3a32325d00602082015260400192915050565b6000613a6960308361469f565b7f42616c616e636520747261636b65722066726f7a656e205b42616c616e63655481526f7261636b61626c652e736f6c3a34335d60801b602082015260400192915050565b6000613abb60678361469f565b7f43757272656e7420626c6f636b206e756d6265722062656c6f77206561726c6981527f65737420736574746c656d656e7420626c6f636b206e756d626572205b44726960208201526000805160206147928339815191526040820152666f6c3a3438395d60c81b606082015260800192915050565b6000613b3e60458361469f565b7f50726f706f73616c20666f756e64207465726d696e61746564205b447269697081527f536574746c656d656e744368616c6c656e676542795061796d656e742e736f6c6020820152643a3534325d60d81b604082015260600192915050565b6000613bab603f8361469f565b7f57616c6c657420666f756e64206c6f636b6564205b4472696970536574746c6581527f6d656e744368616c6c656e676542795061796d656e742e736f6c3a3133345d00602082015260400192915050565b6000613c0a60618361469f565b7f4f7665726c617070696e6720647269697020736574746c656d656e742063686181527f6c6c656e67652070726f706f73616c20666f756e64205b44726969705365747460208201527f6c656d656e744368616c6c656e676542795061796d656e742e736f6c3a3530316040820152605d60f81b606082015260800192915050565b6000613c9960478361469f565b7f57616c6c6574206973206e6f74207061796d656e74207061727479205b44726981526000805160206147928339815191526020820152666f6c3a3439355d60c81b604082015260600192915050565b6000613cf660568361469f565b7f57616c6c65742773206e6f6e63652062656c6f7720686967686573742073657481527f746c6564206e6f6e6365205b4472696970536574746c656d656e744368616c6c602082015275656e676542795061796d656e742e736f6c3a3531385d60501b604082015260600192915050565b6000613d7460608361469f565b7f4f7665726c617070696e67206e756c6c20736574746c656d656e74206368616c81527f6c656e67652070726f706f73616c20666f756e64205b4472696970536574746c60208201527f656d656e744368616c6c656e676542795061796d656e742e736f6c3a3530385d604082015260600192915050565b6000613df9603d8361469f565b7f4e6f2070726f706f73616c20666f756e64205b4472696970536574746c656d6581527f6e744368616c6c656e676542795061796d656e742e736f6c3a3533385d000000602082015260400192915050565b6000613e58602e8361469f565b7f5061796d656e74207365616c73206e6f742067656e75696e65205b56616c696481526d617461626c652e736f6c3a36355d60901b602082015260400192915050565b6000613ea8602c8361469f565b7f57616c6c6574206c6f636b65722066726f7a656e205b57616c6c65744c6f636b81526b61626c652e736f6c3a34335d60a01b602082015260400192915050565b80516040830190613efa848261393f565b50602082015161076060208501826139aa565b80516040830190613efa84826139aa565b80516060830190613f2f84826139aa565b5060208201516107606020850182613ee9565b80516000906040840190613f5685826139aa565b5060208301518482036020860152613f6e82826139c5565b95945050505050565b80516080830190613f8884826139aa565b5060208201516107606020850182613f1e565b805160009060a0840190613faf85826139aa565b506020830151613fc2602086018261393f565b506040830151613fd56040860182613f0d565b5060608301518482036080860152613f6e828261418a565b805160009060c084019061400185826139aa565b506020830151614014602086018261393f565b5060408301516140276040860182613f0d565b506060830151848203608086015261403f828261415e565b915050608083015184820360a0860152613f6e82826139c5565b805160009061022084019061406e85826139aa565b5060208301516140816020860182613ee9565b50604083015184820360608601526140998282613fed565b915050606083015184820360808601526140b38282613f9b565b91505060808301516140c860a0860182613f0d565b5060a08301516140db60e08601826141a2565b5060c08301516140ef6101e08601826139aa565b5060e0830151848203610200860152613f6e8282613f42565b8051608083019061411984826139aa565b50602082015161076060208501828051606083019061413884826139aa565b50602082015161414b60208501826139aa565b50604082015161076060408501826141c7565b805160009060808401906141728582613f1e565b5060208301518482036060860152613f6e8282613948565b8051602080845260009190840190613f6e8282613948565b80516101008301906141b48482614108565b5060208201516107606080850182614108565b613939816146e1565b60208101612b4a828461393f565b60208101612b4a8284613930565b606081016141fa8285613930565b6106166020830184613ee9565b60e08101614215828a613930565b61422260208301896139aa565b61422f60408301886139aa565b61423c60608301876139aa565b61424960808301866139aa565b61425660a083018561393f565b61426360c08301846139aa565b98975050505050505050565b6040810161427d828561393f565b610616602083018461393f565b60808101614298828761393f565b6142a560208301866139aa565b6142b2604083018561393f565b613f6e60608301846139aa565b60a081016142cd828861393f565b6142da60208301876139aa565b6142e7604083018661393f565b6142f460608301856139aa565b61430160808301846139aa565b9695505050505050565b606081016141fa828561393f565b60a08101614327828761393f565b6143346020830186613ee9565b61434160608301856139a1565b613f6e60808301846139a1565b6080810161435c828661393f565b6143696020830185613ee9565b612d9460608301846139aa565b60608101614384828661393f565b81810360208301526143968185614059565b9050612d946040830184613930565b61010081016143b4828b61393f565b6143c1602083018a6139aa565b6143ce60408301896139aa565b6143db60608301886139aa565b6143e860808301876139aa565b6143f560a083018661393f565b61440260c08301856139aa565b61440f60e0830184613930565b9998505050505050505050565b610160810161442b828d61393f565b614438602083018c6139aa565b614445604083018b6139aa565b614452606083018a6139aa565b61445f60808301896139aa565b61446c60a0830188613ee9565b61447960e08301876139aa565b6144876101008301866139a1565b6144956101208301856139aa565b8181036101408301526144a881846139c5565b9c9b505050505050505050505050565b60208101612b4a82846139a1565b60208101612b4a82846139aa565b60208101612b4a82846139b3565b604081016144f082856139b3565b61061660208301846139b3565b60208101612b4a82846139bc565b6020808252810161061681846139c5565b60208082528101612b4a816139fd565b60208082528101612b4a81613a5c565b60208082528101612b4a81613aae565b60208082528101612b4a81613b31565b60208082528101612b4a81613b9e565b60208082528101612b4a81613bfd565b60208082528101612b4a81613c8c565b60208082528101612b4a81613ce9565b60208082528101612b4a81613d67565b60208082528101612b4a81613dec565b60208082528101612b4a81613e4b565b60208082528101612b4a81613e9b565b602080825281016106168184614059565b604080825281016145fe8185614059565b9050610616602083018461393f565b6040810161461b82856139aa565b61061660208301846139aa565b6040518181016001600160401b038111828210171561464657600080fd5b604052919050565b60006001600160401b0382111561466457600080fd5b5060209081020190565b60006001600160401b0382111561468457600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b6000612b4a826146d5565b151590565b90565b6000612b4a826146a8565b806146d08161473f565b919050565b6001600160a01b031690565b60ff1690565b6000612b4a826146bb565b6000612b4a826146c6565b82818337506000910152565b60005b8381101561472457818101518382015260200161470c565b838111156107605750506000910152565b601f01601f191690565b6002811061474957fe5b50565b614755816146a8565b811461474957600080fd5b614755816146b3565b614755816146b8565b614755816146bb565b6002811061474957600080fd5b614755816146e156fe6970536574746c656d656e744368616c6c656e676542795061796d656e742e73a365627a7a723158208377fca6c152a24ff05ca78673a209831b0e8caf71a351e7a734ab34c4fd3ad06c6578706572696d656e74616cf564736f6c634300050b0040
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 : 0xb99f3f4aacb6e1197a623919103b99f4b41aaef0SafeMathUintLib : 0x0ff948c236c8d4dfcd0168bf243314c8ff8ec967
Swarm Source
bzzr://8377fca6c152a24ff05ca78673a209831b0e8caf71a351e7a734ab34c4fd3ad0
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 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.