diff --git a/README.md b/README.md index 78d3424..1d66299 100644 --- a/README.md +++ b/README.md @@ -252,5 +252,39 @@ function getCurrentCollateralRatio(address who, address currencyId) external vie function getDebitExchangeRate(address currencyId) external view returns (uint256); ``` +### Incentives +- Incentives contract address: `ADDRESS.Incentives` +``` +enum PoolId { LOANS, DEX } + +// Gets reward amount in `rewardCurrency` added per period +// Returns (reward_amount) +function getIncentiveRewardAmount(PoolId pool, address poolCurrencyId, address rewardCurrencyId) external view returns (uint256); + +// Fixed reward rate for dex reward pool per period +// Returns (dex_reward_rate) as a FixedU128 representing a decimal +function getDexRewardRate(address currencyId) external view returns (uint256); + +// Stake LP token to add shares to PoolId::Dex +// Returns a boolean value indicating whether the operation succeeded. +function depositDexShare(address currencyId, uint256 amount) external returns (bool); + +// Unstake LP token to remove shares from PoolId::Dex +// Returns a boolean value indicating whether the operation succeeded. +function withdrawDexShare(address currencyId, uint256 amount) external returns (bool); + +// Claim all avalible multi currencies rewards for specific PoolId +// Returns a boolean value indicating whether the operation succeeded. +function claimRewards(PoolId pool, address poolCurrencyId) external returns (bool); + +// Gets deduction rate for claiming reward early +// returns (claim_reward_deduction_rate) as a FixedU128 representing a decimal value +function getClaimRewardDeductionRate(PoolId pool, address poolCurrencyId) external view returns (uint256); + +// Gets the pending rewards for a pool, actual reward could be deducted. +// returns (balances), an array of reward balances corresponding to currencyIds +function getPendingRewards(address[] calldata currencyIds, PoolId pool, address poolCurrencyId, address who) external view returns (uint256[] memory); +``` + ## DeFi Contracts (Coming Soon) These contracts will make Acala's DeFi primitives (stablecoin, staking derivative, and DeX) available in Acala EVM. diff --git a/contracts/incentives/Incentives.sol b/contracts/incentives/Incentives.sol new file mode 100644 index 0000000..bd25381 --- /dev/null +++ b/contracts/incentives/Incentives.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.0; + +import "./InterfaceIncentives.sol"; + +contract Incentives is InterfaceIncentives { + address constant private precompile = address(0x000000000000000000000000000000000000040A); + + /** + * @dev Gets reward amount in `rewardCurrency` added per period + * Returns (reward_amount) + */ + function getIncentiveRewardAmount(PoolId pool, address poolCurrencyId, address rewardCurrencyId) + public + view + override + returns (uint256) { + (bool success, bytes memory returnData) = precompile.staticcall(abi.encodeWithSignature("getIncentiveRewardAmount(PoolId,address,address)", pool, poolCurrencyId, rewardCurrencyId)); + assembly { + if eq(success, 0) { + revert(add(returnData, 0x20), returndatasize()) + } + } + + return abi.decode(returnData, (uint256)); + } + + /** + * @dev Fixed reward rate for dex reward pool per period + * returns (dex_reward_rate) as a FixedU128 representing a decimal value + */ + function getDexRewardRate(address currencyId) + public + view + override + returns (uint256) { + (bool success, bytes memory returnData) = precompile.staticcall(abi.encodeWithSignature("getDexRewardRate(address)", currencyId)); + assembly { + if eq(success, 0) { + revert(add(returnData, 0x20), returndatasize()) + } + } + + return abi.decode(returnData, (uint256)); + } + + /** + * @dev Stake LP token to add shares to PoolId::Dex + * Returns a boolean value indicating whether the operation succeeded. + */ + function depositDexShare(address currencyId, uint256 amount) + public + override + returns (bool) { + require(amount != 0, "Incentives: amount is zero"); + + (bool success, bytes memory returnData) = precompile.call(abi.encodeWithSignature("depositDexShare(address,address,uint256)", msg.sender, currencyId, amount)); + assembly { + if eq(success, 0) { + revert(add(returnData, 0x20), returndatasize()) + } + } + + emit DepositedShare(msg.sender, currencyId, amount); + return true; + } + + /** + * @dev Unstake LP token to remove shares from PoolId::Dex + * Returns a boolean value indicating whether the operation succeeded. + */ + function withdrawDexShare(address currencyId, uint256 amount) + public + override + returns (bool) { + require(amount != 0, "Incentives: amount is zero"); + + (bool success, bytes memory returnData) = precompile.call(abi.encodeWithSignature("withdrawDexShare(address,address,uint256)", msg.sender, currencyId, amount)); + assembly { + if eq(success, 0) { + revert(add(returnData, 0x20), returndatasize()) + } + } + + emit WithdrewShare(msg.sender, currencyId, amount); + return true; + } + + /** + * @dev Claim all avalible multi currencies rewards for specific PoolId + * Returns a boolean value indicating whether the operation succeeded. + */ + function claimRewards(PoolId pool, address poolCurrencyId) + public + override + returns (bool) { + (bool success, bytes memory returnData) = precompile.call(abi.encodeWithSignature("claimRewards(address,PoolId,address)", msg.sender, pool, poolCurrencyId)); + assembly { + if eq(success, 0) { + revert(add(returnData, 0x20), returndatasize()) + } + } + + emit ClaimedRewards(msg.sender, pool, poolCurrencyId); + return true; + } + + /** + * @dev Gets deduction rate for claiming reward early + * returns (claim_reward_deduction_rate) as a FixedU128 representing a decimal value + */ + function getClaimRewardDeductionRate(PoolId pool, address poolCurrencyId) + public + view + override + returns (uint256) { + (bool success, bytes memory returnData) = precompile.staticcall(abi.encodeWithSignature("getClaimRewardDeductionRate(PoolId,address)", pool, poolCurrencyId)); + assembly { + if eq(success, 0) { + revert(add(returnData, 0x20), returndatasize()) + } + } + + return abi.decode(returnData, (uint256)); + } + + /** + * @dev Gets the pending rewards for a pool, actual reward could be deducted. + * returns (balances), an array of reward balances corresponding to currencyIds + */ + function getPendingRewards(address[] calldata currencyIds, PoolId pool, address poolCurrencyId, address who) + public + view + override + returns (uint256[] memory) { + (bool success, bytes memory returnData) = precompile.staticcall(abi.encodeWithSignature("getPendingRewards(address[],PoolId,address,address)", currencyIds, pool, poolCurrencyId, who)); + assembly { + if eq(success, 0) { + revert(add(returnData, 0x20), returndatasize()) + } + } + + return abi.decode(returnData, (uint256[])); + } +} diff --git a/contracts/incentives/InterfaceIncentives.sol b/contracts/incentives/InterfaceIncentives.sol new file mode 100644 index 0000000..9752718 --- /dev/null +++ b/contracts/incentives/InterfaceIncentives.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.0; + +interface InterfaceIncentives { + event DepositedShare(address indexed sender, address indexed currencyId, uint256 amount); + event WithdrewShare(address indexed sender, address indexed currencyId, uint256 amount); + event ClaimedRewards(address indexed sender, PoolId indexed pool, address indexed poolCurrencyId); + enum PoolId { LOANS, DEX } + + // Gets reward amount in `rewardCurrency` added per period + // Returns (reward_amount) + function getIncentiveRewardAmount(PoolId pool, address poolCurrencyId, address rewardCurrencyId) external view returns (uint256); + + // Fixed reward rate for dex reward pool per period + // Returns (dex_reward_rate) as a FixedU128 representing a decimal + function getDexRewardRate(address currencyId) external view returns (uint256); + + // Stake LP token to add shares to PoolId::Dex + // Returns a boolean value indicating whether the operation succeeded. + function depositDexShare(address currencyId, uint256 amount) external returns (bool); + + // Unstake LP token to remove shares from PoolId::Dex + // Returns a boolean value indicating whether the operation succeeded. + function withdrawDexShare(address currencyId, uint256 amount) external returns (bool); + + // Claim all avalible multi currencies rewards for specific PoolId + // Returns a boolean value indicating whether the operation succeeded. + function claimRewards(PoolId pool, address poolCurrencyId) external returns (bool); + + // Gets deduction rate for claiming reward early + // returns (claim_reward_deduction_rate) as a FixedU128 representing a decimal value + function getClaimRewardDeductionRate(PoolId pool, address poolCurrencyId) external view returns (uint256); + + // Gets the pending rewards for a pool, actual reward could be deducted. + // returns (balances), an array of reward balances corresponding to currencyIds + function getPendingRewards(address[] calldata currencyIds, PoolId pool, address poolCurrencyId, address who) external view returns (uint256[] memory); +} diff --git a/contracts/utils/Address.d.ts b/contracts/utils/Address.d.ts index 075c9eb..6f12c89 100644 --- a/contracts/utils/Address.d.ts +++ b/contracts/utils/Address.d.ts @@ -32,3 +32,4 @@ export const DEX: "0x0000000000000000000000000000000000000803"; export const Homa: "0x0000000000000000000000000000000000000805"; export const EVMAccounts: "0x0000000000000000000000000000000000000806"; export const Honzon: "0x0000000000000000000000000000000000000807"; +export const Incentives: "0x0000000000000000000000000000000000000808"; diff --git a/contracts/utils/Address.js b/contracts/utils/Address.js index ea2b347..b16ccc6 100644 --- a/contracts/utils/Address.js +++ b/contracts/utils/Address.js @@ -32,6 +32,7 @@ const DEX = '0x0000000000000000000000000000000000000803'; const Homa = '0x0000000000000000000000000000000000000805'; const EVMAccounts = '0x0000000000000000000000000000000000000806'; const Honzon = '0x0000000000000000000000000000000000000807'; +const Incentives = '0x0000000000000000000000000000000000000808'; module.exports = { ACA, @@ -68,4 +69,5 @@ module.exports = { Homa, EVMAccounts, Honzon, + Incentives, } diff --git a/contracts/utils/Address.sol b/contracts/utils/Address.sol index 7c4c645..eda38ba 100644 --- a/contracts/utils/Address.sol +++ b/contracts/utils/Address.sol @@ -37,4 +37,5 @@ contract ADDRESS { address public constant Homa = 0x0000000000000000000000000000000000000805; address public constant EVMAccounts = 0x0000000000000000000000000000000000000806; address public constant Honzon = 0x0000000000000000000000000000000000000807; + address public constant Incentives = 0x0000000000000000000000000000000000000808; } diff --git a/generate/generate.js b/generate/generate.js index 015c92d..a16e5ff 100644 --- a/generate/generate.js +++ b/generate/generate.js @@ -58,6 +58,10 @@ const generate = async () => { const { bytecode: honzon } = await hre.artifacts.readArtifact("Honzon"); bytecodes.push(['Honzon', ethers.utils.getAddress('0x0000000000000000000000000000000000000807'), honzon]); + // add Incentives bytecodes + const { bytecode: incentives } = await hre.artifacts.readArtifact("Incentives"); + bytecodes.push(['Incentives', ethers.utils.getAddress('0x0000000000000000000000000000000000000808'), incentives]); + // Maybe each nft will deploy a contract, like the mirrored token. // add NFT bytecodes // const { bytecode: nft } = require(`../build/contracts/NFT.json`); diff --git a/resources/bytecodes.json b/resources/bytecodes.json index 962ef88..5948cb2 100644 --- a/resources/bytecodes.json +++ b/resources/bytecodes.json @@ -168,5 +168,10 @@ "Honzon", "0x0000000000000000000000000000000000000807", "0x608060405234801561001057600080fd5b50610a70806100206000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063b33dc19011610050578063b33dc190146100d3578063c4ba4c3a146100fb578063d018f0911461010e57600080fd5b80631384ed1714610077578063345f5d931461009d57806349895dee146100c0575b600080fd5b61008a610085366004610929565b610121565b6040519081526020015b60405180910390f35b6100b06100ab36600461095b565b610249565b6040519015158152602001610094565b6100b06100ce36600461099d565b610472565b6100e66100e1366004610929565b6105d2565b60408051928352602083019190915201610094565b61008a610109366004610908565b610700565b61008a61011c366004610908565b61081f565b60405173ffffffffffffffffffffffffffffffffffffffff8381166024830152821660448201526000908190819061040990606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f1384ed1700000000000000000000000000000000000000000000000000000000179052516101d79190610a01565b600060405180830381855afa9150503d8060008114610212576040519150601f19603f3d011682016040523d82523d6000602084013e610217565b606091505b5091509150600082141561022c573d60208201fd5b8080602001905181019061024091906109c6565b95945050505050565b600082600f0b600014158015610263575081600f0b600014155b6102f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f486f6e7a6f6e3a2061646a7573746d656e7420616d6f756e747320617265207a60448201527f65726f0000000000000000000000000000000000000000000000000000000000606482015260840160405180910390fd5b60405133602482015273ffffffffffffffffffffffffffffffffffffffff85166044820152600f84810b606483015283900b608482015260009081906104099060a401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fd20a1c8700000000000000000000000000000000000000000000000000000000179052516103b79190610a01565b6000604051808303816000865af19150503d80600081146103f4576040519150601f19603f3d011682016040523d82523d6000602084013e6103f9565b606091505b5091509150600082141561040e573d60208201fd5b60408051600f87810b825286900b602082015273ffffffffffffffffffffffffffffffffffffffff88169133917fe2cff686fc32ba2598b795b502cc29355d96476b81bfec8f2ed19fc0c20b751b910160405180910390a350600195945050505050565b60405133602482015273ffffffffffffffffffffffffffffffffffffffff83166044820152606481018290526000908190819061040990608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fbf0ea731000000000000000000000000000000000000000000000000000000001790525161052d9190610a01565b6000604051808303816000865af19150503d806000811461056a576040519150601f19603f3d011682016040523d82523d6000602084013e61056f565b606091505b50915091506000821415610584573d60208201fd5b60405173ffffffffffffffffffffffffffffffffffffffff86169033907f5da7833102bf6cf960a8286f0c40b87af131ed105e112b28276d4b7933b33bde90600090a3506001949350505050565b60405173ffffffffffffffffffffffffffffffffffffffff83811660248301528216604482015260009081908190819061040990606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb33dc190000000000000000000000000000000000000000000000000000000001790525161068a9190610a01565b600060405180830381855afa9150503d80600081146106c5576040519150601f19603f3d011682016040523d82523d6000602084013e6106ca565b606091505b509150915060008214156106df573d60208201fd5b808060200190518101906106f391906109de565b9350935050509250929050565b60405173ffffffffffffffffffffffffffffffffffffffff821660248201526000908190819061040990604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fc4ba4c3a00000000000000000000000000000000000000000000000000000000179052516107ae9190610a01565b600060405180830381855afa9150503d80600081146107e9576040519150601f19603f3d011682016040523d82523d6000602084013e6107ee565b606091505b50915091506000821415610803573d60208201fd5b8080602001905181019061081791906109c6565b949350505050565b60405173ffffffffffffffffffffffffffffffffffffffff821660248201526000908190819061040990604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fd018f09100000000000000000000000000000000000000000000000000000000179052516107ae9190610a01565b803573ffffffffffffffffffffffffffffffffffffffff811681146108f157600080fd5b919050565b8035600f81900b81146108f157600080fd5b600060208284031215610919578081fd5b610922826108cd565b9392505050565b6000806040838503121561093b578081fd5b610944836108cd565b9150610952602084016108cd565b90509250929050565b60008060006060848603121561096f578081fd5b610978846108cd565b9250610986602085016108f6565b9150610994604085016108f6565b90509250925092565b600080604083850312156109af578182fd5b6109b8836108cd565b946020939093013593505050565b6000602082840312156109d7578081fd5b5051919050565b600080604083850312156109f0578182fd5b505080516020909101519092909150565b60008251815b81811015610a215760208186018101518583015201610a07565b81811115610a2f5782828501525b50919091019291505056fea26469706673582212200e675b5e56b1cd6a5b8db5f97db81930a2c87fc55d36632cbbe374d214792bfc64736f6c63430008040033" + ], + [ + "Incentives", + "0x0000000000000000000000000000000000000808", + "0x608060405234801561001057600080fd5b50610fdd806100206000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80636ccf80da1161005b5780636ccf80da146100de5780636ff45b8b146100f15780637ec9313614610104578063a4a7ade21461011757600080fd5b80630720ad711461008257806310b8087f146100aa5780632b4b3abb146100cb575b600080fd5b610095610090366004610b52565b610137565b60405190151581526020015b60405180910390f35b6100bd6100b8366004610cfa565b61030e565b6040519081526020016100a1565b6100956100d9366004610b52565b610432565b6100bd6100ec366004610d2c565b6105f5565b6100956100ff366004610cfa565b61071c565b6100bd610112366004610b31565b6108ad565b61012a610125366004610b7b565b6109cc565b6040516100a19190610ec7565b6000816101a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f496e63656e74697665733a20616d6f756e74206973207a65726f00000000000060448201526064015b60405180910390fd5b60405133602482015273ffffffffffffffffffffffffffffffffffffffff8416604482015260648101839052600090819061040a90608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fc17ca2a6000000000000000000000000000000000000000000000000000000001790525161025e9190610dc1565b6000604051808303816000865af19150503d806000811461029b576040519150601f19603f3d011682016040523d82523d6000602084013e6102a0565b606091505b509150915060008214156102b5573d60208201fd5b60405184815273ffffffffffffffffffffffffffffffffffffffff86169033907f45f78f5c760c3f28245fbb46e318d554fca9c064767f9a6f852daf0035c21b92906020015b60405180910390a3506001949350505050565b600080600061040a73ffffffffffffffffffffffffffffffffffffffff16858560405160240161033f929190610f0b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa2e2fc8e00000000000000000000000000000000000000000000000000000000179052516103c09190610dc1565b600060405180830381855afa9150503d80600081146103fb576040519150601f19603f3d011682016040523d82523d6000602084013e610400565b606091505b50915091506000821415610415573d60208201fd5b808060200190518101906104299190610d6e565b95945050505050565b60008161049b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f496e63656e74697665733a20616d6f756e74206973207a65726f000000000000604482015260640161019c565b60405133602482015273ffffffffffffffffffffffffffffffffffffffff8416604482015260648101839052600090819061040a90608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fdae3ac6900000000000000000000000000000000000000000000000000000000179052516105549190610dc1565b6000604051808303816000865af19150503d8060008114610591576040519150601f19603f3d011682016040523d82523d6000602084013e610596565b606091505b509150915060008214156105ab573d60208201fd5b60405184815273ffffffffffffffffffffffffffffffffffffffff86169033907fd766e42510e7730861ab6096248fb43982df3017d6119d41482e18cb79a7dadb906020016102fb565b600080600061040a73ffffffffffffffffffffffffffffffffffffffff1686868660405160240161062893929190610f3c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f7469000d00000000000000000000000000000000000000000000000000000000179052516106a99190610dc1565b600060405180830381855afa9150503d80600081146106e4576040519150601f19603f3d011682016040523d82523d6000602084013e6106e9565b606091505b509150915060008214156106fe573d60208201fd5b808060200190518101906107129190610d6e565b9695505050505050565b600080600061040a73ffffffffffffffffffffffffffffffffffffffff1633868660405160240161074f93929190610dfa565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe12eab9b00000000000000000000000000000000000000000000000000000000179052516107d09190610dc1565b6000604051808303816000865af19150503d806000811461080d576040519150601f19603f3d011682016040523d82523d6000602084013e610812565b606091505b50915091506000821415610827573d60208201fd5b8373ffffffffffffffffffffffffffffffffffffffff16856001811115610877577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60405133907fc14c8e20e4488520e8daf6686d64ff040c85a6f6a739393ce599a92351c44b3990600090a4506001949350505050565b60405173ffffffffffffffffffffffffffffffffffffffff821660248201526000908190819061040a90604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f7ec93136000000000000000000000000000000000000000000000000000000001790525161095b9190610dc1565b600060405180830381855afa9150503d8060008114610996576040519150601f19603f3d011682016040523d82523d6000602084013e61099b565b606091505b509150915060008214156109b0573d60208201fd5b808060200190518101906109c49190610d6e565b949350505050565b606060008061040a73ffffffffffffffffffffffffffffffffffffffff168888888888604051602401610a03959493929190610e37565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0eb797b10000000000000000000000000000000000000000000000000000000017905251610a849190610dc1565b600060405180830381855afa9150503d8060008114610abf576040519150601f19603f3d011682016040523d82523d6000602084013e610ac4565b606091505b50915091506000821415610ad9573d60208201fd5b80806020019051810190610aed9190610c1c565b98975050505050505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b1d57600080fd5b919050565b803560028110610b1d57600080fd5b600060208284031215610b42578081fd5b610b4b82610af9565b9392505050565b60008060408385031215610b64578081fd5b610b6d83610af9565b946020939093013593505050565b600080600080600060808688031215610b92578081fd5b853567ffffffffffffffff80821115610ba9578283fd5b818801915088601f830112610bbc578283fd5b813581811115610bca578384fd5b8960208260051b8501011115610bde578384fd5b602092830197509550610bf49188019050610b22565b9250610c0260408701610af9565b9150610c1060608701610af9565b90509295509295909350565b60006020808385031215610c2e578182fd5b825167ffffffffffffffff80821115610c45578384fd5b818501915085601f830112610c58578384fd5b815181811115610c6a57610c6a610f78565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610cad57610cad610f78565b604052828152858101935084860182860187018a1015610ccb578788fd5b8795505b83861015610ced578051855260019590950194938601938601610ccf565b5098975050505050505050565b60008060408385031215610d0c578182fd5b610d1583610b22565b9150610d2360208401610af9565b90509250929050565b600080600060608486031215610d40578283fd5b610d4984610b22565b9250610d5760208501610af9565b9150610d6560408501610af9565b90509250925092565b600060208284031215610d7f578081fd5b5051919050565b60028110610dbd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60008251815b81811015610de15760208186018101518583015201610dc7565b81811115610def5782828501525b509190910192915050565b73ffffffffffffffffffffffffffffffffffffffff84811682526060820190610e266020840186610d86565b808416604084015250949350505050565b6080808252810185905260008660a08301825b88811015610e855773ffffffffffffffffffffffffffffffffffffffff610e7084610af9565b16825260209283019290910190600101610e4a565b509150610e9790506020830186610d86565b73ffffffffffffffffffffffffffffffffffffffff80851660408401528084166060840152509695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015610eff57835183529284019291840191600101610ee3565b50909695505050505050565b60408101610f198285610d86565b73ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b60608101610f4a8286610d86565b73ffffffffffffffffffffffffffffffffffffffff8085166020840152808416604084015250949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea26469706673582212209f1e3b5d8118ce78727547cfd8816a1a091a4701ce401d687a80b326b63acf2464736f6c63430008040033" ] ] \ No newline at end of file