Source Code
Latest 25 from a total of 32 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Update Subscribe... | 319778827 | 305 days ago | IN | 0 ETH | 0.00000057 | ||||
| Update Subscribe... | 319778667 | 305 days ago | IN | 0 ETH | 0.00000057 | ||||
| Update Subscribe... | 319772831 | 305 days ago | IN | 0 ETH | 0.00000089 | ||||
| Update Subscribe... | 319772710 | 305 days ago | IN | 0 ETH | 0.00000092 | ||||
| Update Subscribe... | 318159041 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158969 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158898 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158827 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158760 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158692 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158621 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158551 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158484 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158418 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158349 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158285 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158204 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158137 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158070 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318158003 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318157935 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318157866 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318157798 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318157712 | 310 days ago | IN | 0 ETH | 0.00000052 | ||||
| Update Subscribe... | 318157637 | 310 days ago | IN | 0 ETH | 0.00000052 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 425234969 | 4 hrs ago | 0.00003555 ETH | ||||
| 425234969 | 4 hrs ago | 0.00003555 ETH | ||||
| 425186607 | 8 hrs ago | 0.00011452 ETH | ||||
| 425186607 | 8 hrs ago | 0.00011452 ETH | ||||
| 425186607 | 8 hrs ago | 0.00011452 ETH | ||||
| 425186607 | 8 hrs ago | 0.00011452 ETH | ||||
| 425120448 | 12 hrs ago | 0.00010995 ETH | ||||
| 425120448 | 12 hrs ago | 0.00010995 ETH | ||||
| 425120448 | 12 hrs ago | 0.00010995 ETH | ||||
| 425120448 | 12 hrs ago | 0.00010995 ETH | ||||
| 425120298 | 12 hrs ago | 0.00010995 ETH | ||||
| 425120298 | 12 hrs ago | 0.00010995 ETH | ||||
| 425120298 | 12 hrs ago | 0.00010995 ETH | ||||
| 425120298 | 12 hrs ago | 0.00010995 ETH | ||||
| 425119654 | 12 hrs ago | 0.00003421 ETH | ||||
| 425119654 | 12 hrs ago | 0.00003421 ETH | ||||
| 425004391 | 20 hrs ago | 0.00003407 ETH | ||||
| 425004391 | 20 hrs ago | 0.00003407 ETH | ||||
| 424889586 | 28 hrs ago | 0.00003391 ETH | ||||
| 424889586 | 28 hrs ago | 0.00003391 ETH | ||||
| 424775669 | 36 hrs ago | 0.00003385 ETH | ||||
| 424775669 | 36 hrs ago | 0.00003385 ETH | ||||
| 424775668 | 36 hrs ago | 0.00003385 ETH | ||||
| 424775668 | 36 hrs ago | 0.00003385 ETH | ||||
| 424660499 | 44 hrs ago | 0.00003387 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
FeeManager
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
import {IFeeManager} from "./interfaces/IFeeManager.sol";
import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {Common} from "../libraries/Common.sol";
import {IRewardManager} from "./interfaces/IRewardManager.sol";
import {IWERC20} from "../../shared/interfaces/IWERC20.sol";
import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol";
import {Math} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/Math.sol";
import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol";
/**
* @title FeeManager
* @author Michael Fletcher
* @author Austin Born
* @notice This contract is used for the handling of fees required for users verifying reports.
*/
contract FeeManager is IFeeManager, ConfirmedOwner, ITypeAndVersion {
using SafeERC20 for IERC20;
/// @notice list of subscribers and their discounts subscriberDiscounts[subscriber][feedId][token]
mapping(address => mapping(bytes32 => mapping(address => uint256))) public s_subscriberDiscounts;
/// @notice map of global discounts
mapping(address => mapping(address => uint256)) public s_globalDiscounts;
/// @notice keep track of any subsidised link that is owed to the reward manager.
mapping(bytes32 => uint256) public s_linkDeficit;
/// @notice the total discount that can be applied to a fee, 1e18 = 100% discount
uint64 private constant PERCENTAGE_SCALAR = 1e18;
/// @notice the LINK token address
address public immutable i_linkAddress;
/// @notice the native token address
address public immutable i_nativeAddress;
/// @notice the proxy address
address public immutable i_proxyAddress;
/// @notice the reward manager address
IRewardManager public immutable i_rewardManager;
// @notice the mask to apply to get the report version
bytes32 private constant REPORT_VERSION_MASK = 0xffff000000000000000000000000000000000000000000000000000000000000;
// @notice the different report versions
bytes32 private constant REPORT_V1 = 0x0001000000000000000000000000000000000000000000000000000000000000;
/// @notice the surcharge fee to be paid if paying in native
uint256 public s_nativeSurcharge;
/// @notice the error thrown if the discount or surcharge is invalid
error InvalidSurcharge();
/// @notice the error thrown if the discount is invalid
error InvalidDiscount();
/// @notice the error thrown if the address is invalid
error InvalidAddress();
/// @notice thrown if msg.value is supplied with a bad quote
error InvalidDeposit();
/// @notice thrown if a report has expired
error ExpiredReport();
/// @notice thrown if a report has no quote
error InvalidQuote();
// @notice thrown when the caller is not authorized
error Unauthorized();
// @notice thrown when trying to clear a zero deficit
error ZeroDeficit();
/// @notice thrown when trying to pay an address that cannot except funds
error InvalidReceivingAddress();
/// @notice Emitted whenever a subscriber's discount is updated
/// @param subscriber address of the subscriber to update discounts for
/// @param feedId Feed ID for the discount
/// @param token Token address for the discount
/// @param discount Discount to apply, in relation to the PERCENTAGE_SCALAR
event SubscriberDiscountUpdated(address indexed subscriber, bytes32 indexed feedId, address token, uint64 discount);
/// @notice Emitted when updating the native surcharge
/// @param newSurcharge Surcharge amount to apply relative to PERCENTAGE_SCALAR
event NativeSurchargeUpdated(uint64 newSurcharge);
/// @notice Emits when this contract does not have enough LINK to send to the reward manager when paying in native
/// @param rewards Config digest and link fees which could not be subsidised
event InsufficientLink(IRewardManager.FeePayment[] rewards);
/// @notice Emitted when funds are withdrawn
/// @param adminAddress Address of the admin
/// @param recipient Address of the recipient
/// @param assetAddress Address of the asset withdrawn
/// @param quantity Amount of the asset withdrawn
event Withdraw(address adminAddress, address recipient, address assetAddress, uint192 quantity);
/// @notice Emits when a deficit has been cleared for a particular config digest
/// @param configDigest Config digest of the deficit cleared
/// @param linkQuantity Amount of LINK required to pay the deficit
event LinkDeficitCleared(bytes32 indexed configDigest, uint256 linkQuantity);
/// @notice Emits when a fee has been processed
/// @param configDigest Config digest of the fee processed
/// @param subscriber Address of the subscriber who paid the fee
/// @param fee Fee paid
/// @param reward Reward paid
/// @param appliedDiscount Discount applied to the fee
event DiscountApplied(
bytes32 indexed configDigest,
address indexed subscriber,
Common.Asset fee,
Common.Asset reward,
uint256 appliedDiscount
);
/**
* @notice Construct the FeeManager contract
* @param _linkAddress The address of the LINK token
* @param _nativeAddress The address of the wrapped ERC-20 version of the native token (represents fee in native or wrapped)
* @param _proxyAddress The address of the proxy contract
* @param _rewardManagerAddress The address of the reward manager contract
*/
constructor(
address _linkAddress,
address _nativeAddress,
address _proxyAddress,
address _rewardManagerAddress
) ConfirmedOwner(msg.sender) {
if (
_linkAddress == address(0) ||
_nativeAddress == address(0) ||
_proxyAddress == address(0) ||
_rewardManagerAddress == address(0)
) revert InvalidAddress();
i_linkAddress = _linkAddress;
i_nativeAddress = _nativeAddress;
i_proxyAddress = _proxyAddress;
i_rewardManager = IRewardManager(_rewardManagerAddress);
IERC20(i_linkAddress).approve(address(i_rewardManager), type(uint256).max);
}
modifier onlyOwnerOrProxy() {
if (msg.sender != i_proxyAddress && msg.sender != owner()) revert Unauthorized();
_;
}
modifier onlyProxy() {
if (msg.sender != i_proxyAddress) revert Unauthorized();
_;
}
/// @inheritdoc ITypeAndVersion
function typeAndVersion() external pure override returns (string memory) {
return "FeeManager 2.1.0";
}
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return interfaceId == this.processFee.selector || interfaceId == this.processFeeBulk.selector;
}
/// @inheritdoc IVerifierFeeManager
function processFee(
bytes calldata payload,
bytes calldata parameterPayload,
address subscriber
) external payable override onlyProxy {
(Common.Asset memory fee, Common.Asset memory reward, uint256 appliedDiscount) = _processFee(
payload,
parameterPayload,
subscriber
);
if (fee.amount == 0) {
_transfer(subscriber, msg.value);
return;
}
IFeeManager.FeeAndReward[] memory feeAndReward = new IFeeManager.FeeAndReward[](1);
feeAndReward[0] = IFeeManager.FeeAndReward(bytes32(payload), fee, reward, appliedDiscount);
if (fee.assetAddress == i_linkAddress) {
_handleFeesAndRewards(subscriber, feeAndReward, 1, 0);
} else {
_handleFeesAndRewards(subscriber, feeAndReward, 0, 1);
}
}
/// @inheritdoc IVerifierFeeManager
function processFeeBulk(
bytes[] calldata payloads,
bytes calldata parameterPayload,
address subscriber
) external payable override onlyProxy {
FeeAndReward[] memory feesAndRewards = new IFeeManager.FeeAndReward[](payloads.length);
//keep track of the number of fees to prevent over initialising the FeePayment array within _convertToLinkAndNativeFees
uint256 numberOfLinkFees;
uint256 numberOfNativeFees;
uint256 feesAndRewardsIndex;
for (uint256 i; i < payloads.length; ++i) {
(Common.Asset memory fee, Common.Asset memory reward, uint256 appliedDiscount) = _processFee(
payloads[i],
parameterPayload,
subscriber
);
if (fee.amount != 0) {
feesAndRewards[feesAndRewardsIndex++] = IFeeManager.FeeAndReward(
bytes32(payloads[i]),
fee,
reward,
appliedDiscount
);
unchecked {
//keep track of some tallys to make downstream calculations more efficient
if (fee.assetAddress == i_linkAddress) {
++numberOfLinkFees;
} else {
++numberOfNativeFees;
}
}
}
}
if (numberOfLinkFees != 0 || numberOfNativeFees != 0) {
_handleFeesAndRewards(subscriber, feesAndRewards, numberOfLinkFees, numberOfNativeFees);
} else {
_transfer(subscriber, msg.value);
}
}
/// @inheritdoc IFeeManager
function getFeeAndReward(
address subscriber,
bytes memory report,
address quoteAddress
) public view returns (Common.Asset memory, Common.Asset memory, uint256) {
Common.Asset memory fee;
Common.Asset memory reward;
//get the feedId from the report
bytes32 feedId = bytes32(report);
//the report needs to be a support version
bytes32 reportVersion = _getReportVersion(feedId);
//version 1 of the reports don't require quotes, so the fee will be 0
if (reportVersion == REPORT_V1) {
fee.assetAddress = i_nativeAddress;
reward.assetAddress = i_linkAddress;
return (fee, reward, 0);
}
//verify the quote payload is a supported token
if (quoteAddress != i_nativeAddress && quoteAddress != i_linkAddress) {
revert InvalidQuote();
}
//decode the report depending on the version
uint256 linkQuantity;
uint256 nativeQuantity;
uint256 expiresAt;
(, , , nativeQuantity, linkQuantity, expiresAt) = abi.decode(
report,
(bytes32, uint32, uint32, uint192, uint192, uint32)
);
//read the timestamp bytes from the report data and verify it has not expired
if (expiresAt < block.timestamp) {
revert ExpiredReport();
}
//get the discount being applied
uint256 discount = s_subscriberDiscounts[subscriber][feedId][quoteAddress];
if (discount == 0) {
//check if a global discount has been applied
discount = s_globalDiscounts[subscriber][quoteAddress];
}
//the reward is always set in LINK
reward.assetAddress = i_linkAddress;
reward.amount = Math.ceilDiv(linkQuantity * (PERCENTAGE_SCALAR - discount), PERCENTAGE_SCALAR);
//calculate either the LINK fee or native fee if it's within the report
if (quoteAddress == i_linkAddress) {
fee.assetAddress = i_linkAddress;
fee.amount = reward.amount;
} else {
uint256 surchargedFee = Math.ceilDiv(nativeQuantity * (PERCENTAGE_SCALAR + s_nativeSurcharge), PERCENTAGE_SCALAR);
fee.assetAddress = i_nativeAddress;
fee.amount = Math.ceilDiv(surchargedFee * (PERCENTAGE_SCALAR - discount), PERCENTAGE_SCALAR);
}
//return the fee
return (fee, reward, discount);
}
/// @inheritdoc IVerifierFeeManager
function setFeeRecipients(
bytes32 configDigest,
Common.AddressAndWeight[] calldata rewardRecipientAndWeights
) external onlyOwnerOrProxy {
i_rewardManager.setRewardRecipients(configDigest, rewardRecipientAndWeights);
}
/// @inheritdoc IFeeManager
function setNativeSurcharge(uint64 surcharge) external onlyOwner {
if (surcharge > PERCENTAGE_SCALAR) revert InvalidSurcharge();
s_nativeSurcharge = surcharge;
emit NativeSurchargeUpdated(surcharge);
}
/// @inheritdoc IFeeManager
function updateSubscriberDiscount(
address subscriber,
bytes32 feedId,
address token,
uint64 discount
) external onlyOwner {
//make sure the discount is not greater than the total discount that can be applied
if (discount > PERCENTAGE_SCALAR) revert InvalidDiscount();
//make sure the token is either LINK or native
if (token != i_linkAddress && token != i_nativeAddress) revert InvalidAddress();
s_subscriberDiscounts[subscriber][feedId][token] = discount;
emit SubscriberDiscountUpdated(subscriber, feedId, token, discount);
}
function updateSubscriberGlobalDiscount(address subscriber, address token, uint64 discount) external onlyOwner {
//make sure the discount is not greater than the total discount that can be applied
if (discount > PERCENTAGE_SCALAR) revert InvalidDiscount();
//make sure the token is either LINK or native
if (token != i_linkAddress && token != i_nativeAddress) revert InvalidAddress();
s_globalDiscounts[subscriber][token] = discount;
emit SubscriberDiscountUpdated(subscriber, bytes32(0), token, discount);
}
/// @inheritdoc IFeeManager
function withdraw(address assetAddress, address recipient, uint192 quantity) external onlyOwner {
//address 0 is used to withdraw native in the context of withdrawing
if (assetAddress == address(0)) {
_transfer(recipient, quantity);
return;
}
//withdraw the requested asset
IERC20(assetAddress).safeTransfer(recipient, quantity);
//emit event when funds are withdrawn
emit Withdraw(msg.sender, recipient, assetAddress, uint192(quantity));
}
/// @inheritdoc IFeeManager
function linkAvailableForPayment() external view returns (uint256) {
//return the amount of LINK this contact has available to pay rewards
return IERC20(i_linkAddress).balanceOf(address(this));
}
/**
* @notice Gets the current version of the report that is encoded as the last two bytes of the feed
* @param feedId feed id to get the report version for
*/
function _getReportVersion(bytes32 feedId) internal pure returns (bytes32) {
return REPORT_VERSION_MASK & feedId;
}
function _processFee(
bytes calldata payload,
bytes calldata parameterPayload,
address subscriber
) internal view returns (Common.Asset memory, Common.Asset memory, uint256) {
if (subscriber == address(this)) revert InvalidAddress();
//decode the report from the payload
(, bytes memory report) = abi.decode(payload, (bytes32[3], bytes));
//get the feedId from the report
bytes32 feedId = bytes32(report);
//v1 doesn't need a quote payload, so skip the decoding
address quote;
if (_getReportVersion(feedId) != REPORT_V1) {
//decode the quote from the bytes
(quote) = abi.decode(parameterPayload, (address));
}
//decode the fee, it will always be native or LINK
return getFeeAndReward(subscriber, report, quote);
}
function _handleFeesAndRewards(
address subscriber,
FeeAndReward[] memory feesAndRewards,
uint256 numberOfLinkFees,
uint256 numberOfNativeFees
) internal {
IRewardManager.FeePayment[] memory linkRewards = new IRewardManager.FeePayment[](numberOfLinkFees);
IRewardManager.FeePayment[] memory nativeFeeLinkRewards = new IRewardManager.FeePayment[](numberOfNativeFees);
uint256 totalNativeFee;
uint256 totalNativeFeeLinkValue;
uint256 linkRewardsIndex;
uint256 nativeFeeLinkRewardsIndex;
uint256 totalNumberOfFees = numberOfLinkFees + numberOfNativeFees;
for (uint256 i; i < totalNumberOfFees; ++i) {
if (feesAndRewards[i].fee.assetAddress == i_linkAddress) {
linkRewards[linkRewardsIndex++] = IRewardManager.FeePayment(
feesAndRewards[i].configDigest,
uint192(feesAndRewards[i].reward.amount)
);
} else {
nativeFeeLinkRewards[nativeFeeLinkRewardsIndex++] = IRewardManager.FeePayment(
feesAndRewards[i].configDigest,
uint192(feesAndRewards[i].reward.amount)
);
totalNativeFee += feesAndRewards[i].fee.amount;
totalNativeFeeLinkValue += feesAndRewards[i].reward.amount;
}
if (feesAndRewards[i].appliedDiscount != 0) {
emit DiscountApplied(
feesAndRewards[i].configDigest,
subscriber,
feesAndRewards[i].fee,
feesAndRewards[i].reward,
feesAndRewards[i].appliedDiscount
);
}
}
//keep track of change in case of any over payment
uint256 change;
if (msg.value != 0) {
//there must be enough to cover the fee
if (totalNativeFee > msg.value) revert InvalidDeposit();
//wrap the amount required to pay the fee & approve as the subscriber paid in wrapped native
IWERC20(i_nativeAddress).deposit{value: totalNativeFee}();
unchecked {
//msg.value is always >= to fee.amount
change = msg.value - totalNativeFee;
}
} else {
if (totalNativeFee != 0) {
//subscriber has paid in wrapped native, so transfer the native to this contract
IERC20(i_nativeAddress).safeTransferFrom(subscriber, address(this), totalNativeFee);
}
}
if (linkRewards.length != 0) {
i_rewardManager.onFeePaid(linkRewards, subscriber);
}
if (nativeFeeLinkRewards.length != 0) {
//distribute subsidised fees paid in Native
if (totalNativeFeeLinkValue > IERC20(i_linkAddress).balanceOf(address(this))) {
// If not enough LINK on this contract to forward for rewards, tally the deficit to be paid by out-of-band LINK
for (uint256 i; i < nativeFeeLinkRewards.length; ++i) {
unchecked {
//we have previously tallied the fees, any overflows would have already reverted
s_linkDeficit[nativeFeeLinkRewards[i].poolId] += nativeFeeLinkRewards[i].amount;
}
}
emit InsufficientLink(nativeFeeLinkRewards);
} else {
//distribute the fees
i_rewardManager.onFeePaid(nativeFeeLinkRewards, address(this));
}
}
// a refund may be needed if the payee has paid in excess of the fee
_transfer(subscriber, change);
}
function _transfer(address to, uint256 quantity) internal {
if (quantity != 0) {
(bool success, ) = payable(to).call{value: quantity}("");
if (!success) revert InvalidReceivingAddress();
}
}
/// @inheritdoc IFeeManager
function payLinkDeficit(bytes32 configDigest) external onlyOwner {
uint256 deficit = s_linkDeficit[configDigest];
if (deficit == 0) revert ZeroDeficit();
delete s_linkDeficit[configDigest];
IRewardManager.FeePayment[] memory deficitFeePayment = new IRewardManager.FeePayment[](1);
deficitFeePayment[0] = IRewardManager.FeePayment(configDigest, uint192(deficit));
i_rewardManager.onFeePaid(deficitFeePayment, address(this));
emit LinkDeficitCleared(configDigest, deficit);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {ConfirmedOwnerWithProposal} from "./ConfirmedOwnerWithProposal.sol";
/// @title The ConfirmedOwner contract
/// @notice A contract with helpers for basic contract ownership.
contract ConfirmedOwner is ConfirmedOwnerWithProposal {
constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {Common} from "../../libraries/Common.sol";
import {IVerifierFeeManager} from "./IVerifierFeeManager.sol";
interface IFeeManager is IERC165, IVerifierFeeManager {
/**
* @notice Calculate the applied fee and the reward from a report. If the sender is a subscriber, they will receive a discount.
* @param subscriber address trying to verify
* @param report report to calculate the fee for
* @param quoteAddress address of the quote payment token
* @return (fee, reward, totalDiscount) fee and the reward data with the discount applied
*/
function getFeeAndReward(
address subscriber,
bytes memory report,
address quoteAddress
) external returns (Common.Asset memory, Common.Asset memory, uint256);
/**
* @notice Sets the native surcharge
* @param surcharge surcharge to be paid if paying in native
*/
function setNativeSurcharge(uint64 surcharge) external;
/**
* @notice Adds a subscriber to the fee manager
* @param subscriber address of the subscriber
* @param feedId feed id to apply the discount to
* @param token token to apply the discount to
* @param discount discount to be applied to the fee
*/
function updateSubscriberDiscount(address subscriber, bytes32 feedId, address token, uint64 discount) external;
/**
* @notice Withdraws any native or LINK rewards to the owner address
* @param assetAddress address of the asset to withdraw
* @param recipientAddress address to withdraw to
* @param quantity quantity to withdraw
*/
function withdraw(address assetAddress, address recipientAddress, uint192 quantity) external;
/**
* @notice Returns the link balance of the fee manager
* @return link balance of the fee manager
*/
function linkAvailableForPayment() external returns (uint256);
/**
* @notice Admin function to pay the LINK deficit for a given config digest
* @param configDigest the config digest to pay the deficit for
*/
function payLinkDeficit(bytes32 configDigest) external;
/**
* @notice Adds a subscriber to the fee manager
* @param subscriber address of the subscriber
* @param token token to apply the discount to
* @param discount discount to be applied to the fee
*/
function updateSubscriberGlobalDiscount(address subscriber, address token, uint64 discount) external;
/**
* @notice The structure to hold a fee and reward to verify a report
* @param digest the digest linked to the fee and reward
* @param fee the fee paid to verify the report
* @param reward the reward paid upon verification
& @param appliedDiscount the discount applied to the reward
*/
struct FeeAndReward {
bytes32 configDigest;
Common.Asset fee;
Common.Asset reward;
uint256 appliedDiscount;
}
/**
* @notice The structure to hold quote metadata
* @param quoteAddress the address of the quote
*/
struct Quote {
address quoteAddress;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ITypeAndVersion {
function typeAndVersion() external pure returns (string memory);
}// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/*
* @title Common
* @author Michael Fletcher
* @notice Common functions and structs
*/
library Common {
// @notice The asset struct to hold the address of an asset and amount
struct Asset {
address assetAddress;
uint256 amount;
}
// @notice Struct to hold the address and its associated weight
struct AddressAndWeight {
address addr;
uint64 weight;
}
/**
* @notice Checks if an array of AddressAndWeight has duplicate addresses
* @param recipients The array of AddressAndWeight to check
* @return bool True if there are duplicates, false otherwise
*/
function _hasDuplicateAddresses(address[] memory recipients) internal pure returns (bool) {
for (uint256 i = 0; i < recipients.length; ) {
for (uint256 j = i + 1; j < recipients.length; ) {
if (recipients[i] == recipients[j]) {
return true;
}
unchecked {
++j;
}
}
unchecked {
++i;
}
}
return false;
}
/**
* @notice Checks if an array of AddressAndWeight has duplicate addresses
* @param recipients The array of AddressAndWeight to check
* @return bool True if there are duplicates, false otherwise
*/
function _hasDuplicateAddresses(Common.AddressAndWeight[] memory recipients) internal pure returns (bool) {
for (uint256 i = 0; i < recipients.length; ) {
for (uint256 j = i + 1; j < recipients.length; ) {
if (recipients[i].addr == recipients[j].addr) {
return true;
}
unchecked {
++j;
}
}
unchecked {
++i;
}
}
return false;
}
/**
* @notice sorts a list of addresses numerically
* @param arr The array of addresses to sort
* @param left the start index
* @param right the end index
*/
function _quickSort(address[] memory arr, int256 left, int256 right) internal pure {
int256 i = left;
int256 j = right;
if (i == j) return;
address pivot = arr[uint256(left + (right - left) / 2)];
while (i <= j) {
while (uint160(arr[uint256(i)]) < uint160(pivot)) i++;
while (uint160(pivot) < uint160(arr[uint256(j)])) j--;
if (i <= j) {
(arr[uint256(i)], arr[uint256(j)]) = (arr[uint256(j)], arr[uint256(i)]);
i++;
j--;
}
}
if (left < j) _quickSort(arr, left, j);
if (i < right) _quickSort(arr, i, right);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {Common} from "../../libraries/Common.sol";
interface IRewardManager is IERC165 {
/**
* @notice Record the fee received for a particular pool
* @param payments array of structs containing pool id and amount
* @param payee the user the funds should be retrieved from
*/
function onFeePaid(FeePayment[] calldata payments, address payee) external;
/**
* @notice Claims the rewards in a specific pool
* @param poolIds array of poolIds to claim rewards for
*/
function claimRewards(bytes32[] calldata poolIds) external;
/**
* @notice Set the RewardRecipients and weights for a specific pool. This should only be called once per pool Id. Else updateRewardRecipients should be used.
* @param poolId poolId to set RewardRecipients and weights for
* @param rewardRecipientAndWeights array of each RewardRecipient and associated weight
*/
function setRewardRecipients(bytes32 poolId, Common.AddressAndWeight[] calldata rewardRecipientAndWeights) external;
/**
* @notice Updates a subset the reward recipients for a specific poolId. The collective weight of the recipients should add up to the recipients existing weights. Any recipients with a weight of 0 will be removed.
* @param poolId the poolId to update
* @param newRewardRecipients array of new reward recipients
*/
function updateRewardRecipients(bytes32 poolId, Common.AddressAndWeight[] calldata newRewardRecipients) external;
/**
* @notice Pays all the recipients for each of the pool ids
* @param poolId the pool id to pay recipients for
* @param recipients array of recipients to pay within the pool
*/
function payRecipients(bytes32 poolId, address[] calldata recipients) external;
/**
* @notice Sets the fee manager. This needs to be done post construction to prevent a circular dependency.
* @param newFeeManager address of the new verifier proxy
*/
function setFeeManager(address newFeeManager) external;
/**
* @notice Gets a list of pool ids which have reward for a specific recipient.
* @param recipient address of the recipient to get pool ids for
* @param startIndex the index to start from
* @param endIndex the index to stop at
*/
function getAvailableRewardPoolIds(
address recipient,
uint256 startIndex,
uint256 endIndex
) external view returns (bytes32[] memory);
/**
* @notice The structure to hold a fee payment notice
* @param poolId the poolId receiving the payment
* @param amount the amount being paid
*/
struct FeePayment {
bytes32 poolId;
uint192 amount;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IWERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {Common} from "../../libraries/Common.sol";
interface IVerifierFeeManager is IERC165 {
/**
* @notice Handles fees for a report from the subscriber and manages rewards
* @param payload report to process the fee for
* @param parameterPayload fee payload
* @param subscriber address of the fee will be applied
*/
function processFee(bytes calldata payload, bytes calldata parameterPayload, address subscriber) external payable;
/**
* @notice Processes the fees for each report in the payload, billing the subscriber and paying the reward manager
* @param payloads reports to process
* @param parameterPayload fee payload
* @param subscriber address of the user to process fee for
*/
function processFeeBulk(
bytes[] calldata payloads,
bytes calldata parameterPayload,
address subscriber
) external payable;
/**
* @notice Sets the fee recipients according to the fee manager
* @param configDigest digest of the configuration
* @param rewardRecipientAndWeights the address and weights of all the recipients to receive rewards
*/
function setFeeRecipients(
bytes32 configDigest,
Common.AddressAndWeight[] calldata rewardRecipientAndWeights
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IOwnable} from "../interfaces/IOwnable.sol";
/// @title The ConfirmedOwner contract
/// @notice A contract with helpers for basic contract ownership.
contract ConfirmedOwnerWithProposal is IOwnable {
address private s_owner;
address private s_pendingOwner;
event OwnershipTransferRequested(address indexed from, address indexed to);
event OwnershipTransferred(address indexed from, address indexed to);
constructor(address newOwner, address pendingOwner) {
// solhint-disable-next-line gas-custom-errors
require(newOwner != address(0), "Cannot set owner to zero");
s_owner = newOwner;
if (pendingOwner != address(0)) {
_transferOwnership(pendingOwner);
}
}
/// @notice Allows an owner to begin transferring ownership to a new address.
function transferOwnership(address to) public override onlyOwner {
_transferOwnership(to);
}
/// @notice Allows an ownership transfer to be completed by the recipient.
function acceptOwnership() external override {
// solhint-disable-next-line gas-custom-errors
require(msg.sender == s_pendingOwner, "Must be proposed owner");
address oldOwner = s_owner;
s_owner = msg.sender;
s_pendingOwner = address(0);
emit OwnershipTransferred(oldOwner, msg.sender);
}
/// @notice Get the current owner
function owner() public view override returns (address) {
return s_owner;
}
/// @notice validate, transfer ownership, and emit relevant events
function _transferOwnership(address to) private {
// solhint-disable-next-line gas-custom-errors
require(to != msg.sender, "Cannot transfer to self");
s_pendingOwner = to;
emit OwnershipTransferRequested(s_owner, to);
}
/// @notice validate access
function _validateOwnership() internal view {
// solhint-disable-next-line gas-custom-errors
require(msg.sender == s_owner, "Only callable by owner");
}
/// @notice Reverts if called by anyone other than the contract owner.
modifier onlyOwner() {
_validateOwnership();
_;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IOwnable {
function owner() external returns (address);
function transferOwnership(address recipient) external;
function acceptOwnership() external;
}{
"remappings": [
"forge-std/=src/v0.8/vendor/forge-std/src/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@arbitrum/=node_modules/@arbitrum/",
"hardhat/=node_modules/hardhat/",
"@eth-optimism/=node_modules/@eth-optimism/",
"@scroll-tech/=node_modules/@scroll-tech/",
"@zksync/=node_modules/@zksync/"
],
"optimizer": {
"enabled": true,
"runs": 1000000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_linkAddress","type":"address"},{"internalType":"address","name":"_nativeAddress","type":"address"},{"internalType":"address","name":"_proxyAddress","type":"address"},{"internalType":"address","name":"_rewardManagerAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ExpiredReport","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidDeposit","type":"error"},{"inputs":[],"name":"InvalidDiscount","type":"error"},{"inputs":[],"name":"InvalidQuote","type":"error"},{"inputs":[],"name":"InvalidReceivingAddress","type":"error"},{"inputs":[],"name":"InvalidSurcharge","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroDeficit","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":true,"internalType":"address","name":"subscriber","type":"address"},{"components":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"struct Common.Asset","name":"fee","type":"tuple"},{"components":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"struct Common.Asset","name":"reward","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"appliedDiscount","type":"uint256"}],"name":"DiscountApplied","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"uint192","name":"amount","type":"uint192"}],"indexed":false,"internalType":"struct IRewardManager.FeePayment[]","name":"rewards","type":"tuple[]"}],"name":"InsufficientLink","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"linkQuantity","type":"uint256"}],"name":"LinkDeficitCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"newSurcharge","type":"uint64"}],"name":"NativeSurchargeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"subscriber","type":"address"},{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint64","name":"discount","type":"uint64"}],"name":"SubscriberDiscountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"adminAddress","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":false,"internalType":"uint192","name":"quantity","type":"uint192"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"subscriber","type":"address"},{"internalType":"bytes","name":"report","type":"bytes"},{"internalType":"address","name":"quoteAddress","type":"address"}],"name":"getFeeAndReward","outputs":[{"components":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Common.Asset","name":"","type":"tuple"},{"components":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Common.Asset","name":"","type":"tuple"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"i_linkAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"i_nativeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"i_proxyAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"i_rewardManager","outputs":[{"internalType":"contract IRewardManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"linkAvailableForPayment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"name":"payLinkDeficit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"bytes","name":"parameterPayload","type":"bytes"},{"internalType":"address","name":"subscriber","type":"address"}],"name":"processFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"payloads","type":"bytes[]"},{"internalType":"bytes","name":"parameterPayload","type":"bytes"},{"internalType":"address","name":"subscriber","type":"address"}],"name":"processFeeBulk","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"s_globalDiscounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"s_linkDeficit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"s_nativeSurcharge","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"s_subscriberDiscounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"weight","type":"uint64"}],"internalType":"struct Common.AddressAndWeight[]","name":"rewardRecipientAndWeights","type":"tuple[]"}],"name":"setFeeRecipients","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"surcharge","type":"uint64"}],"name":"setNativeSurcharge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"subscriber","type":"address"},{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint64","name":"discount","type":"uint64"}],"name":"updateSubscriberDiscount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"subscriber","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint64","name":"discount","type":"uint64"}],"name":"updateSubscriberGlobalDiscount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint192","name":"quantity","type":"uint192"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101006040523480156200001257600080fd5b506040516200374038038062003740833981016040819052620000359162000288565b33806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620001c0565b5050506001600160a01b0384161580620000e057506001600160a01b038316155b80620000f357506001600160a01b038216155b806200010657506001600160a01b038116155b15620001255760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03848116608081905284821660a05283821660c05290821660e081905260405163095ea7b360e01b81526004810191909152600019602482015263095ea7b3906044016020604051808303816000875af11580156200018f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b59190620002e5565b505050505062000310565b336001600160a01b038216036200021a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200028357600080fd5b919050565b600080600080608085870312156200029f57600080fd5b620002aa856200026b565b9350620002ba602086016200026b565b9250620002ca604086016200026b565b9150620002da606086016200026b565b905092959194509250565b600060208284031215620002f857600080fd5b815180151581146200030957600080fd5b9392505050565b60805160a05160c05160e05161334062000400600039600081816102c301528181611644015281816117d20152818161209101526122df015260008181610383015281816107d701528181610f47015261171801526000818161033c01528181610ab301528181610d6a01528181611164015281816111bb015281816114b901528181611fb701526120600152600081816105280152818161095201528181610a5c01528181610d1301528181610eaa015281816110530152818161118901528181611212015281816113aa015281816114150152818161145501528181611c32015261215201526133406000f3fe6080604052600436106101805760003560e01c806376cf3187116100d6578063dba45fe01161007f578063ea4b861b11610059578063ea4b861b14610516578063f2fde38b1461054a578063f65df9621461056a57600080fd5b8063dba45fe014610478578063e03dab1a1461048b578063e389d9a4146104f657600080fd5b80638da5cb5b116100b05780638da5cb5b14610418578063ce7817d114610443578063d09dc3391461046357600080fd5b806376cf3187146103a557806379ba5097146103c557806387d6d843146103da57600080fd5b806332f5f746116101385780636387866811610112578063638786681461032a5780636c2f1a171461035e5780636d1342cb1461037157600080fd5b806332f5f7461461029b5780633aa5ac07146102b1578063505380941461030a57600080fd5b8063181f5a7711610169578063181f5a77146101f55780631cc7f2d8146102415780631d4d84a21461027957600080fd5b8063013f542b1461018557806301ffc9a7146101c5575b600080fd5b34801561019157600080fd5b506101b26101a036600461289a565b60046020526000908152604090205481565b6040519081526020015b60405180910390f35b3480156101d157600080fd5b506101e56101e03660046128b3565b61058a565b60405190151581526020016101bc565b34801561020157600080fd5b50604080518082018252601081527f4665654d616e6167657220322e312e3000000000000000000000000000000000602082015290516101bc9190612919565b34801561024d57600080fd5b506101b261025c36600461299c565b600360209081526000928352604080842090915290825290205481565b34801561028557600080fd5b506102996102943660046129fb565b610623565b005b3480156102a757600080fd5b506101b260055481565b3480156102bd57600080fd5b506102e57f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bc565b34801561031657600080fd5b50610299610325366004612a5e565b610725565b34801561033657600080fd5b506102e57f000000000000000000000000000000000000000000000000000000000000000081565b61029961036c366004612ac2565b6107bf565b34801561037d57600080fd5b506102e57f000000000000000000000000000000000000000000000000000000000000000081565b3480156103b157600080fd5b506102996103c0366004612b71565b610a06565b3480156103d157600080fd5b50610299610bbb565b3480156103e657600080fd5b506101b26103f5366004612bb8565b600260209081526000938452604080852082529284528284209052825290205481565b34801561042457600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166102e5565b34801561044f57600080fd5b5061029961045e366004612bef565b610cbd565b34801561046f57600080fd5b506101b2610e79565b610299610486366004612c40565b610f2f565b34801561049757600080fd5b506104ab6104a6366004612d9e565b6110cb565b60408051845173ffffffffffffffffffffffffffffffffffffffff9081168252602095860151868301528451169181019190915292909101516060830152608082015260a0016101bc565b34801561050257600080fd5b5061029961051136600461289a565b61151b565b34801561052257600080fd5b506102e57f000000000000000000000000000000000000000000000000000000000000000081565b34801561055657600080fd5b50610299610565366004612df7565b6116ec565b34801561057657600080fd5b50610299610585366004612e14565b611700565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fdba45fe000000000000000000000000000000000000000000000000000000000148061061d57507fffffffff0000000000000000000000000000000000000000000000000000000082167f6c2f1a1700000000000000000000000000000000000000000000000000000000145b92915050565b61062b611842565b73ffffffffffffffffffffffffffffffffffffffff831661066f5761066a828277ffffffffffffffffffffffffffffffffffffffffffffffff166118c5565b505050565b6106aa73ffffffffffffffffffffffffffffffffffffffff84168377ffffffffffffffffffffffffffffffffffffffffffffffff8416611969565b6040805133815273ffffffffffffffffffffffffffffffffffffffff848116602083015285168183015277ffffffffffffffffffffffffffffffffffffffffffffffff8316606082015290517f7ff78a71698bdb18dcca96f52ab25e0a1b146fb6a49adf8e6845299e49021f299181900360800190a1505050565b61072d611842565b670de0b6b3a764000067ffffffffffffffff82161115610779576040517f05e8ac2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660058190556040519081527f08f7c0d17932ddb8523bc06754d42ff19ebc77d76a8b9bfde02c28ab1ed3d6399060200160405180910390a150565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461082e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008467ffffffffffffffff81111561084957610849612cc4565b60405190808252806020026020018201604052801561088257816020015b61086f61280d565b8152602001906001900390816108675790505b5090506000806000805b888110156109cd5760008060006108c88d8d868181106108ae576108ae612e93565b90506020028101906108c09190612ec2565b8d8d8d611a3d565b92509250925082602001516000146109b95760405180608001604052808e8e878181106108f7576108f7612e93565b90506020028101906109099190612ec2565b61091291612f27565b81526020018481526020018381526020018281525088868061093390612f92565b97508151811061094557610945612e93565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16036109b2578660010196506109b9565b8560010195505b505050806109c690612f92565b905061088c565b50821515806109db57508115155b156109f1576109ec85858585611b4d565b6109fb565b6109fb85346118c5565b505050505050505050565b610a0e611842565b670de0b6b3a764000067ffffffffffffffff82161115610a5a576040517f997ea36000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610b0257507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15610b39576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff838116600081815260036020908152604080832094871680845294825280832067ffffffffffffffff87169081905581519586529185019190915290927f5eba5a8afa39780f0f99b6cbeb95f3da6a7040ca00abd46bdc91a0a060134139910160405180910390a3505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610cc5611842565b670de0b6b3a764000067ffffffffffffffff82161115610d11576040517f997ea36000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610db957507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15610df0576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff848116600081815260026020908152604080832088845282528083209487168084529482529182902067ffffffffffffffff86169081905582519485529084015285927f5eba5a8afa39780f0f99b6cbeb95f3da6a7040ca00abd46bdc91a0a060134139910160405180910390a350505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610f06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2a9190612fca565b905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f9e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000610fb08888888888611a3d565b9250925092508260200151600003610fd457610fcc84346118c5565b5050506110c4565b604080516001808252818301909252600091816020015b610ff361280d565b815260200190600190039081610feb57505060408051608081019091529091508061101e8a8c612f27565b8152602001858152602001848152602001838152508160008151811061104657611046612e93565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff16036110b6576109ec858260016000611b4d565b6109fb858260006001611b4d565b5050505050565b604080518082018252600080825260208083018290528351808501855282815280820183905284518086018652838152808301849052855180870190965283865291850183905292938261111e88612fe3565b90507fffff0000000000000000000000000000000000000000000000000000000000008082169081016111b957505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811683527f0000000000000000000000000000000000000000000000000000000000000000168152909350915060009050611512565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff161415801561126157507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614155b15611298576040517ff861803000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008b8060200190518101906112b1919061303c565b77ffffffffffffffffffffffffffffffffffffffffffffffff91821698509116955063ffffffff1693505050428210159050611319576040517fb6c405f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808e1660009081526002602090815260408083208984528252808320938f1683529290529081205490819003611393575073ffffffffffffffffffffffffffffffffffffffff808e166000908152600360209081526040808320938f16835292905220545b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001687526113f96113e182670de0b6b3a76400006130ae565b6113eb90866130c1565b670de0b6b3a7640000612361565b602088015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116908d16036114865773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016885260208088015190890152611503565b6005546000906114a2906113e190670de0b6b3a76400006130d8565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168a5290506114fc6114f283670de0b6b3a76400006130ae565b6113eb90836130c1565b60208a0152505b96995094975094955050505050505b93509350939050565b611523611842565b6000818152600460205260408120549081900361156c576040517f03aad31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600460205260408082208290558051600180825281830190925290816020015b604080518082019091526000808252602082015281526020019060019003908161159157905050905060405180604001604052808481526020018377ffffffffffffffffffffffffffffffffffffffffffffffff16815250816000815181106115fc576115fc612e93565b60209081029190910101526040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa199061167b908490309060040161314b565b600060405180830381600087803b15801561169557600080fd5b505af11580156116a9573d6000803e3d6000fd5b50505050827f843f0b103e50b42b08f9d30f12f961845a6d02623730872e24644899c0dd9895836040516116df91815260200190565b60405180910390a2505050565b6116f4611842565b6116fd81612399565b50565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161480159061175e575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15611795576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f14060f2300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906314060f239061180b90869086908690600401613183565b600060405180830381600087803b15801561182557600080fd5b505af1158015611839573d6000803e3d6000fd5b50505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146118c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c38565b565b80156119655760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611925576040519150601f19603f3d011682016040523d82523d6000602084013e61192a565b606091505b505090508061066a576040517fef2af20100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b60405173ffffffffffffffffffffffffffffffffffffffff831660248201526044810182905261066a9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261248e565b6040805180820190915260008082526020820152604080518082019091526000808252602082015260003073ffffffffffffffffffffffffffffffffffffffff851603611ab6576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611ac4888a018a613203565b915050600081611ad390612fe3565b905060007e010000000000000000000000000000000000000000000000000000000000007fffff000000000000000000000000000000000000000000000000000000000000831614611b2e57611b2b888a018a612df7565b90505b611b398784836110cb565b955095509550505050955095509592505050565b60008267ffffffffffffffff811115611b6857611b68612cc4565b604051908082528060200260200182016040528015611bad57816020015b6040805180820190915260008082526020820152815260200190600190039081611b865790505b50905060008267ffffffffffffffff811115611bcb57611bcb612cc4565b604051908082528060200260200182016040528015611c1057816020015b6040805180820190915260008082526020820152815260200190600190039081611be95790505b509050600080808080611c23888a6130d8565b905060005b81811015611f72577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168b8281518110611c7957611c79612e93565b6020026020010151602001516000015173ffffffffffffffffffffffffffffffffffffffff1603611d3f5760405180604001604052808c8381518110611cc157611cc1612e93565b60200260200101516000015181526020018c8381518110611ce457611ce4612e93565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16815250888580611d1d90612f92565b965081518110611d2f57611d2f612e93565b6020026020010181905250611e34565b60405180604001604052808c8381518110611d5c57611d5c612e93565b60200260200101516000015181526020018c8381518110611d7f57611d7f612e93565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16815250878480611db890612f92565b955081518110611dca57611dca612e93565b60200260200101819052508a8181518110611de757611de7612e93565b6020026020010151602001516020015186611e0291906130d8565b95508a8181518110611e1657611e16612e93565b6020026020010151604001516020015185611e3191906130d8565b94505b8a8181518110611e4657611e46612e93565b602002602001015160600151600014611f62578b73ffffffffffffffffffffffffffffffffffffffff168b8281518110611e8257611e82612e93565b6020026020010151600001517f88b15eb682210089cddf967648e2cb2a4535aeadc8f8f36050922e33c04e71258d8481518110611ec157611ec1612e93565b6020026020010151602001518e8581518110611edf57611edf612e93565b6020026020010151604001518f8681518110611efd57611efd612e93565b602002602001015160600151604051611f5993929190835173ffffffffffffffffffffffffffffffffffffffff908116825260209485015185830152835116604082015291909201516060820152608081019190915260a00190565b60405180910390a35b611f6b81612f92565b9050611c28565b50600034156120405734861115611fb5576040517fb2e532de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0876040518263ffffffff1660e01b81526004016000604051808303818588803b15801561201d57600080fd5b505af1158015612031573d6000803e3d6000fd5b50505050508534039050612088565b85156120885761208873ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168d308961259a565b87511561211d577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b0d9fa19898e6040518363ffffffff1660e01b81526004016120ea92919061314b565b600060405180830381600087803b15801561210457600080fd5b505af1158015612118573d6000803e3d6000fd5b505050505b865115612349576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156121ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d29190612fca565b8511156122a25760005b8751811015612265578781815181106121f7576121f7612e93565b60200260200101516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16600460008a848151811061223357612233612e93565b6020908102919091018101515182528101919091526040016000208054909101905561225e81612f92565b90506121dc565b507ff52e5907b69d97c33392936c12d78b494463b78c5b72df50b4c497eee5720b678760405161229591906132a7565b60405180910390a1612349565b6040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa1990612316908a90309060040161314b565b600060405180830381600087803b15801561233057600080fd5b505af1158015612344573d6000803e3d6000fd5b505050505b6123538c826118c5565b505050505050505050505050565b6000821561238f57816123756001856130ae565b61237f91906132ba565b61238a9060016130d8565b612392565b60005b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff821603612418576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c38565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006124f0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166125fe9092919063ffffffff16565b80519091501561066a578080602001905181019061250e91906132f5565b61066a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610c38565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526125f89085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016119bb565b50505050565b606061260d8484600085612615565b949350505050565b6060824710156126a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610c38565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516126d09190613317565b60006040518083038185875af1925050503d806000811461270d576040519150601f19603f3d011682016040523d82523d6000602084013e612712565b606091505b50915091506127238783838761272e565b979650505050505050565b606083156127c45782516000036127bd5773ffffffffffffffffffffffffffffffffffffffff85163b6127bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c38565b508161260d565b61260d83838151156127d95781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c389190612919565b6040518060800160405280600080191681526020016128556040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b815260200161288d6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b8152602001600081525090565b6000602082840312156128ac57600080fd5b5035919050565b6000602082840312156128c557600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461239257600080fd5b60005b838110156129105781810151838201526020016128f8565b50506000910152565b60208152600082518060208401526129388160408501602087016128f5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b73ffffffffffffffffffffffffffffffffffffffff811681146116fd57600080fd5b80356129978161296a565b919050565b600080604083850312156129af57600080fd5b82356129ba8161296a565b915060208301356129ca8161296a565b809150509250929050565b77ffffffffffffffffffffffffffffffffffffffffffffffff811681146116fd57600080fd5b600080600060608486031215612a1057600080fd5b8335612a1b8161296a565b92506020840135612a2b8161296a565b91506040840135612a3b816129d5565b809150509250925092565b803567ffffffffffffffff8116811461299757600080fd5b600060208284031215612a7057600080fd5b61239282612a46565b60008083601f840112612a8b57600080fd5b50813567ffffffffffffffff811115612aa357600080fd5b602083019150836020828501011115612abb57600080fd5b9250929050565b600080600080600060608688031215612ada57600080fd5b853567ffffffffffffffff80821115612af257600080fd5b818801915088601f830112612b0657600080fd5b813581811115612b1557600080fd5b8960208260051b8501011115612b2a57600080fd5b602092830197509550908701359080821115612b4557600080fd5b50612b5288828901612a79565b9094509250612b6590506040870161298c565b90509295509295909350565b600080600060608486031215612b8657600080fd5b8335612b918161296a565b92506020840135612ba18161296a565b9150612baf60408501612a46565b90509250925092565b600080600060608486031215612bcd57600080fd5b8335612bd88161296a565b9250602084013591506040840135612a3b8161296a565b60008060008060808587031215612c0557600080fd5b8435612c108161296a565b9350602085013592506040850135612c278161296a565b9150612c3560608601612a46565b905092959194509250565b600080600080600060608688031215612c5857600080fd5b853567ffffffffffffffff80821115612c7057600080fd5b612c7c89838a01612a79565b90975095506020880135915080821115612c9557600080fd5b50612ca288828901612a79565b9094509250506040860135612cb68161296a565b809150509295509295909350565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112612d0457600080fd5b813567ffffffffffffffff80821115612d1f57612d1f612cc4565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715612d6557612d65612cc4565b81604052838152866020858801011115612d7e57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600060608486031215612db357600080fd5b8335612dbe8161296a565b9250602084013567ffffffffffffffff811115612dda57600080fd5b612de686828701612cf3565b9250506040840135612a3b8161296a565b600060208284031215612e0957600080fd5b81356123928161296a565b600080600060408486031215612e2957600080fd5b83359250602084013567ffffffffffffffff80821115612e4857600080fd5b818601915086601f830112612e5c57600080fd5b813581811115612e6b57600080fd5b8760208260061b8501011115612e8057600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612ef757600080fd5b83018035915067ffffffffffffffff821115612f1257600080fd5b602001915036819003821315612abb57600080fd5b8035602083101561061d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612fc357612fc3612f63565b5060010190565b600060208284031215612fdc57600080fd5b5051919050565b80516020808301519190811015613022577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b805163ffffffff8116811461299757600080fd5b60008060008060008060c0878903121561305557600080fd5b8651955061306560208801613028565b945061307360408801613028565b93506060870151613083816129d5565b6080880151909350613094816129d5565b91506130a260a08801613028565b90509295509295509295565b8181038181111561061d5761061d612f63565b808202811582820484141761061d5761061d612f63565b8082018082111561061d5761061d612f63565b600081518084526020808501945080840160005b838110156131405781518051885283015177ffffffffffffffffffffffffffffffffffffffffffffffff1683880152604090960195908201906001016130ff565b509495945050505050565b60408152600061315e60408301856130eb565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b8381526040602080830182905282820184905260009190859060608501845b878110156131f65783356131b58161296a565b73ffffffffffffffffffffffffffffffffffffffff16825267ffffffffffffffff6131e1858501612a46565b168284015292840192908401906001016131a2565b5098975050505050505050565b6000806080838503121561321657600080fd5b83601f84011261322557600080fd5b6040516060810167ffffffffffffffff828210818311171561324957613249612cc4565b81604052829150606086018781111561326157600080fd5b865b8181101561327b578035845260209384019301613263565b509294509135918083111561328f57600080fd5b505061329d85828601612cf3565b9150509250929050565b60208152600061239260208301846130eb565b6000826132f0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006020828403121561330757600080fd5b8151801515811461239257600080fd5b600082516133298184602087016128f5565b919091019291505056fea164736f6c6343000813000a000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb400000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000478aa2ac9f6d65f84e09d9185d126c3a17c2a93c000000000000000000000000525a8b8e83a8168c599f6160f6303002c19087a9
Deployed Bytecode
0x6080604052600436106101805760003560e01c806376cf3187116100d6578063dba45fe01161007f578063ea4b861b11610059578063ea4b861b14610516578063f2fde38b1461054a578063f65df9621461056a57600080fd5b8063dba45fe014610478578063e03dab1a1461048b578063e389d9a4146104f657600080fd5b80638da5cb5b116100b05780638da5cb5b14610418578063ce7817d114610443578063d09dc3391461046357600080fd5b806376cf3187146103a557806379ba5097146103c557806387d6d843146103da57600080fd5b806332f5f746116101385780636387866811610112578063638786681461032a5780636c2f1a171461035e5780636d1342cb1461037157600080fd5b806332f5f7461461029b5780633aa5ac07146102b1578063505380941461030a57600080fd5b8063181f5a7711610169578063181f5a77146101f55780631cc7f2d8146102415780631d4d84a21461027957600080fd5b8063013f542b1461018557806301ffc9a7146101c5575b600080fd5b34801561019157600080fd5b506101b26101a036600461289a565b60046020526000908152604090205481565b6040519081526020015b60405180910390f35b3480156101d157600080fd5b506101e56101e03660046128b3565b61058a565b60405190151581526020016101bc565b34801561020157600080fd5b50604080518082018252601081527f4665654d616e6167657220322e312e3000000000000000000000000000000000602082015290516101bc9190612919565b34801561024d57600080fd5b506101b261025c36600461299c565b600360209081526000928352604080842090915290825290205481565b34801561028557600080fd5b506102996102943660046129fb565b610623565b005b3480156102a757600080fd5b506101b260055481565b3480156102bd57600080fd5b506102e57f000000000000000000000000525a8b8e83a8168c599f6160f6303002c19087a981565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bc565b34801561031657600080fd5b50610299610325366004612a5e565b610725565b34801561033657600080fd5b506102e57f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab181565b61029961036c366004612ac2565b6107bf565b34801561037d57600080fd5b506102e57f000000000000000000000000478aa2ac9f6d65f84e09d9185d126c3a17c2a93c81565b3480156103b157600080fd5b506102996103c0366004612b71565b610a06565b3480156103d157600080fd5b50610299610bbb565b3480156103e657600080fd5b506101b26103f5366004612bb8565b600260209081526000938452604080852082529284528284209052825290205481565b34801561042457600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166102e5565b34801561044f57600080fd5b5061029961045e366004612bef565b610cbd565b34801561046f57600080fd5b506101b2610e79565b610299610486366004612c40565b610f2f565b34801561049757600080fd5b506104ab6104a6366004612d9e565b6110cb565b60408051845173ffffffffffffffffffffffffffffffffffffffff9081168252602095860151868301528451169181019190915292909101516060830152608082015260a0016101bc565b34801561050257600080fd5b5061029961051136600461289a565b61151b565b34801561052257600080fd5b506102e57f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb481565b34801561055657600080fd5b50610299610565366004612df7565b6116ec565b34801561057657600080fd5b50610299610585366004612e14565b611700565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fdba45fe000000000000000000000000000000000000000000000000000000000148061061d57507fffffffff0000000000000000000000000000000000000000000000000000000082167f6c2f1a1700000000000000000000000000000000000000000000000000000000145b92915050565b61062b611842565b73ffffffffffffffffffffffffffffffffffffffff831661066f5761066a828277ffffffffffffffffffffffffffffffffffffffffffffffff166118c5565b505050565b6106aa73ffffffffffffffffffffffffffffffffffffffff84168377ffffffffffffffffffffffffffffffffffffffffffffffff8416611969565b6040805133815273ffffffffffffffffffffffffffffffffffffffff848116602083015285168183015277ffffffffffffffffffffffffffffffffffffffffffffffff8316606082015290517f7ff78a71698bdb18dcca96f52ab25e0a1b146fb6a49adf8e6845299e49021f299181900360800190a1505050565b61072d611842565b670de0b6b3a764000067ffffffffffffffff82161115610779576040517f05e8ac2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660058190556040519081527f08f7c0d17932ddb8523bc06754d42ff19ebc77d76a8b9bfde02c28ab1ed3d6399060200160405180910390a150565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000478aa2ac9f6d65f84e09d9185d126c3a17c2a93c161461082e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008467ffffffffffffffff81111561084957610849612cc4565b60405190808252806020026020018201604052801561088257816020015b61086f61280d565b8152602001906001900390816108675790505b5090506000806000805b888110156109cd5760008060006108c88d8d868181106108ae576108ae612e93565b90506020028101906108c09190612ec2565b8d8d8d611a3d565b92509250925082602001516000146109b95760405180608001604052808e8e878181106108f7576108f7612e93565b90506020028101906109099190612ec2565b61091291612f27565b81526020018481526020018381526020018281525088868061093390612f92565b97508151811061094557610945612e93565b60200260200101819052507f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb473ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16036109b2578660010196506109b9565b8560010195505b505050806109c690612f92565b905061088c565b50821515806109db57508115155b156109f1576109ec85858585611b4d565b6109fb565b6109fb85346118c5565b505050505050505050565b610a0e611842565b670de0b6b3a764000067ffffffffffffffff82161115610a5a576040517f997ea36000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610b0257507f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15610b39576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff838116600081815260036020908152604080832094871680845294825280832067ffffffffffffffff87169081905581519586529185019190915290927f5eba5a8afa39780f0f99b6cbeb95f3da6a7040ca00abd46bdc91a0a060134139910160405180910390a3505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610cc5611842565b670de0b6b3a764000067ffffffffffffffff82161115610d11576040517f997ea36000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610db957507f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15610df0576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff848116600081815260026020908152604080832088845282528083209487168084529482529182902067ffffffffffffffff86169081905582519485529084015285927f5eba5a8afa39780f0f99b6cbeb95f3da6a7040ca00abd46bdc91a0a060134139910160405180910390a350505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb473ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610f06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2a9190612fca565b905090565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000478aa2ac9f6d65f84e09d9185d126c3a17c2a93c1614610f9e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000610fb08888888888611a3d565b9250925092508260200151600003610fd457610fcc84346118c5565b5050506110c4565b604080516001808252818301909252600091816020015b610ff361280d565b815260200190600190039081610feb57505060408051608081019091529091508061101e8a8c612f27565b8152602001858152602001848152602001838152508160008151811061104657611046612e93565b60200260200101819052507f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb473ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff16036110b6576109ec858260016000611b4d565b6109fb858260006001611b4d565b5050505050565b604080518082018252600080825260208083018290528351808501855282815280820183905284518086018652838152808301849052855180870190965283865291850183905292938261111e88612fe3565b90507fffff0000000000000000000000000000000000000000000000000000000000008082169081016111b957505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1811683527f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb4168152909350915060009050611512565b7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab173ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff161415801561126157507f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb473ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614155b15611298576040517ff861803000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008b8060200190518101906112b1919061303c565b77ffffffffffffffffffffffffffffffffffffffffffffffff91821698509116955063ffffffff1693505050428210159050611319576040517fb6c405f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808e1660009081526002602090815260408083208984528252808320938f1683529290529081205490819003611393575073ffffffffffffffffffffffffffffffffffffffff808e166000908152600360209081526040808320938f16835292905220545b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb41687526113f96113e182670de0b6b3a76400006130ae565b6113eb90866130c1565b670de0b6b3a7640000612361565b602088015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb48116908d16036114865773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb416885260208088015190890152611503565b6005546000906114a2906113e190670de0b6b3a76400006130d8565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1168a5290506114fc6114f283670de0b6b3a76400006130ae565b6113eb90836130c1565b60208a0152505b96995094975094955050505050505b93509350939050565b611523611842565b6000818152600460205260408120549081900361156c576040517f03aad31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600460205260408082208290558051600180825281830190925290816020015b604080518082019091526000808252602082015281526020019060019003908161159157905050905060405180604001604052808481526020018377ffffffffffffffffffffffffffffffffffffffffffffffff16815250816000815181106115fc576115fc612e93565b60209081029190910101526040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000525a8b8e83a8168c599f6160f6303002c19087a9169063b0d9fa199061167b908490309060040161314b565b600060405180830381600087803b15801561169557600080fd5b505af11580156116a9573d6000803e3d6000fd5b50505050827f843f0b103e50b42b08f9d30f12f961845a6d02623730872e24644899c0dd9895836040516116df91815260200190565b60405180910390a2505050565b6116f4611842565b6116fd81612399565b50565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000478aa2ac9f6d65f84e09d9185d126c3a17c2a93c161480159061175e575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15611795576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f14060f2300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000525a8b8e83a8168c599f6160f6303002c19087a916906314060f239061180b90869086908690600401613183565b600060405180830381600087803b15801561182557600080fd5b505af1158015611839573d6000803e3d6000fd5b50505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146118c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c38565b565b80156119655760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611925576040519150601f19603f3d011682016040523d82523d6000602084013e61192a565b606091505b505090508061066a576040517fef2af20100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b60405173ffffffffffffffffffffffffffffffffffffffff831660248201526044810182905261066a9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261248e565b6040805180820190915260008082526020820152604080518082019091526000808252602082015260003073ffffffffffffffffffffffffffffffffffffffff851603611ab6576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611ac4888a018a613203565b915050600081611ad390612fe3565b905060007e010000000000000000000000000000000000000000000000000000000000007fffff000000000000000000000000000000000000000000000000000000000000831614611b2e57611b2b888a018a612df7565b90505b611b398784836110cb565b955095509550505050955095509592505050565b60008267ffffffffffffffff811115611b6857611b68612cc4565b604051908082528060200260200182016040528015611bad57816020015b6040805180820190915260008082526020820152815260200190600190039081611b865790505b50905060008267ffffffffffffffff811115611bcb57611bcb612cc4565b604051908082528060200260200182016040528015611c1057816020015b6040805180820190915260008082526020820152815260200190600190039081611be95790505b509050600080808080611c23888a6130d8565b905060005b81811015611f72577f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb473ffffffffffffffffffffffffffffffffffffffff168b8281518110611c7957611c79612e93565b6020026020010151602001516000015173ffffffffffffffffffffffffffffffffffffffff1603611d3f5760405180604001604052808c8381518110611cc157611cc1612e93565b60200260200101516000015181526020018c8381518110611ce457611ce4612e93565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16815250888580611d1d90612f92565b965081518110611d2f57611d2f612e93565b6020026020010181905250611e34565b60405180604001604052808c8381518110611d5c57611d5c612e93565b60200260200101516000015181526020018c8381518110611d7f57611d7f612e93565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16815250878480611db890612f92565b955081518110611dca57611dca612e93565b60200260200101819052508a8181518110611de757611de7612e93565b6020026020010151602001516020015186611e0291906130d8565b95508a8181518110611e1657611e16612e93565b6020026020010151604001516020015185611e3191906130d8565b94505b8a8181518110611e4657611e46612e93565b602002602001015160600151600014611f62578b73ffffffffffffffffffffffffffffffffffffffff168b8281518110611e8257611e82612e93565b6020026020010151600001517f88b15eb682210089cddf967648e2cb2a4535aeadc8f8f36050922e33c04e71258d8481518110611ec157611ec1612e93565b6020026020010151602001518e8581518110611edf57611edf612e93565b6020026020010151604001518f8681518110611efd57611efd612e93565b602002602001015160600151604051611f5993929190835173ffffffffffffffffffffffffffffffffffffffff908116825260209485015185830152835116604082015291909201516060820152608081019190915260a00190565b60405180910390a35b611f6b81612f92565b9050611c28565b50600034156120405734861115611fb5576040517fb2e532de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab173ffffffffffffffffffffffffffffffffffffffff1663d0e30db0876040518263ffffffff1660e01b81526004016000604051808303818588803b15801561201d57600080fd5b505af1158015612031573d6000803e3d6000fd5b50505050508534039050612088565b85156120885761208873ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1168d308961259a565b87511561211d577f000000000000000000000000525a8b8e83a8168c599f6160f6303002c19087a973ffffffffffffffffffffffffffffffffffffffff1663b0d9fa19898e6040518363ffffffff1660e01b81526004016120ea92919061314b565b600060405180830381600087803b15801561210457600080fd5b505af1158015612118573d6000803e3d6000fd5b505050505b865115612349576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb473ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156121ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d29190612fca565b8511156122a25760005b8751811015612265578781815181106121f7576121f7612e93565b60200260200101516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16600460008a848151811061223357612233612e93565b6020908102919091018101515182528101919091526040016000208054909101905561225e81612f92565b90506121dc565b507ff52e5907b69d97c33392936c12d78b494463b78c5b72df50b4c497eee5720b678760405161229591906132a7565b60405180910390a1612349565b6040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000525a8b8e83a8168c599f6160f6303002c19087a9169063b0d9fa1990612316908a90309060040161314b565b600060405180830381600087803b15801561233057600080fd5b505af1158015612344573d6000803e3d6000fd5b505050505b6123538c826118c5565b505050505050505050505050565b6000821561238f57816123756001856130ae565b61237f91906132ba565b61238a9060016130d8565b612392565b60005b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff821603612418576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c38565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006124f0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166125fe9092919063ffffffff16565b80519091501561066a578080602001905181019061250e91906132f5565b61066a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610c38565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526125f89085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016119bb565b50505050565b606061260d8484600085612615565b949350505050565b6060824710156126a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610c38565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516126d09190613317565b60006040518083038185875af1925050503d806000811461270d576040519150601f19603f3d011682016040523d82523d6000602084013e612712565b606091505b50915091506127238783838761272e565b979650505050505050565b606083156127c45782516000036127bd5773ffffffffffffffffffffffffffffffffffffffff85163b6127bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c38565b508161260d565b61260d83838151156127d95781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c389190612919565b6040518060800160405280600080191681526020016128556040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b815260200161288d6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b8152602001600081525090565b6000602082840312156128ac57600080fd5b5035919050565b6000602082840312156128c557600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461239257600080fd5b60005b838110156129105781810151838201526020016128f8565b50506000910152565b60208152600082518060208401526129388160408501602087016128f5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b73ffffffffffffffffffffffffffffffffffffffff811681146116fd57600080fd5b80356129978161296a565b919050565b600080604083850312156129af57600080fd5b82356129ba8161296a565b915060208301356129ca8161296a565b809150509250929050565b77ffffffffffffffffffffffffffffffffffffffffffffffff811681146116fd57600080fd5b600080600060608486031215612a1057600080fd5b8335612a1b8161296a565b92506020840135612a2b8161296a565b91506040840135612a3b816129d5565b809150509250925092565b803567ffffffffffffffff8116811461299757600080fd5b600060208284031215612a7057600080fd5b61239282612a46565b60008083601f840112612a8b57600080fd5b50813567ffffffffffffffff811115612aa357600080fd5b602083019150836020828501011115612abb57600080fd5b9250929050565b600080600080600060608688031215612ada57600080fd5b853567ffffffffffffffff80821115612af257600080fd5b818801915088601f830112612b0657600080fd5b813581811115612b1557600080fd5b8960208260051b8501011115612b2a57600080fd5b602092830197509550908701359080821115612b4557600080fd5b50612b5288828901612a79565b9094509250612b6590506040870161298c565b90509295509295909350565b600080600060608486031215612b8657600080fd5b8335612b918161296a565b92506020840135612ba18161296a565b9150612baf60408501612a46565b90509250925092565b600080600060608486031215612bcd57600080fd5b8335612bd88161296a565b9250602084013591506040840135612a3b8161296a565b60008060008060808587031215612c0557600080fd5b8435612c108161296a565b9350602085013592506040850135612c278161296a565b9150612c3560608601612a46565b905092959194509250565b600080600080600060608688031215612c5857600080fd5b853567ffffffffffffffff80821115612c7057600080fd5b612c7c89838a01612a79565b90975095506020880135915080821115612c9557600080fd5b50612ca288828901612a79565b9094509250506040860135612cb68161296a565b809150509295509295909350565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112612d0457600080fd5b813567ffffffffffffffff80821115612d1f57612d1f612cc4565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715612d6557612d65612cc4565b81604052838152866020858801011115612d7e57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600060608486031215612db357600080fd5b8335612dbe8161296a565b9250602084013567ffffffffffffffff811115612dda57600080fd5b612de686828701612cf3565b9250506040840135612a3b8161296a565b600060208284031215612e0957600080fd5b81356123928161296a565b600080600060408486031215612e2957600080fd5b83359250602084013567ffffffffffffffff80821115612e4857600080fd5b818601915086601f830112612e5c57600080fd5b813581811115612e6b57600080fd5b8760208260061b8501011115612e8057600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612ef757600080fd5b83018035915067ffffffffffffffff821115612f1257600080fd5b602001915036819003821315612abb57600080fd5b8035602083101561061d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612fc357612fc3612f63565b5060010190565b600060208284031215612fdc57600080fd5b5051919050565b80516020808301519190811015613022577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b805163ffffffff8116811461299757600080fd5b60008060008060008060c0878903121561305557600080fd5b8651955061306560208801613028565b945061307360408801613028565b93506060870151613083816129d5565b6080880151909350613094816129d5565b91506130a260a08801613028565b90509295509295509295565b8181038181111561061d5761061d612f63565b808202811582820484141761061d5761061d612f63565b8082018082111561061d5761061d612f63565b600081518084526020808501945080840160005b838110156131405781518051885283015177ffffffffffffffffffffffffffffffffffffffffffffffff1683880152604090960195908201906001016130ff565b509495945050505050565b60408152600061315e60408301856130eb565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b8381526040602080830182905282820184905260009190859060608501845b878110156131f65783356131b58161296a565b73ffffffffffffffffffffffffffffffffffffffff16825267ffffffffffffffff6131e1858501612a46565b168284015292840192908401906001016131a2565b5098975050505050505050565b6000806080838503121561321657600080fd5b83601f84011261322557600080fd5b6040516060810167ffffffffffffffff828210818311171561324957613249612cc4565b81604052829150606086018781111561326157600080fd5b865b8181101561327b578035845260209384019301613263565b509294509135918083111561328f57600080fd5b505061329d85828601612cf3565b9150509250929050565b60208152600061239260208301846130eb565b6000826132f0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006020828403121561330757600080fd5b8151801515811461239257600080fd5b600082516133298184602087016128f5565b919091019291505056fea164736f6c6343000813000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb400000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000478aa2ac9f6d65f84e09d9185d126c3a17c2a93c000000000000000000000000525a8b8e83a8168c599f6160f6303002c19087a9
-----Decoded View---------------
Arg [0] : _linkAddress (address): 0xf97f4df75117a78c1A5a0DBb814Af92458539FB4
Arg [1] : _nativeAddress (address): 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
Arg [2] : _proxyAddress (address): 0x478Aa2aC9F6D65F84e09D9185d126c3a17c2a93C
Arg [3] : _rewardManagerAddress (address): 0x525a8B8E83A8168c599F6160f6303002C19087A9
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000f97f4df75117a78c1a5a0dbb814af92458539fb4
Arg [1] : 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
Arg [2] : 000000000000000000000000478aa2ac9f6d65f84e09d9185d126c3a17c2a93c
Arg [3] : 000000000000000000000000525a8b8e83a8168c599f6160f6303002c19087a9
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.