Skip to content

Commit

Permalink
Merge pull request bnb-chain#113 from binance-chain/burn
Browse files Browse the repository at this point in the history
[R4R] implement bep 95
  • Loading branch information
yutianwu authored Oct 25, 2021
2 parents 3b1ed71 + 3152a05 commit ce622fe
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 4 deletions.
29 changes: 29 additions & 0 deletions contracts/BSCValidatorSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
mapping(address =>uint256) public currentValidatorSetMap;
uint256 public numOfJailed;

uint256 public constant BURN_RATIO_SCALE = 10000;
address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;
uint256 public constant INIT_BURN_RATIO = 0;
uint256 public burnRatio;
bool public burnRatioInitialized;

struct Validator{
address consensusAddress;
address payable feeAddress;
Expand Down Expand Up @@ -90,6 +96,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
event failReasonWithStr(string message);
event unexpectedPackage(uint8 channelId, bytes msgBytes);
event paramChange(string key, bytes value);
event feeBurned(uint256 amount);

/*********************** init **************************/
function init() external onlyNotInit{
Expand Down Expand Up @@ -143,6 +150,22 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
function deposit(address valAddr) external payable onlyCoinbase onlyInit noEmptyDeposit{
uint256 value = msg.value;
uint256 index = currentValidatorSetMap[valAddr];

uint256 curBurnRatio = INIT_BURN_RATIO;
if (burnRatioInitialized) {
curBurnRatio = burnRatio;
}

if (value > 0 && curBurnRatio > 0) {
uint256 toBurn = value.mul(curBurnRatio).div(BURN_RATIO_SCALE);
if (toBurn > 0) {
address(uint160(BURN_ADDRESS)).transfer(toBurn);
emit feeBurned(toBurn);

value = value.sub(toBurn);
}
}

if (index>0) {
Validator storage validator = currentValidatorSet[index-1];
if (validator.jailed) {
Expand Down Expand Up @@ -384,6 +407,12 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
uint256 newExpireTimeSecondGap = BytesToTypes.bytesToUint256(32, value);
require(newExpireTimeSecondGap >=100 && newExpireTimeSecondGap <= 1e5, "the expireTimeSecondGap is out of range");
expireTimeSecondGap = newExpireTimeSecondGap;
} else if (Memory.compareStrings(key, "burnRatio")) {
require(value.length == 32, "length of burnRatio mismatch");
uint256 newBurnRatio = BytesToTypes.bytesToUint256(32, value);
require(newBurnRatio <= BURN_RATIO_SCALE, "the burnRatio must be no greater than 10000");
burnRatio = newBurnRatio;
burnRatioInitialized = true;
} else {
require(false, "unknown param");
}
Expand Down
29 changes: 29 additions & 0 deletions contracts/BSCValidatorSet.template
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
mapping(address =>uint256) public currentValidatorSetMap;
uint256 public numOfJailed;

uint256 public constant BURN_RATIO_SCALE = 10000;
address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;
uint256 public constant INIT_BURN_RATIO = {{initBurnRatio}};
uint256 public burnRatio;
bool public burnRatioInitialized;

struct Validator{
address consensusAddress;
address payable feeAddress;
Expand Down Expand Up @@ -90,6 +96,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
event failReasonWithStr(string message);
event unexpectedPackage(uint8 channelId, bytes msgBytes);
event paramChange(string key, bytes value);
event feeBurned(uint256 amount);

/*********************** init **************************/
function init() external onlyNotInit{
Expand Down Expand Up @@ -143,6 +150,22 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
function deposit(address valAddr) external payable onlyCoinbase onlyInit noEmptyDeposit{
uint256 value = msg.value;
uint256 index = currentValidatorSetMap[valAddr];

uint256 curBurnRatio = INIT_BURN_RATIO;
if (burnRatioInitialized) {
curBurnRatio = burnRatio;
}

if (value > 0 && curBurnRatio > 0) {
uint256 toBurn = value.mul(curBurnRatio).div(BURN_RATIO_SCALE);
if (toBurn > 0) {
address(uint160(BURN_ADDRESS)).transfer(toBurn);
emit feeBurned(toBurn);

value = value.sub(toBurn);
}
}

if (index>0) {
Validator storage validator = currentValidatorSet[index-1];
if (validator.jailed) {
Expand Down Expand Up @@ -393,6 +416,12 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica
uint256 newExpireTimeSecondGap = BytesToTypes.bytesToUint256(32, value);
require(newExpireTimeSecondGap >=100 && newExpireTimeSecondGap <= 1e5, "the expireTimeSecondGap is out of range");
expireTimeSecondGap = newExpireTimeSecondGap;
} else if (Memory.compareStrings(key, "burnRatio")) {
require(value.length == 32, "length of burnRatio mismatch");
uint256 newBurnRatio = BytesToTypes.bytesToUint256(32, value);
require(newBurnRatio <= BURN_RATIO_SCALE, "the burnRatio must be no greater than 10000");
burnRatio = newBurnRatio;
burnRatioInitialized = true;
} else {
require(false, "unknown param");
}
Expand Down
7 changes: 7 additions & 0 deletions generate-genesis.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ program.option(
"initValidatorSetBytes",
""
)

program.option(
"--initBurnRatio <initBurnRatio>",
"initBurnRatio",
"0"
)

program.option("--initConsensusStateBytes <initConsensusStateBytes>",
"init consensusState bytes, hex encoding, no prefix with 0x",
"42696e616e63652d436861696e2d4e696c650000000000000000000000000000000000000000000229eca254b3859bffefaf85f4c95da9fbd26527766b784272789c30ec56b380b6eb96442aaab207bc59978ba3dd477690f5c5872334fc39e627723daa97e441e88ba4515150ec3182bc82593df36f8abb25a619187fcfab7e552b94e64ed2deed000000e8d4a51000");
Expand Down
7 changes: 7 additions & 0 deletions generate-validatorset.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ program.option(
""
)

program.option(
"--initBurnRatio <initBurnRatio>",
"initBurnRatio",
"0"
)

program.option("--mock <mock>",
"if use mock",
false);
Expand All @@ -35,6 +41,7 @@ if (initValidatorSetBytes == ""){
}
const data = {
initValidatorSetBytes: initValidatorSetBytes,
initBurnRatio: program.initBurnRatio,
mock: program.mock,
};

Expand Down
2 changes: 1 addition & 1 deletion genesis.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
"lint:sol": "solium -d contracts/",
"flatten": "truffle-flattener contracts/BSCValidatorSet.sol > contracts/flattened/BSCValidatorSet.sol && truffle-flattener contracts/GovHub.sol > contracts/flattened/GovHub.sol && truffle-flattener contracts/RelayerHub.sol > contracts/flattened/RelayerHub.sol && truffle-flattener contracts/RelayerIncentivize.sol > contracts/flattened/RelayerIncentivize.sol && truffle-flattener contracts/SlashIndicator.sol > contracts/flattened/SlashIndicator.sol && truffle-flattener contracts/SystemReward.sol > contracts/flattened/SystemReward.sol && truffle-flattener contracts/TendermintLightClient.sol > contracts/flattened/TendermintLightClient.sol && truffle-flattener contracts/TokenHub.sol > contracts/flattened/TokenHub.sol && truffle-flattener contracts/CrossChain.sol > contracts/flattened/CrossChain.sol && truffle-flattener contracts/TokenManager.sol > contracts/flattened/TokenManager.sol",
"generate-test": "node generate-system.js --mock true && node generate-systemReward.js --mock true && node generate-validatorset.js --mock true && node generate-system.js --mock true && node generate-crosschain.js --mock true && node generate-tokenhub.js --mock true && node generate-tendermintlightclient.js --mock true && node generate-relayerincentivizecontract.js --roundSize 30 --maximumWeight 3 --mock true && node generate-slash.js --mock true",
"generate-mainnet": "node generate-genesis.js --chainid 56 --bscChainId 0038 --initConsensusStateBytes 42696e616e63652d436861696e2d5469677269730000000000000000000000000000000006915167cedaf7bbf7df47d932fdda630527ee648562cf3e52c5e5f46156a3a971a4ceb443c53a50d8653ef8cf1e5716da68120fb51b636dc6d111ec3277b098ecd42d49d3769d8a1f78b4c17a965f7a30d4181fabbd1f969f46d3c8e83b5ad4845421d8000000e8d4a510002ba4e81542f437b7ae1f8a35ddb233c789a8dc22734377d9b6d63af1ca403b61000000e8d4a51000df8da8c5abfdb38595391308bb71e5a1e0aabdc1d0cf38315d50d6be939b2606000000e8d4a51000b6619edca4143484800281d698b70c935e9152ad57b31d85c05f2f79f64b39f3000000e8d4a510009446d14ad86c8d2d74780b0847110001a1c2e252eedfea4753ebbbfce3a22f52000000e8d4a510000353c639f80cc8015944436dab1032245d44f912edc31ef668ff9f4a45cd0599000000e8d4a51000e81d3797e0544c3a718e1f05f0fb782212e248e784c1a851be87e77ae0db230e000000e8d4a510005e3fcda30bd19d45c4b73688da35e7da1fce7c6859b2c1f20ed5202d24144e3e000000e8d4a51000b06a59a2d75bf5d014fce7c999b5e71e7a960870f725847d4ba3235baeaa08ef000000e8d4a510000c910e2fe650e4e01406b3310b489fb60a84bc3ff5c5bee3a56d5898b6a8af32000000e8d4a5100071f2d7b8ec1c8b99a653429b0118cd201f794f409d0fea4d65b1b662f2b00063000000e8d4a51000 --initValidatorSetBytes f905ec80f905e8f846942a7cdd959bfe8d9487b2a43b33565295a698f7e294b6a7edd747c0554875d3fc531d19ba1497992c5e941ff80f3f7f110ffd8920a3ac38fdef318fe94a3f86048c27395000f846946488aa4d1955ee33403f8ccb1d4de5fb97c7ade294220f003d8bdfaadf52aa1e55ae4cc485e6794875941a87e90e440a39c99aa9cb5cea0ad6a3f0b2407b86048c27395000f846949ef9f4360c606c7ab4db26b016007d3ad0ab86a0946103af86a874b705854033438383c82575f25bc29418e2db06cbff3e3c5f856410a1838649e760175786048c27395000f84694ee01c3b1283aa067c58eab4709f85e99d46de5fe94ee4b9bfb1871c64e2bcabb1dc382dc8b7c4218a29415904ab26ab0e99d70b51c220ccdcccabee6e29786048c27395000f84694685b1ded8013785d6623cc18d214320b6bb6475994a20ef4e5e4e7e36258dbf51f4d905114cb1b34bc9413e39085dc88704f4394d35209a02b1a9520320c86048c27395000f8469478f3adfc719c99674c072166708589033e2d9afe9448a30d5eaa7b64492a160f139e2da2800ec3834e94055838358c29edf4dcc1ba1985ad58aedbb6be2b86048c27395000f84694c2be4ec20253b8642161bc3f444f53679c1f3d479466f50c616d737e60d7ca6311ff0d9c434197898a94d1d678a2506eeaa365056fe565df8bc8659f28b086048c27395000f846942f7be8361c80a4c1e7e9aaf001d0877f1cfde218945f93992ac37f3e61db2ef8a587a436a161fd210b94ecbc4fb1a97861344dad0867ca3cba2b860411f086048c27395000f84694ce2fd7544e0b2cc94692d4a704debef7bcb613289444abc67b4b2fba283c582387f54c9cba7c34bafa948acc2ab395ded08bb75ce85bf0f95ad2abc51ad586048c27395000f84694b8f7166496996a7da21cf1f1b04d9b3e26a3d077946770572763289aac606e4f327c2f6cc1aa3b3e3b94882d745ed97d4422ca8da1c22ec49d880c4c097286048c27395000f846942d4c407bbe49438ed859fe965b140dcf1aab71a9943ad0939e120f33518fbba04631afe7a3ed6327b194b2bbb170ca4e499a2b0f3cc85ebfa6e8c4dfcbea86048c27395000f846946bbad7cf34b5fa511d8e963dbba288b1960e75d694853b0f6c324d1f4e76c8266942337ac1b0af1a229442498946a51ca5924552ead6fc2af08b94fcba648601d1a94a2000f846944430b3230294d12c6ab2aac5c2cd68e80b16b581947b107f4976a252a6939b771202c28e64e03f52d694795811a7f214084116949fc4f53cedbf189eeab28601d1a94a2000f84694ea0a6e3c511bbd10f4519ece37dc24887e11b55d946811ca77acfb221a49393c193f3a22db829fcc8e9464feb7c04830dd9ace164fc5c52b3f5a29e5018a8601d1a94a2000f846947ae2f5b9e386cd1b50a4550696d957cb4900f03a94e83bcc5077e6b873995c24bac871b5ad856047e19464e48d4057a90b233e026c1041e6012ada897fe88601d1a94a2000f8469482012708dafc9e1b880fd083b32182b869be8e09948e5adc73a2d233a1b496ed3115464dd6c7b887509428b383d324bc9a37f4e276190796ba5a8947f5ed8601d1a94a2000f8469422b81f8e175ffde54d797fe11eb03f9e3bf75f1d94a1c3ef7ca38d8ba80cce3bfc53ebd2903ed21658942767f7447f7b9b70313d4147b795414aecea54718601d1a94a2000f8469468bf0b8b6fb4e317a0f9d6f03eaf8ce6675bc60d94675cfe570b7902623f47e7f59c9664b5f5065dcf94d84f0d2e50bcf00f2fc476e1c57f5ca2d57f625b8601d1a94a2000f846948c4d90829ce8f72d0163c1d5cf348a862d5506309485c42a7b34309bee2ed6a235f86d16f059deec5894cc2cedc53f0fa6d376336efb67e43d167169f3b78601d1a94a2000f8469435e7a025f4da968de7e4d7e4004197917f4070f194b1182abaeeb3b4d8eba7e6a4162eac7ace23d57394c4fd0d870da52e73de2dd8ded19fe3d26f43a1138601d1a94a2000f84694d6caa02bbebaebb5d7e581e4b66559e635f805ff94c07335cf083c1c46a487f0325769d88e163b653694efaff03b42e41f953a925fc43720e45fb61a19938601d1a94a2000",
"generate-testnet": "node generate-genesis.js --chainid 97 --bscChainId 0061 --initConsensusStateBytes 42696e616e63652d436861696e2d47616e67657300000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000aea1ac326886b992a991d21a6eb155f41b77867cbf659e78f31d89d8205122a84d1be64f0e9a466c2e66a53433928192783e29f8fa21beb2133499b5ef770f60000000e8d4a5100099308aa365c40554bc89982af505d85da95251445d5dd4a9bb37dd2584fd92d3000000e8d4a5100001776920ff0b0f38d78cf95c033c21adf7045785114e392a7544179652e0a612000000e8d4a51000 --initValidatorSetBytes f901a880f901a4f844941284214b9b9c85549ab3d2b972df0deef66ac2c9946ddf42a51534fc98d0c0a3b42c963cace8441ddf946ddf42a51534fc98d0c0a3b42c963cace8441ddf8410000000f84494a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0948081ef03f1d9e0bb4a5bf38f16285c879299f07f948081ef03f1d9e0bb4a5bf38f16285c879299f07f8410000000f8449435552c16704d214347f29fa77f77da6d75d7c75294dc4973e838e3949c77aced16ac2315dc2d7ab11194dc4973e838e3949c77aced16ac2315dc2d7ab1118410000000f84494980a75ecd1309ea12fa2ed87a8744fbfc9b863d594cc6ac05c95a99c1f7b5f88de0e3486c82293b27094cc6ac05c95a99c1f7b5f88de0e3486c82293b2708410000000f84494f474cf03cceff28abc65c9cbae594f725c80e12d94e61a183325a18a173319dd8e19c8d069459e217594e61a183325a18a173319dd8e19c8d069459e21758410000000f84494b71b214cb885500844365e95cd9942c7276e7fd894d22ca3ba2141d23adab65ce4940eb7665ea2b6a794d22ca3ba2141d23adab65ce4940eb7665ea2b6a78410000000"
"generate-mainnet": "node generate-genesis.js --chainid 56 --bscChainId 0038 --initBurnRatio 1000 --initConsensusStateBytes 42696e616e63652d436861696e2d5469677269730000000000000000000000000000000006915167cedaf7bbf7df47d932fdda630527ee648562cf3e52c5e5f46156a3a971a4ceb443c53a50d8653ef8cf1e5716da68120fb51b636dc6d111ec3277b098ecd42d49d3769d8a1f78b4c17a965f7a30d4181fabbd1f969f46d3c8e83b5ad4845421d8000000e8d4a510002ba4e81542f437b7ae1f8a35ddb233c789a8dc22734377d9b6d63af1ca403b61000000e8d4a51000df8da8c5abfdb38595391308bb71e5a1e0aabdc1d0cf38315d50d6be939b2606000000e8d4a51000b6619edca4143484800281d698b70c935e9152ad57b31d85c05f2f79f64b39f3000000e8d4a510009446d14ad86c8d2d74780b0847110001a1c2e252eedfea4753ebbbfce3a22f52000000e8d4a510000353c639f80cc8015944436dab1032245d44f912edc31ef668ff9f4a45cd0599000000e8d4a51000e81d3797e0544c3a718e1f05f0fb782212e248e784c1a851be87e77ae0db230e000000e8d4a510005e3fcda30bd19d45c4b73688da35e7da1fce7c6859b2c1f20ed5202d24144e3e000000e8d4a51000b06a59a2d75bf5d014fce7c999b5e71e7a960870f725847d4ba3235baeaa08ef000000e8d4a510000c910e2fe650e4e01406b3310b489fb60a84bc3ff5c5bee3a56d5898b6a8af32000000e8d4a5100071f2d7b8ec1c8b99a653429b0118cd201f794f409d0fea4d65b1b662f2b00063000000e8d4a51000 --initValidatorSetBytes f905ec80f905e8f846942a7cdd959bfe8d9487b2a43b33565295a698f7e294b6a7edd747c0554875d3fc531d19ba1497992c5e941ff80f3f7f110ffd8920a3ac38fdef318fe94a3f86048c27395000f846946488aa4d1955ee33403f8ccb1d4de5fb97c7ade294220f003d8bdfaadf52aa1e55ae4cc485e6794875941a87e90e440a39c99aa9cb5cea0ad6a3f0b2407b86048c27395000f846949ef9f4360c606c7ab4db26b016007d3ad0ab86a0946103af86a874b705854033438383c82575f25bc29418e2db06cbff3e3c5f856410a1838649e760175786048c27395000f84694ee01c3b1283aa067c58eab4709f85e99d46de5fe94ee4b9bfb1871c64e2bcabb1dc382dc8b7c4218a29415904ab26ab0e99d70b51c220ccdcccabee6e29786048c27395000f84694685b1ded8013785d6623cc18d214320b6bb6475994a20ef4e5e4e7e36258dbf51f4d905114cb1b34bc9413e39085dc88704f4394d35209a02b1a9520320c86048c27395000f8469478f3adfc719c99674c072166708589033e2d9afe9448a30d5eaa7b64492a160f139e2da2800ec3834e94055838358c29edf4dcc1ba1985ad58aedbb6be2b86048c27395000f84694c2be4ec20253b8642161bc3f444f53679c1f3d479466f50c616d737e60d7ca6311ff0d9c434197898a94d1d678a2506eeaa365056fe565df8bc8659f28b086048c27395000f846942f7be8361c80a4c1e7e9aaf001d0877f1cfde218945f93992ac37f3e61db2ef8a587a436a161fd210b94ecbc4fb1a97861344dad0867ca3cba2b860411f086048c27395000f84694ce2fd7544e0b2cc94692d4a704debef7bcb613289444abc67b4b2fba283c582387f54c9cba7c34bafa948acc2ab395ded08bb75ce85bf0f95ad2abc51ad586048c27395000f84694b8f7166496996a7da21cf1f1b04d9b3e26a3d077946770572763289aac606e4f327c2f6cc1aa3b3e3b94882d745ed97d4422ca8da1c22ec49d880c4c097286048c27395000f846942d4c407bbe49438ed859fe965b140dcf1aab71a9943ad0939e120f33518fbba04631afe7a3ed6327b194b2bbb170ca4e499a2b0f3cc85ebfa6e8c4dfcbea86048c27395000f846946bbad7cf34b5fa511d8e963dbba288b1960e75d694853b0f6c324d1f4e76c8266942337ac1b0af1a229442498946a51ca5924552ead6fc2af08b94fcba648601d1a94a2000f846944430b3230294d12c6ab2aac5c2cd68e80b16b581947b107f4976a252a6939b771202c28e64e03f52d694795811a7f214084116949fc4f53cedbf189eeab28601d1a94a2000f84694ea0a6e3c511bbd10f4519ece37dc24887e11b55d946811ca77acfb221a49393c193f3a22db829fcc8e9464feb7c04830dd9ace164fc5c52b3f5a29e5018a8601d1a94a2000f846947ae2f5b9e386cd1b50a4550696d957cb4900f03a94e83bcc5077e6b873995c24bac871b5ad856047e19464e48d4057a90b233e026c1041e6012ada897fe88601d1a94a2000f8469482012708dafc9e1b880fd083b32182b869be8e09948e5adc73a2d233a1b496ed3115464dd6c7b887509428b383d324bc9a37f4e276190796ba5a8947f5ed8601d1a94a2000f8469422b81f8e175ffde54d797fe11eb03f9e3bf75f1d94a1c3ef7ca38d8ba80cce3bfc53ebd2903ed21658942767f7447f7b9b70313d4147b795414aecea54718601d1a94a2000f8469468bf0b8b6fb4e317a0f9d6f03eaf8ce6675bc60d94675cfe570b7902623f47e7f59c9664b5f5065dcf94d84f0d2e50bcf00f2fc476e1c57f5ca2d57f625b8601d1a94a2000f846948c4d90829ce8f72d0163c1d5cf348a862d5506309485c42a7b34309bee2ed6a235f86d16f059deec5894cc2cedc53f0fa6d376336efb67e43d167169f3b78601d1a94a2000f8469435e7a025f4da968de7e4d7e4004197917f4070f194b1182abaeeb3b4d8eba7e6a4162eac7ace23d57394c4fd0d870da52e73de2dd8ded19fe3d26f43a1138601d1a94a2000f84694d6caa02bbebaebb5d7e581e4b66559e635f805ff94c07335cf083c1c46a487f0325769d88e163b653694efaff03b42e41f953a925fc43720e45fb61a19938601d1a94a2000",
"generate-testnet": "node generate-genesis.js --chainid 97 --bscChainId 0061 --initBurnRatio 1000 --initConsensusStateBytes 42696e616e63652d436861696e2d47616e67657300000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000aea1ac326886b992a991d21a6eb155f41b77867cbf659e78f31d89d8205122a84d1be64f0e9a466c2e66a53433928192783e29f8fa21beb2133499b5ef770f60000000e8d4a5100099308aa365c40554bc89982af505d85da95251445d5dd4a9bb37dd2584fd92d3000000e8d4a5100001776920ff0b0f38d78cf95c033c21adf7045785114e392a7544179652e0a612000000e8d4a51000 --initValidatorSetBytes f901a880f901a4f844941284214b9b9c85549ab3d2b972df0deef66ac2c9946ddf42a51534fc98d0c0a3b42c963cace8441ddf946ddf42a51534fc98d0c0a3b42c963cace8441ddf8410000000f84494a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0948081ef03f1d9e0bb4a5bf38f16285c879299f07f948081ef03f1d9e0bb4a5bf38f16285c879299f07f8410000000f8449435552c16704d214347f29fa77f77da6d75d7c75294dc4973e838e3949c77aced16ac2315dc2d7ab11194dc4973e838e3949c77aced16ac2315dc2d7ab1118410000000f84494980a75ecd1309ea12fa2ed87a8744fbfc9b863d594cc6ac05c95a99c1f7b5f88de0e3486c82293b27094cc6ac05c95a99c1f7b5f88de0e3486c82293b2708410000000f84494f474cf03cceff28abc65c9cbae594f725c80e12d94e61a183325a18a173319dd8e19c8d069459e217594e61a183325a18a173319dd8e19c8d069459e21758410000000f84494b71b214cb885500844365e95cd9942c7276e7fd894d22ca3ba2141d23adab65ce4940eb7665ea2b6a794d22ca3ba2141d23adab65ce4940eb7665ea2b6a78410000000"
},
"author": "",
"license": "MIT",
Expand Down
Loading

0 comments on commit ce622fe

Please sign in to comment.