Contract Name:
BSCValidatorSet
Contract Source Code:
File 1 of 1 : BSCValidatorSet
pragma solidity =0.6.4;
pragma experimental ABIEncoderV2;
// contracts/interface/IApplication.sol
interface IApplication {
/**
* @dev Handle syn package
*/
function handleSynPackage(
uint8 channelId,
bytes calldata msgBytes
) external returns (bytes memory responsePayload);
/**
* @dev Handle ack package
*/
function handleAckPackage(uint8 channelId, bytes calldata msgBytes) external;
/**
* @dev Handle fail ack package
*/
function handleFailAckPackage(uint8 channelId, bytes calldata msgBytes) external;
}
// contracts/interface/IBSCValidatorSet.sol
interface IBSCValidatorSet {
function misdemeanor(address validator) external;
function felony(address validator) external;
function isCurrentValidator(address validator) external view returns (bool);
function getLivingValidators() external view returns (address[] memory, bytes[] memory);
function getMiningValidators() external view returns (address[] memory, bytes[] memory);
function isMonitoredForMaliciousVote(bytes calldata voteAddr) external view returns (bool);
}
// contracts/interface/ILightClient.sol
interface ILightClient {
function isHeaderSynced(uint64 height) external view returns (bool);
function getAppHash(uint64 height) external view returns (bytes32);
function getSubmitter(uint64 height) external view returns (address payable);
}
// contracts/interface/IParamSubscriber.sol
interface IParamSubscriber {
function updateParam(string calldata key, bytes calldata value) external;
}
// contracts/interface/IRelayerHub.sol
interface IRelayerHub {
function isRelayer(address sender) external view returns (bool);
}
// contracts/interface/ISlashIndicator.sol
interface ISlashIndicator {
function clean() external;
function downtimeSlash(address validator, uint256 count) external;
function sendFelonyPackage(address validator) external;
function getSlashThresholds() external view returns (uint256, uint256);
}
// contracts/interface/IStakeHub.sol
interface IStakeHub {
function downtimeSlash(address validator) external;
function maliciousVoteSlash(bytes calldata voteAddress) external;
function doubleSignSlash(address validator) external;
function voteToOperator(bytes calldata voteAddress) external view returns (address);
function consensusToOperator(address validator) external view returns (address);
function getValidatorConsensusAddress(address validator) external view returns (address);
function getValidatorCreditContract(address validator) external view returns (address);
function getValidatorVoteAddress(address validator) external view returns (bytes memory);
function maxElectedValidators() external view returns (uint256);
function distributeReward(address validator) external payable;
}
// contracts/interface/ISystemReward.sol
interface ISystemReward {
function claimRewards(address payable to, uint256 amount) external returns (uint256 actualAmount);
}
// contracts/interface/ITokenHub.sol
interface ITokenHub {
function getMiniRelayFee() external view returns (uint256);
function getContractAddrByBEP2Symbol(bytes32 bep2Symbol) external view returns (address);
function getBep2SymbolByContractAddr(address contractAddr) external view returns (bytes32);
function bindToken(bytes32 bep2Symbol, address contractAddr, uint256 decimals) external;
function unbindToken(bytes32 bep2Symbol, address contractAddr) external;
function transferOut(
address contractAddr,
address recipient,
uint256 amount,
uint64 expireTime
) external payable returns (bool);
function recoverBCAsset(bytes32 tokenSymbol, address recipient, uint256 amount) external;
function cancelTokenRecoverLock(bytes32 tokenSymbol, address attacker) external;
/* solium-disable-next-line */
function batchTransferOutBNB(
address[] calldata recipientAddrs,
uint256[] calldata amounts,
address[] calldata refundAddrs,
uint64 expireTime
) external payable returns (bool);
function withdrawStakingBNB(uint256 amount) external returns (bool);
function cancelTransferIn(address tokenAddress, address attacker) external;
}
// contracts/lib/BytesLib.sol
/*
* @title Solidity Bytes Arrays Utils
* @author Gonçalo Sá <[email protected]>
* Copyright (c) 2016-2020 zpouladzade/Seriality
* @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
* The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
*/
library BytesLib {
function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {
bytes memory tempBytes;
assembly {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// Store the length of the first bytes array at the beginning of
// the memory for tempBytes.
let length := mload(_preBytes)
mstore(tempBytes, length)
// Maintain a memory counter for the current write location in the
// temp bytes array by adding the 32 bytes for the array length to
// the starting location.
let mc := add(tempBytes, 0x20)
// Stop copying when the memory counter reaches the length of the
// first bytes array.
let end := add(mc, length)
for {
// Initialize a copy counter to the start of the _preBytes data,
// 32 bytes into its memory.
let cc := add(_preBytes, 0x20)
} lt(mc, end) {
// Increase both counters by 32 bytes each iteration.
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
// Write the _preBytes data into the tempBytes memory 32 bytes
// at a time.
mstore(mc, mload(cc))
}
// Add the length of _postBytes to the current length of tempBytes
// and store it as the new length in the first 32 bytes of the
// tempBytes memory.
length := mload(_postBytes)
mstore(tempBytes, add(length, mload(tempBytes)))
// Move the memory counter back from a multiple of 0x20 to the
// actual end of the _preBytes data.
mc := end
// Stop copying when the memory counter reaches the new combined
// length of the arrays.
end := add(mc, length)
for { let cc := add(_postBytes, 0x20) } lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} { mstore(mc, mload(cc)) }
// Update the free-memory pointer by padding our last write location
// to 32 bytes: add 31 bytes to the end of tempBytes to move to the
// next 32 byte block, then round down to the nearest multiple of
// 32. If the sum of the length of the two arrays is zero then add
// one before rounding down to leave a blank 32 bytes (the length block with 0).
mstore(
0x40,
and(
add(add(end, iszero(add(length, mload(_preBytes)))), 31),
not(31) // Round down to the nearest 32 bytes.
)
)
}
return tempBytes;
}
function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
assembly {
// Read the first 32 bytes of _preBytes storage, which is the length
// of the array. (We don't need to use the offset into the slot
// because arrays use the entire slot.)
let fslot := sload(_preBytes_slot)
// Arrays of 31 bytes or less have an even value in their slot,
// while longer arrays have an odd value. The actual length is
// the slot divided by two for odd values, and the lowest order
// byte divided by two for even values.
// If the slot is even, bitwise and the slot with 255 and divide by
// two to get the length. If the slot is odd, bitwise and the slot
// with -1 and divide by two.
let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
let mlength := mload(_postBytes)
let newlength := add(slength, mlength)
// slength can contain both the length and contents of the array
// if length < 32 bytes so let's prepare for that
// v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
switch add(lt(slength, 32), lt(newlength, 32))
case 2 {
// Since the new array still fits in the slot, we just need to
// update the contents of the slot.
// uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
sstore(
_preBytes_slot,
// all the modifications to the slot are inside this
// next block
add(
// we can just add to the slot contents because the
// bytes we want to change are the LSBs
fslot,
add(
mul(
div(
// load the bytes from memory
mload(add(_postBytes, 0x20)),
// zero all bytes to the right
exp(0x100, sub(32, mlength))
),
// and now shift left the number of bytes to
// leave space for the length in the slot
exp(0x100, sub(32, newlength))
),
// increase length by the double of the memory
// bytes length
mul(mlength, 2)
)
)
)
}
case 1 {
// The stored value fits in the slot, but the combined value
// will exceed it.
// get the keccak hash to get the contents of the array
mstore(0x0, _preBytes_slot)
let sc := add(keccak256(0x0, 0x20), div(slength, 32))
// save new length
sstore(_preBytes_slot, add(mul(newlength, 2), 1))
// The contents of the _postBytes array start 32 bytes into
// the structure. Our first read should obtain the `submod`
// bytes that can fit into the unused space in the last word
// of the stored array. To get this, we read 32 bytes starting
// from `submod`, so the data we read overlaps with the array
// contents by `submod` bytes. Masking the lowest-order
// `submod` bytes allows us to add that value directly to the
// stored value.
let submod := sub(32, slength)
let mc := add(_postBytes, submod)
let end := add(_postBytes, mlength)
let mask := sub(exp(0x100, submod), 1)
sstore(
sc,
add(
and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00),
and(mload(mc), mask)
)
)
for {
mc := add(mc, 0x20)
sc := add(sc, 1)
} lt(mc, end) {
sc := add(sc, 1)
mc := add(mc, 0x20)
} { sstore(sc, mload(mc)) }
mask := exp(0x100, sub(mc, end))
sstore(sc, mul(div(mload(mc), mask), mask))
}
default {
// get the keccak hash to get the contents of the array
mstore(0x0, _preBytes_slot)
// Start copying to the last used word of the stored array.
let sc := add(keccak256(0x0, 0x20), div(slength, 32))
// save new length
sstore(_preBytes_slot, add(mul(newlength, 2), 1))
// Copy over the first `submod` bytes of the new data as in
// case 1 above.
let slengthmod := mod(slength, 32)
let mlengthmod := mod(mlength, 32)
let submod := sub(32, slengthmod)
let mc := add(_postBytes, submod)
let end := add(_postBytes, mlength)
let mask := sub(exp(0x100, submod), 1)
sstore(sc, add(sload(sc), and(mload(mc), mask)))
for {
sc := add(sc, 1)
mc := add(mc, 0x20)
} lt(mc, end) {
sc := add(sc, 1)
mc := add(mc, 0x20)
} { sstore(sc, mload(mc)) }
mask := exp(0x100, sub(mc, end))
sstore(sc, mul(div(mload(mc), mask), mask))
}
}
}
function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
require(_bytes.length >= (_start + _length));
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// The first word of the slice result is potentially a partial
// word read from the original array. To read it, we calculate
// the length of that partial word and start copying that many
// bytes into the array. The first word we copy will start with
// data we don't care about, but the last `lengthmod` bytes will
// land at the beginning of the contents of the new array. When
// we're done copying, we overwrite the full first word with
// the actual length of the slice.
let lengthmod := and(_length, 31)
// The multiplication in the next line is necessary
// because when slicing multiples of 32 bytes (lengthmod == 0)
// the following copy loop was copying the origin's length
// and then ending prematurely not copying everything it should.
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
// The multiplication in the next line has the same exact purpose
// as the one above.
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} { mstore(mc, mload(cc)) }
mstore(tempBytes, _length)
//update free-memory pointer
//allocating the array padded to 32 bytes like the compiler does now
mstore(0x40, and(add(mc, 31), not(31)))
}
//if we want a zero-length slice let's just return a zero-length array
default {
tempBytes := mload(0x40)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_bytes.length >= (_start + 20));
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
require(_bytes.length >= (_start + 1));
uint8 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x1), _start))
}
return tempUint;
}
function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
require(_bytes.length >= (_start + 2));
uint16 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x2), _start))
}
return tempUint;
}
function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
require(_bytes.length >= (_start + 4));
uint32 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x4), _start))
}
return tempUint;
}
function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
require(_bytes.length >= (_start + 8));
uint64 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x8), _start))
}
return tempUint;
}
function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
require(_bytes.length >= (_start + 12));
uint96 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0xc), _start))
}
return tempUint;
}
function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
require(_bytes.length >= (_start + 16));
uint128 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x10), _start))
}
return tempUint;
}
function toUint(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
require(_bytes.length >= (_start + 32));
uint256 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x20), _start))
}
return tempUint;
}
function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
require(_bytes.length >= (_start + 32));
bytes32 tempBytes32;
assembly {
tempBytes32 := mload(add(add(_bytes, 0x20), _start))
}
return tempBytes32;
}
function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
bool success = true;
assembly {
let length := mload(_preBytes)
// if lengths don't match the arrays are not equal
switch eq(length, mload(_postBytes))
case 1 {
// cb is a circuit breaker in the for loop since there's
// no said feature for inline assembly loops
// cb = 1 - don't breaker
// cb = 0 - break
let cb := 1
let mc := add(_preBytes, 0x20)
let end := add(mc, length)
for { let cc := add(_postBytes, 0x20) }
// the next line is the loop condition:
// while (uint(mc < end) + cb == 2)
eq(add(lt(mc, end), cb), 2) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
// if any of these checks fails then arrays are not equal
if iszero(eq(mload(mc), mload(cc))) {
// unsuccess:
success := 0
cb := 0
}
}
}
default {
// unsuccess:
success := 0
}
}
return success;
}
function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {
bool success = true;
assembly {
// we know _preBytes_offset is 0
let fslot := sload(_preBytes_slot)
// Decode the length of the stored array like in concatStorage().
let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
let mlength := mload(_postBytes)
// if lengths don't match the arrays are not equal
switch eq(slength, mlength)
case 1 {
// slength can contain both the length and contents of the array
// if length < 32 bytes so let's prepare for that
// v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
if iszero(iszero(slength)) {
switch lt(slength, 32)
case 1 {
// blank the last byte which is the length
fslot := mul(div(fslot, 0x100), 0x100)
if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
// unsuccess:
success := 0
}
}
default {
// cb is a circuit breaker in the for loop since there's
// no said feature for inline assembly loops
// cb = 1 - don't breaker
// cb = 0 - break
let cb := 1
// get the keccak hash to get the contents of the array
mstore(0x0, _preBytes_slot)
let sc := keccak256(0x0, 0x20)
let mc := add(_postBytes, 0x20)
let end := add(mc, mlength)
// the next line is the loop condition:
// while (uint(mc < end) + cb == 2)
for { } eq(add(lt(mc, end), cb), 2) {
sc := add(sc, 1)
mc := add(mc, 0x20)
} {
if iszero(eq(sload(sc), mload(mc))) {
// unsuccess:
success := 0
cb := 0
}
}
}
}
}
default {
// unsuccess:
success := 0
}
}
return success;
}
}
// contracts/lib/BytesToTypes.sol
/**
* @title BytesToTypes
* Copyright (c) 2016-2020 zpouladzade/Seriality
* @dev The BytesToTypes contract converts the memory byte arrays to the standard solidity types
* @author [email protected]
*/
library BytesToTypes {
function bytesToAddress(uint256 _offst, bytes memory _input) internal pure returns (address _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToBool(uint256 _offst, bytes memory _input) internal pure returns (bool _output) {
uint8 x;
assembly {
x := mload(add(_input, _offst))
}
x == 0 ? _output = false : _output = true;
}
function getStringSize(uint256 _offst, bytes memory _input) internal pure returns (uint256 size) {
assembly {
size := mload(add(_input, _offst))
let chunk_count := add(div(size, 32), 1) // chunk_count = size/32 + 1
if gt(mod(size, 32), 0) {
// if size%32 > 0
chunk_count := add(chunk_count, 1)
}
size := mul(chunk_count, 32) // first 32 bytes reseves for size in strings
}
}
function bytesToString(uint256 _offst, bytes memory _input, bytes memory _output) internal pure {
uint256 size = 32;
assembly {
let chunk_count
size := mload(add(_input, _offst))
chunk_count := add(div(size, 32), 1) // chunk_count = size/32 + 1
if gt(mod(size, 32), 0) { chunk_count := add(chunk_count, 1) } // chunk_count++
for { let index := 0 } lt(index, chunk_count) { index := add(index, 1) } {
mstore(add(_output, mul(index, 32)), mload(add(_input, _offst)))
_offst := sub(_offst, 32) // _offst -= 32
}
}
}
function bytesToBytes32(uint256 _offst, bytes memory _input, bytes32 _output) internal pure {
assembly {
mstore(_output, add(_input, _offst))
mstore(add(_output, 32), add(add(_input, _offst), 32))
}
}
function bytesToInt8(uint256 _offst, bytes memory _input) internal pure returns (int8 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt16(uint256 _offst, bytes memory _input) internal pure returns (int16 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt24(uint256 _offst, bytes memory _input) internal pure returns (int24 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt32(uint256 _offst, bytes memory _input) internal pure returns (int32 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt40(uint256 _offst, bytes memory _input) internal pure returns (int40 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt48(uint256 _offst, bytes memory _input) internal pure returns (int48 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt56(uint256 _offst, bytes memory _input) internal pure returns (int56 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt64(uint256 _offst, bytes memory _input) internal pure returns (int64 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt72(uint256 _offst, bytes memory _input) internal pure returns (int72 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt80(uint256 _offst, bytes memory _input) internal pure returns (int80 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt88(uint256 _offst, bytes memory _input) internal pure returns (int88 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt96(uint256 _offst, bytes memory _input) internal pure returns (int96 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt104(uint256 _offst, bytes memory _input) internal pure returns (int104 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt112(uint256 _offst, bytes memory _input) internal pure returns (int112 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt120(uint256 _offst, bytes memory _input) internal pure returns (int120 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt128(uint256 _offst, bytes memory _input) internal pure returns (int128 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt136(uint256 _offst, bytes memory _input) internal pure returns (int136 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt144(uint256 _offst, bytes memory _input) internal pure returns (int144 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt152(uint256 _offst, bytes memory _input) internal pure returns (int152 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt160(uint256 _offst, bytes memory _input) internal pure returns (int160 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt168(uint256 _offst, bytes memory _input) internal pure returns (int168 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt176(uint256 _offst, bytes memory _input) internal pure returns (int176 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt184(uint256 _offst, bytes memory _input) internal pure returns (int184 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt192(uint256 _offst, bytes memory _input) internal pure returns (int192 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt200(uint256 _offst, bytes memory _input) internal pure returns (int200 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt208(uint256 _offst, bytes memory _input) internal pure returns (int208 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt216(uint256 _offst, bytes memory _input) internal pure returns (int216 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt224(uint256 _offst, bytes memory _input) internal pure returns (int224 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt232(uint256 _offst, bytes memory _input) internal pure returns (int232 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt240(uint256 _offst, bytes memory _input) internal pure returns (int240 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt248(uint256 _offst, bytes memory _input) internal pure returns (int248 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToInt256(uint256 _offst, bytes memory _input) internal pure returns (int256 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint8(uint256 _offst, bytes memory _input) internal pure returns (uint8 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint16(uint256 _offst, bytes memory _input) internal pure returns (uint16 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint24(uint256 _offst, bytes memory _input) internal pure returns (uint24 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint32(uint256 _offst, bytes memory _input) internal pure returns (uint32 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint40(uint256 _offst, bytes memory _input) internal pure returns (uint40 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint48(uint256 _offst, bytes memory _input) internal pure returns (uint48 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint56(uint256 _offst, bytes memory _input) internal pure returns (uint56 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint64(uint256 _offst, bytes memory _input) internal pure returns (uint64 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint72(uint256 _offst, bytes memory _input) internal pure returns (uint72 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint80(uint256 _offst, bytes memory _input) internal pure returns (uint80 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint88(uint256 _offst, bytes memory _input) internal pure returns (uint88 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint96(uint256 _offst, bytes memory _input) internal pure returns (uint96 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint104(uint256 _offst, bytes memory _input) internal pure returns (uint104 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint112(uint256 _offst, bytes memory _input) internal pure returns (uint112 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint120(uint256 _offst, bytes memory _input) internal pure returns (uint120 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint128(uint256 _offst, bytes memory _input) internal pure returns (uint128 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint136(uint256 _offst, bytes memory _input) internal pure returns (uint136 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint144(uint256 _offst, bytes memory _input) internal pure returns (uint144 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint152(uint256 _offst, bytes memory _input) internal pure returns (uint152 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint160(uint256 _offst, bytes memory _input) internal pure returns (uint160 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint168(uint256 _offst, bytes memory _input) internal pure returns (uint168 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint176(uint256 _offst, bytes memory _input) internal pure returns (uint176 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint184(uint256 _offst, bytes memory _input) internal pure returns (uint184 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint192(uint256 _offst, bytes memory _input) internal pure returns (uint192 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint200(uint256 _offst, bytes memory _input) internal pure returns (uint200 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint208(uint256 _offst, bytes memory _input) internal pure returns (uint208 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint216(uint256 _offst, bytes memory _input) internal pure returns (uint216 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint224(uint256 _offst, bytes memory _input) internal pure returns (uint224 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint232(uint256 _offst, bytes memory _input) internal pure returns (uint232 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint240(uint256 _offst, bytes memory _input) internal pure returns (uint240 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint248(uint256 _offst, bytes memory _input) internal pure returns (uint248 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
function bytesToUint256(uint256 _offst, bytes memory _input) internal pure returns (uint256 _output) {
assembly {
_output := mload(add(_input, _offst))
}
}
}
// contracts/lib/Memory.sol
library Memory {
// Size of a word, in bytes.
uint256 internal constant WORD_SIZE = 32;
// Size of the header of a 'bytes' array.
uint256 internal constant BYTES_HEADER_SIZE = 32;
// Address of the free memory pointer.
uint256 internal constant FREE_MEM_PTR = 0x40;
// Compares the 'len' bytes starting at address 'addr' in memory with the 'len'
// bytes starting at 'addr2'.
// Returns 'true' if the bytes are the same, otherwise 'false'.
function equals(uint256 addr, uint256 addr2, uint256 len) internal pure returns (bool equal) {
assembly {
equal := eq(keccak256(addr, len), keccak256(addr2, len))
}
}
// Compares the 'len' bytes starting at address 'addr' in memory with the bytes stored in
// 'bts'. It is allowed to set 'len' to a lower value then 'bts.length', in which case only
// the first 'len' bytes will be compared.
// Requires that 'bts.length >= len'
function equals(uint256 addr, uint256 len, bytes memory bts) internal pure returns (bool equal) {
require(bts.length >= len);
uint256 addr2;
assembly {
addr2 := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
return equals(addr, addr2, len);
}
function compareStrings(string memory a, string memory b) internal pure returns (bool) {
return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))));
}
// Copy 'len' bytes from memory address 'src', to address 'dest'.
// This function does not check the or destination, it only copies
// the bytes.
function copy(uint256 src, uint256 dest, uint256 len) internal pure {
// Copy word-length chunks while possible
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
assembly {
mstore(dest, mload(src))
}
dest += WORD_SIZE;
src += WORD_SIZE;
}
// Copy remaining bytes
uint256 mask = 256 ** (WORD_SIZE - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
// Returns a memory pointer to the provided bytes array.
function ptr(bytes memory bts) internal pure returns (uint256 addr) {
assembly {
addr := bts
}
}
// Returns a memory pointer to the data portion of the provided bytes array.
function dataPtr(bytes memory bts) internal pure returns (uint256 addr) {
assembly {
addr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
}
// This function does the same as 'dataPtr(bytes memory)', but will also return the
// length of the provided bytes array.
function fromBytes(bytes memory bts) internal pure returns (uint256 addr, uint256 len) {
len = bts.length;
assembly {
addr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
}
// Creates a 'bytes memory' variable from the memory address 'addr', with the
// length 'len'. The function will allocate new memory for the bytes array, and
// the 'len bytes starting at 'addr' will be copied into that new memory.
function toBytes(uint256 addr, uint256 len) internal pure returns (bytes memory bts) {
bts = new bytes(len);
uint256 btsptr;
assembly {
btsptr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
copy(addr, btsptr, len);
}
// Get the word stored at memory address 'addr' as a 'uint'.
function toUint(uint256 addr) internal pure returns (uint256 n) {
assembly {
n := mload(addr)
}
}
// Get the word stored at memory address 'addr' as a 'bytes32'.
function toBytes32(uint256 addr) internal pure returns (bytes32 bts) {
assembly {
bts := mload(addr)
}
}
}
// contracts/lib/RLPDecode.sol
library RLPDecode {
uint8 constant STRING_SHORT_START = 0x80;
uint8 constant STRING_LONG_START = 0xb8;
uint8 constant LIST_SHORT_START = 0xc0;
uint8 constant LIST_LONG_START = 0xf8;
uint8 constant WORD_SIZE = 32;
struct RLPItem {
uint256 len;
uint256 memPtr;
}
struct Iterator {
RLPItem item; // Item that's being iterated over.
uint256 nextPtr; // Position of the next item in the list.
}
function next(Iterator memory self) internal pure returns (RLPItem memory) {
require(hasNext(self));
uint256 ptr = self.nextPtr;
uint256 itemLength = _itemLength(ptr);
self.nextPtr = ptr + itemLength;
return RLPItem(itemLength, ptr);
}
function hasNext(Iterator memory self) internal pure returns (bool) {
RLPItem memory item = self.item;
return self.nextPtr < item.memPtr + item.len;
}
function toRLPItem(bytes memory self) internal pure returns (RLPItem memory) {
uint256 memPtr;
assembly {
memPtr := add(self, 0x20)
}
return RLPItem(self.length, memPtr);
}
function iterator(RLPItem memory self) internal pure returns (Iterator memory) {
require(isList(self));
uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);
return Iterator(self, ptr);
}
function rlpLen(RLPItem memory item) internal pure returns (uint256) {
return item.len;
}
function payloadLen(RLPItem memory item) internal pure returns (uint256) {
return item.len - _payloadOffset(item.memPtr);
}
function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
require(isList(item));
uint256 items = numItems(item);
RLPItem[] memory result = new RLPItem[](items);
uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);
uint256 dataLen;
for (uint256 i = 0; i < items; ++i) {
dataLen = _itemLength(memPtr);
result[i] = RLPItem(dataLen, memPtr);
memPtr = memPtr + dataLen;
}
return result;
}
function isList(RLPItem memory item) internal pure returns (bool) {
if (item.len == 0) return false;
uint8 byte0;
uint256 memPtr = item.memPtr;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < LIST_SHORT_START) {
return false;
}
return true;
}
function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {
bytes memory result = new bytes(item.len);
if (result.length == 0) return result;
uint256 ptr;
assembly {
ptr := add(0x20, result)
}
copy(item.memPtr, ptr, item.len);
return result;
}
function toBoolean(RLPItem memory item) internal pure returns (bool) {
require(item.len == 1);
uint256 result;
uint256 memPtr = item.memPtr;
assembly {
result := byte(0, mload(memPtr))
}
if (result == 0 || result == STRING_SHORT_START) {
return false;
} else {
return true;
}
}
function toAddress(RLPItem memory item) internal pure returns (address) {
// 1 byte for the length prefix
require(item.len == 21);
return address(toUint(item));
}
function toUint(RLPItem memory item) internal pure returns (uint256) {
require(item.len > 0 && item.len <= 33);
uint256 offset = _payloadOffset(item.memPtr);
require(item.len >= offset, "length is less than offset");
uint256 len = item.len - offset;
uint256 result;
uint256 memPtr = item.memPtr + offset;
assembly {
result := mload(memPtr)
// shfit to the correct location if neccesary
if lt(len, 32) { result := div(result, exp(256, sub(32, len))) }
}
return result;
}
// enforces 32 byte length
function toUintStrict(RLPItem memory item) internal pure returns (uint256) {
// one byte prefix
require(item.len == 33);
uint256 result;
uint256 memPtr = item.memPtr + 1;
assembly {
result := mload(memPtr)
}
return result;
}
function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
require(item.len > 0);
uint256 offset = _payloadOffset(item.memPtr);
uint256 len = item.len - offset; // data length
bytes memory result = new bytes(len);
uint256 destPtr;
assembly {
destPtr := add(0x20, result)
}
copy(item.memPtr + offset, destPtr, len);
return result;
}
function numItems(RLPItem memory item) private pure returns (uint256) {
if (item.len == 0) return 0;
uint256 count = 0;
uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);
uint256 endPtr = item.memPtr + item.len;
while (currPtr < endPtr) {
currPtr = currPtr + _itemLength(currPtr); // skip over an item
++count;
}
return count;
}
function _itemLength(uint256 memPtr) private pure returns (uint256) {
uint256 itemLen;
uint256 byte0;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < STRING_SHORT_START) {
itemLen = 1;
} else if (byte0 < STRING_LONG_START) {
itemLen = byte0 - STRING_SHORT_START + 1;
} else if (byte0 < LIST_SHORT_START) {
uint256 dataLen;
assembly {
let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
memPtr := add(memPtr, 1) // skip over the first byte
/* 32 byte word size */
dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
itemLen := add(dataLen, add(byteLen, 1))
}
require(itemLen >= dataLen, "addition overflow");
} else if (byte0 < LIST_LONG_START) {
itemLen = byte0 - LIST_SHORT_START + 1;
} else {
uint256 dataLen;
assembly {
let byteLen := sub(byte0, 0xf7)
memPtr := add(memPtr, 1)
dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
itemLen := add(dataLen, add(byteLen, 1))
}
require(itemLen >= dataLen, "addition overflow");
}
return itemLen;
}
// @return number of bytes until the data
function _payloadOffset(uint256 memPtr) private pure returns (uint256) {
uint256 byte0;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < STRING_SHORT_START) {
return 0;
} else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {
return 1;
} else if (
byte0 < LIST_SHORT_START // being explicit
) {
return byte0 - (STRING_LONG_START - 1) + 1;
} else {
return byte0 - (LIST_LONG_START - 1) + 1;
}
}
/*
* @param src Pointer to source
* @param dest Pointer to destination
* @param len Amount of memory to copy from the source
*/
function copy(uint256 src, uint256 dest, uint256 len) private pure {
if (len == 0) return;
// copy as many word sizes as possible
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
assembly {
mstore(dest, mload(src))
}
src += WORD_SIZE;
dest += WORD_SIZE;
}
// left over bytes. Mask is used to remove unwanted bytes from the word
uint256 mask = 256 ** (WORD_SIZE - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask)) // zero out src
let destpart := and(mload(dest), mask) // retrieve the bytes
mstore(dest, or(destpart, srcpart))
}
}
}
// contracts/lib/RLPEncode.sol
library RLPEncode {
uint8 constant STRING_OFFSET = 0x80;
uint8 constant LIST_OFFSET = 0xc0;
/**
* @notice Encode string item
* @param self The string (ie. byte array) item to encode
* @return The RLP encoded string in bytes
*/
function encodeBytes(bytes memory self) internal pure returns (bytes memory) {
if (self.length == 1 && self[0] <= 0x7f) {
return self;
}
return mergeBytes(encodeLength(self.length, STRING_OFFSET), self);
}
/**
* @notice Encode address
* @param self The address to encode
* @return The RLP encoded address in bytes
*/
function encodeAddress(address self) internal pure returns (bytes memory) {
bytes memory b;
assembly {
let m := mload(0x40)
mstore(add(m, 20), xor(0x140000000000000000000000000000000000000000, self))
mstore(0x40, add(m, 52))
b := m
}
return encodeBytes(b);
}
/**
* @notice Encode uint
* @param self The uint to encode
* @return The RLP encoded uint in bytes
*/
function encodeUint(uint256 self) internal pure returns (bytes memory) {
return encodeBytes(toBinary(self));
}
/**
* @notice Encode int
* @param self The int to encode
* @return The RLP encoded int in bytes
*/
function encodeInt(int256 self) internal pure returns (bytes memory) {
return encodeUint(uint256(self));
}
/**
* @notice Encode bool
* @param self The bool to encode
* @return The RLP encoded bool in bytes
*/
function encodeBool(bool self) internal pure returns (bytes memory) {
bytes memory rs = new bytes(1);
rs[0] = (self ? bytes1(0x01) : bytes1(0x80));
return rs;
}
/**
* @notice Encode list of items
* @param self The list of items to encode, each item in list must be already encoded
* @return The RLP encoded list of items in bytes
*/
function encodeList(bytes[] memory self) internal pure returns (bytes memory) {
if (self.length == 0) {
return new bytes(0);
}
bytes memory payload = self[0];
for (uint256 i = 1; i < self.length; ++i) {
payload = mergeBytes(payload, self[i]);
}
return mergeBytes(encodeLength(payload.length, LIST_OFFSET), payload);
}
/**
* @notice Concat two bytes arrays
* @param _preBytes The first bytes array
* @param _postBytes The second bytes array
* @return The merged bytes array
*/
function mergeBytes(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {
bytes memory tempBytes;
assembly {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// Store the length of the first bytes array at the beginning of
// the memory for tempBytes.
let length := mload(_preBytes)
mstore(tempBytes, length)
// Maintain a memory counter for the current write location in the
// temp bytes array by adding the 32 bytes for the array length to
// the starting location.
let mc := add(tempBytes, 0x20)
// Stop copying when the memory counter reaches the length of the
// first bytes array.
let end := add(mc, length)
for {
// Initialize a copy counter to the start of the _preBytes data,
// 32 bytes into its memory.
let cc := add(_preBytes, 0x20)
} lt(mc, end) {
// Increase both counters by 32 bytes each iteration.
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
// Write the _preBytes data into the tempBytes memory 32 bytes
// at a time.
mstore(mc, mload(cc))
}
// Add the length of _postBytes to the current length of tempBytes
// and store it as the new length in the first 32 bytes of the
// tempBytes memory.
length := mload(_postBytes)
mstore(tempBytes, add(length, mload(tempBytes)))
// Move the memory counter back from a multiple of 0x20 to the
// actual end of the _preBytes data.
mc := end
// Stop copying when the memory counter reaches the new combined
// length of the arrays.
end := add(mc, length)
for { let cc := add(_postBytes, 0x20) } lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} { mstore(mc, mload(cc)) }
// Update the free-memory pointer by padding our last write location
// to 32 bytes: add 31 bytes to the end of tempBytes to move to the
// next 32 byte block, then round down to the nearest multiple of
// 32. If the sum of the length of the two arrays is zero then add
// one before rounding down to leave a blank 32 bytes (the length block with 0).
mstore(
0x40,
and(
add(add(end, iszero(add(length, mload(_preBytes)))), 31),
not(31) // Round down to the nearest 32 bytes.
)
)
}
return tempBytes;
}
/**
* @notice Encode the first byte, followed by the `length` in binary form if `length` is more than 55.
* @param length The length of the string or the payload
* @param offset `STRING_OFFSET` if item is string, `LIST_OFFSET` if item is list
* @return RLP encoded bytes
*/
function encodeLength(uint256 length, uint256 offset) internal pure returns (bytes memory) {
require(length < 256 ** 8, "input too long");
bytes memory rs = new bytes(1);
if (length <= 55) {
rs[0] = bytes1(uint8(length + offset));
return rs;
}
bytes memory bl = toBinary(length);
rs[0] = bytes1(uint8(bl.length + offset + 55));
return mergeBytes(rs, bl);
}
/**
* @notice Encode integer in big endian binary form with no leading zeroes
* @param x The integer to encode
* @return RLP encoded bytes
*/
function toBinary(uint256 x) internal pure returns (bytes memory) {
bytes memory b = new bytes(32);
assembly {
mstore(add(b, 32), x)
}
uint256 i;
if (x & 0xffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000 == 0) {
i = 24;
} else if (x & 0xffffffffffffffffffffffffffffffff00000000000000000000000000000000 == 0) {
i = 16;
} else {
i = 0;
}
for (; i < 32; ++i) {
if (b[i] != 0) {
break;
}
}
uint256 length = 32 - i;
bytes memory rs = new bytes(length);
assembly {
mstore(add(rs, length), x)
mstore(rs, length)
}
return rs;
}
}
// contracts/lib/SafeMath.sol
/**
* Copyright (c) 2016-2019 zOS Global Limited
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
// contracts/lib/CmnPkg.sol
library CmnPkg {
using RLPEncode for *;
using RLPDecode for *;
struct CommonAckPackage {
uint32 code;
}
function encodeCommonAckPackage(uint32 code) internal pure returns (bytes memory) {
bytes[] memory elements = new bytes[](1);
elements[0] = uint256(code).encodeUint();
return elements.encodeList();
}
function decodeCommonAckPackage(bytes memory msgBytes) internal pure returns (CommonAckPackage memory, bool) {
CommonAckPackage memory ackPkg;
RLPDecode.Iterator memory iter = msgBytes.toRLPItem().iterator();
bool success = false;
uint256 idx = 0;
while (iter.hasNext()) {
if (idx == 0) {
ackPkg.code = uint32(iter.next().toUint());
success = true;
} else {
break;
}
++idx;
}
return (ackPkg, success);
}
}
// contracts/System.sol
contract System {
bool public alreadyInit;
uint32 public constant CODE_OK = 0;
uint32 public constant ERROR_FAIL_DECODE = 100;
uint8 public constant BIND_CHANNELID = 0x01;
uint8 public constant TRANSFER_IN_CHANNELID = 0x02;
uint8 public constant TRANSFER_OUT_CHANNELID = 0x03;
uint8 public constant STAKING_CHANNELID = 0x08;
uint8 public constant GOV_CHANNELID = 0x09;
uint8 public constant SLASH_CHANNELID = 0x0b;
uint8 public constant CROSS_STAKE_CHANNELID = 0x10;
uint8 public constant BC_FUSION_CHANNELID = 0x11; // new channel id for cross-chain redelegate from Beacon Chain to Smart Chain after Feynman upgrade
uint16 public constant bscChainID = 0x0038;
address public constant VALIDATOR_CONTRACT_ADDR = 0x0000000000000000000000000000000000001000;
address public constant SLASH_CONTRACT_ADDR = 0x0000000000000000000000000000000000001001;
address public constant SYSTEM_REWARD_ADDR = 0x0000000000000000000000000000000000001002;
address public constant LIGHT_CLIENT_ADDR = 0x0000000000000000000000000000000000001003;
address public constant TOKEN_HUB_ADDR = 0x0000000000000000000000000000000000001004;
address public constant INCENTIVIZE_ADDR = 0x0000000000000000000000000000000000001005;
address public constant RELAYERHUB_CONTRACT_ADDR = 0x0000000000000000000000000000000000001006;
address public constant GOV_HUB_ADDR = 0x0000000000000000000000000000000000001007;
address public constant TOKEN_MANAGER_ADDR = 0x0000000000000000000000000000000000001008;
address public constant CROSS_CHAIN_CONTRACT_ADDR = 0x0000000000000000000000000000000000002000;
address public constant STAKING_CONTRACT_ADDR = 0x0000000000000000000000000000000000002001;
address public constant STAKE_HUB_ADDR = 0x0000000000000000000000000000000000002002;
address public constant STAKE_CREDIT_ADDR = 0x0000000000000000000000000000000000002003;
address public constant GOVERNOR_ADDR = 0x0000000000000000000000000000000000002004;
address public constant GOV_TOKEN_ADDR = 0x0000000000000000000000000000000000002005;
address public constant TIMELOCK_ADDR = 0x0000000000000000000000000000000000002006;
address public constant TOKEN_RECOVER_PORTAL_ADDR = 0x0000000000000000000000000000000000003000;
modifier onlyCoinbase() {
require(msg.sender == block.coinbase, "the message sender must be the block producer");
_;
}
modifier onlyZeroGasPrice() {
require(tx.gasprice == 0, "gasprice is not zero");
_;
}
modifier onlyNotInit() {
require(!alreadyInit, "the contract already init");
_;
}
modifier onlyInit() {
require(alreadyInit, "the contract not init yet");
_;
}
modifier onlySlash() {
require(msg.sender == SLASH_CONTRACT_ADDR, "the message sender must be slash contract");
_;
}
modifier onlyTokenHub() {
require(msg.sender == TOKEN_HUB_ADDR, "the message sender must be token hub contract");
_;
}
modifier onlyGov() {
require(msg.sender == GOV_HUB_ADDR, "the message sender must be governance contract");
_;
}
modifier onlyValidatorContract() {
require(msg.sender == VALIDATOR_CONTRACT_ADDR, "the message sender must be validatorSet contract");
_;
}
modifier onlyCrossChainContract() {
require(msg.sender == CROSS_CHAIN_CONTRACT_ADDR, "the message sender must be cross chain contract");
_;
}
modifier onlyRelayerIncentivize() {
require(msg.sender == INCENTIVIZE_ADDR, "the message sender must be incentivize contract");
_;
}
modifier onlyRelayer() {
require(IRelayerHub(RELAYERHUB_CONTRACT_ADDR).isRelayer(msg.sender), "the msg sender is not a relayer");
_;
}
modifier onlyTokenManager() {
require(msg.sender == TOKEN_MANAGER_ADDR, "the msg sender must be tokenManager");
_;
}
modifier onlyStakeHub() {
require(msg.sender == STAKE_HUB_ADDR, "the msg sender must be stakeHub");
_;
}
modifier onlyGovernorTimelock() {
require(msg.sender == TIMELOCK_ADDR, "the msg sender must be governor timelock contract");
_;
}
modifier onlyTokenRecoverPortal() {
require(msg.sender == TOKEN_RECOVER_PORTAL_ADDR, "the msg sender must be token recover portal");
_;
}
// Not reliable, do not use when need strong verify
function isContract(address addr) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(addr)
}
return size > 0;
}
}
// contracts/BSCValidatorSet.sol
interface ICrossChain {
function registeredContractChannelMap(address, uint8) external view returns (bool);
}
contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplication {
using SafeMath for uint256;
using RLPDecode for *;
// will not transfer value less than 0.1 BNB for validators
uint256 public constant DUSTY_INCOMING = 1e17;
uint8 public constant JAIL_MESSAGE_TYPE = 1;
uint8 public constant VALIDATORS_UPDATE_MESSAGE_TYPE = 0;
// the precision of cross chain value transfer.
uint256 public constant PRECISION = 1e10;
uint256 public constant EXPIRE_TIME_SECOND_GAP = 1000;
uint256 public constant MAX_NUM_OF_VALIDATORS = 100;
bytes public constant INIT_VALIDATORSET_BYTES = hex"0x6080604052600436106104fb5760003560e01c806388b32f111161028c578063c6d339451161015a578063e40716a1116100cc578063f92eb86b11610085578063f92eb86b14610d2d578063f9a2bbc714610d42578063fc3e590814610d57578063fccc281314610d6c578063fd4ad81f14610d81578063fd6a687914610db057610502565b8063e40716a114610c9b578063ea321e4914610cb0578063eb57e20214610cd0578063eda5868c14610cf0578063f1fad10414610d05578063f340fa0114610d1a57610502565b8063d86222d51161011e578063d86222d514610c1d578063daacdb6614610c32578063dc927faf14610c47578063df8079e914610c5c578063e086c7b114610c71578063e1c7392a14610c8657610502565b8063c6d3394514610bbe578063c81b166214610bd3578063c8509d811461098d578063ce910b0c14610be8578063d68fb56a14610c0857610502565b8063a78abc16116101fe578063ad3c9da6116101b7578063ad3c9da614610b3d578063aef198a914610b5d578063b7ab4db514610b72578063b8cf4ef114610b94578063bf9f4995146106fe578063c466689d14610ba957610502565b8063a78abc1614610ab4578063aa82dce114610ac9578063aad5606314610ade578063aaf5eb6814610af3578063ab51bb9614610b08578063ac43175114610b1d57610502565b806396713da91161025057806396713da914610a365780639dc0926214610a4b5780639fe0f81614610a60578063a0dc275814610a75578063a1a11bf514610a8a578063a5422d5c14610a9f57610502565b806388b32f11146109c25780638a7beb01146109d75780638b5ad0c9146109ec5780638d19a41014610a015780639369d7de14610a2157610502565b806351b4dce3116103c957806370fd5bad1161033b5780637e434d54116102f45780637e434d541461094e57806381650b6214610963578063820dcaa814610978578063831d65d11461098d578063853230aa1461090f57806386249882146109ad57610502565b806370fd5bad146108d0578063718a8aa8146108e557806375d47a0a146108fa57806378dfed4a1461090f5780637942fd05146109245780637a84ca2a1461093957610502565b80635d77156c1161038d5780635d77156c1461082a5780635de1e22c1461083f57806360eba4fe1461085457806362b72cf5146108745780636969a25c146108895780636e47b482146108bb57610502565b806351b4dce3146107ab57806351e80672146107c057806355614fcc146107d5578063565c56b3146107f55780635667515a1461081557610502565b8063300c35671161046d57806343756e5c1161042657806343756e5c1461072057806345cf9daf14610735578063493279b11461074a5780634bf6c8821461076c5780634df6e0c3146107815780635192c82c1461079657610502565b8063300c35671461065b578063321d398a1461067b5780633365af3a1461069b57806335409f7f146106bb5780633b071dcc146106db5780633dffc387146106fe57610502565b8063152ad3b8116104bf578063152ad3b8146105ba5780631e4c1524146105dc5780631ff18069146105fc578063219f22d51461061157806328087028146106265780632a0ffb6e1461063b57610502565b806304c4fec61461050757806307a568471461051e5780630bee7a67146105495780630e2374a51461056b5780631182b8751461058d57610502565b3661050257005b600080fd5b34801561051357600080fd5b5061051c610dc5565b005b34801561052a57600080fd5b50610533610e37565b6040516105409190618ed8565b60405180910390f35b34801561055557600080fd5b5061055e610e3d565b6040516105409190618f02565b34801561057757600080fd5b50610580610e42565b60405161054091906181eb565b34801561059957600080fd5b506105ad6105a83660046180d1565b610e48565b604051610540919061837e565b3480156105c657600080fd5b506105cf611165565b6040516105409190618373565b3480156105e857600080fd5b5061051c6105f7366004617edf565b61116e565b34801561060857600080fd5b50610533611844565b34801561061d57600080fd5b5061055e61184a565b34801561063257600080fd5b5061058061184f565b34801561064757600080fd5b5061051c610656366004617e3f565b611855565b34801561066757600080fd5b5061051c610676366004617e77565b611902565b34801561068757600080fd5b506105cf61069636600461807e565b611c4b565b3480156106a757600080fd5b506105cf6106b636600461807e565b611d1a565b3480156106c757600080fd5b5061051c6106d6366004617e3f565b611dcb565b3480156106e757600080fd5b506106f0611f30565b604051610540929190618289565b34801561070a57600080fd5b5061071361220c565b6040516105409190618f13565b34801561072c57600080fd5b50610580612211565b34801561074157600080fd5b50610533612217565b34801561075657600080fd5b5061075f61221d565b6040516105409190618ec9565b34801561077857600080fd5b50610713612222565b34801561078d57600080fd5b506106f0612227565b3480156107a257600080fd5b506105336123b3565b3480156107b757600080fd5b506105806123b9565b3480156107cc57600080fd5b506105806123bf565b3480156107e157600080fd5b506105cf6107f0366004617e3f565b6123c5565b34801561080157600080fd5b50610533610810366004617e3f565b6123fa565b34801561082157600080fd5b5061071361244b565b34801561083657600080fd5b5061055e612450565b34801561084b57600080fd5b50610533612455565b34801561086057600080fd5b506105ad61086f36600461807e565b61245b565b34801561088057600080fd5b50610533612501565b34801561089557600080fd5b506108a96108a436600461807e565b612507565b60405161054096959493929190618218565b3480156108c757600080fd5b5061058061256b565b3480156108dc57600080fd5b50610713612571565b3480156108f157600080fd5b50610713612576565b34801561090657600080fd5b5061058061257b565b34801561091b57600080fd5b50610533612581565b34801561093057600080fd5b50610713612587565b34801561094557600080fd5b5061053361258c565b34801561095a57600080fd5b50610580612592565b34801561096f57600080fd5b5061055e612598565b34801561098457600080fd5b5061053361259d565b34801561099957600080fd5b5061051c6109a83660046180d1565b6125a3565b3480156109b957600080fd5b50610533612604565b3480156109ce57600080fd5b5061053361260a565b3480156109e357600080fd5b506105cf612610565b3480156109f857600080fd5b50610533612619565b348015610a0d57600080fd5b50610533610a1c366004617e3f565b61261f565b348015610a2d57600080fd5b5061051c61265f565b348015610a4257600080fd5b50610713612773565b348015610a5757600080fd5b50610580612778565b348015610a6c57600080fd5b5061053361277e565b348015610a8157600080fd5b50610533612783565b348015610a9657600080fd5b50610580612788565b348015610aab57600080fd5b506105ad61278e565b348015610ac057600080fd5b506105cf6127ad565b348015610ad557600080fd5b506105806127b6565b348015610aea57600080fd5b506105806127bc565b348015610aff57600080fd5b506105336127c2565b348015610b1457600080fd5b5061055e61244b565b348015610b2957600080fd5b5061051c610b38366004618022565b6127cb565b348015610b4957600080fd5b50610533610b58366004617e3f565b613084565b348015610b6957600080fd5b50610533613096565b348015610b7e57600080fd5b50610b876130a3565b6040516105409190618276565b348015610ba057600080fd5b5061053361318f565b348015610bb557600080fd5b50610533613194565b348015610bca57600080fd5b50610533612571565b348015610bdf57600080fd5b5061058061319a565b348015610bf457600080fd5b506105ad610c0336600461807e565b6131a0565b348015610c1457600080fd5b506105336131ad565b348015610c2957600080fd5b506105336131ec565b348015610c3e57600080fd5b506105336131f8565b348015610c5357600080fd5b506105806131fe565b348015610c6857600080fd5b50610580613204565b348015610c7d57600080fd5b50610533610e3d565b348015610c9257600080fd5b5061051c61320a565b348015610ca757600080fd5b506105336133b9565b348015610cbc57600080fd5b506105cf610ccb366004617fe3565b6133bf565b348015610cdc57600080fd5b5061051c610ceb366004617e3f565b613545565b348015610cfc57600080fd5b5061055e613649565b348015610d1157600080fd5b5061071361364e565b61051c610d28366004617e3f565b613653565b348015610d3957600080fd5b506105336139d2565b348015610d4e57600080fd5b506105806139d8565b348015610d6357600080fd5b5061071361277e565b348015610d7857600080fd5b506105806139de565b348015610d8d57600080fd5b50610da1610d9c36600461807e565b6139e4565b60405161054093929190618ee1565b348015610dbc57600080fd5b50610580613aa6565b6000610dd03361261f565b9050600b8181548110610ddf57fe5b600091825260209091206001601690920201015460ff16610e1b5760405162461bcd60e51b8152600401610e1290618ae4565b60405180910390fd5b6000610e256131ad565b9050610e32338383613aac565b505050565b60095481565b606481565b61200181565b60005460609060ff16610e6d5760405162461bcd60e51b8152600401610e12906185a5565b3361200014610e8e5760405162461bcd60e51b8152600401610e1290618ce5565b600b54610f4c57610e9d6179eb565b60015460005b81811015610f4857600b80546001810182556000919091528351600080516020618fe583398151915260169092029182019081556020808601516000805160206196148339815191528401805460ff1916911515919091179055604086015180518794610f2493600080516020619005833981519152909101920190617a1a565b506060820151610f3a9060038301906013617a94565b505050806001019050610ea3565b5050505b610f54617ac1565b6000610f9585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613d7192505050565b9150915080610fb157610fa86064613f2d565b9250505061115e565b815160009060ff16610fd657610fcf83602001518460400151613f8e565b905061112a565b825160ff16600114156111265782602001515160011461101b57600080516020618fc583398151915260405161100b9061899d565b60405180910390a1506067611121565b6000836020015160008151811061102e57fe5b602090810291909101810151516001600160a01b0381166000908152600490925260409091205490915080158061108f575060018082038154811061106f57fe5b9060005260206000209060040201600201601c9054906101000a900460ff165b156110cd576040516001600160a01b038316907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a261111a565b60006110dc8360018403615150565b905080611118576040516001600160a01b038416907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a25b505b6000925050505b61112a565b5060655b63ffffffff811661114f575050604080516000815260208101909152915061115e9050565b61115881613f2d565b93505050505b9392505050565b60075460ff1681565b33411461118d5760405162461bcd60e51b8152600401610e1290618d34565b3a156111ab5760405162461bcd60e51b8152600401610e1290618a23565b82516040805182815260208084028201019091526060908280156111e957816020015b6111d6617ae5565b8152602001906001900390816111ce5790505b50905060005b82811015611293576040518060c0016040528087838151811061120e57fe5b60200260200101516001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200186838151811061125057fe5b60200260200101516001600160401b03168152602001600015158152602001600081525082828151811061128057fe5b60209081029190910101526001016111ef565b5060405163d31f968d60e01b81526120009063d31f968d906112be906110009060089060040161825a565b60206040518083038186803b1580156112d657600080fd5b505afa1580156112ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130e9190617fc3565b15611631578051601554818111156113b057815b818110156113ae57601580548061133557fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b0319169055600301559055601680548061138857fe5b6001900381819060005260206000200160006113a49190617b1a565b9055600101611322565b505b60005b828110156115f0578181106114d85760158482815181106113d057fe5b602090810291909101810151825460018181018555600094855293839020825160049092020180546001600160a01b039283166001600160a01b0319918216178255938301519481018054958316958516959095179094556040820151600285018054606085015160808601511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b199590961692909716919091179290921692909217169290921790915560a0015160039091015585516016908790839081106114a057fe5b602090810291909101810151825460018101845560009384529282902081516114d29491909101929190910190617a1a565b506115e8565b8381815181106114e457fe5b6020026020010151601582815481106114f957fe5b6000918252602091829020835160049092020180546001600160a01b039283166001600160a01b0319918216178255928401516001820180549184169185169190911790556040840151600282018054606087015160808801511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909716929097169190911792909216939093171692909217905560a09091015160039091015585518690829081106115b457fe5b6020026020010151601682815481106115c957fe5b9060005260206000200190805190602001906115e6929190617a1a565b505b6001016113b3565b507fb8e726330a0dad1cf3d04e925663b17e391f1ed547d79b7f4e5f344119b44246826040516116209190618ed8565b60405180910390a150505050610e32565b60608061163e8386615513565b9150915060005b6001548110156117345760006001828154811061165e57fe5b90600052602060002090600402016003015490508060001461172b5760006001838154811061168957fe5b9060005260206000209060040201600301819055506120026001600160a01b031663092193ab82600185815481106116bd57fe5b60009182526020909120600491820201546040516001600160e01b031960e086901b1681526116f8926001600160a01b0390921691016181eb565b6000604051808303818588803b15801561171157600080fd5b505af1158015611725573d6000803e3d6000fd5b50505050505b50600101611645565b5047156117a2577f6ecc855f9440a9282c90913bbc91619fd44f5ec0b462af28d127b116f130aa4d4760405161176a9190618ed8565b60405180910390a1604051611002904780156108fc02916000818181858888f193505050501580156117a0573d6000803e3d6000fd5b505b600060038190556005558151156117bd576117bd82826159fa565b6110016001600160a01b031663fc4333cd6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156117fa57600080fd5b505af115801561180e573d6000803e3d6000fd5b50506040517fedd8d7296956dd970ab4de3f2fc03be2b0ffc615d20cd4c72c6e44f928630ebf925060009150a150505050505050565b60035481565b606881565b61200581565b33612002146118765760405162461bcd60e51b8152600401610e1290618e92565b60005b6015548110156118fe57816001600160a01b03166015828154811061189a57fe5b60009182526020909120600490910201546001600160a01b031614156118f6576001601582815481106118c957fe5b9060005260206000209060040201600201601c6101000a81548160ff0219169083151502179055506118fe565b600101611879565b5050565b3341146119215760405162461bcd60e51b8152600401610e1290618d34565b60105443116119425760405162461bcd60e51b8152600401610e1290618738565b3a156119605760405162461bcd60e51b8152600401610e1290618a23565b60005460ff166119825760405162461bcd60e51b8152600401610e12906185a5565b60006110023168056bc75e2d631000008111156119b9576119b28168056bc75e2d6310000063ffffffff6161e916565b91506119c0565b5050611c41565b6040516309a99b4f60e41b815261100290639a99b4f0906119e790309086906004016181ff565b602060405180830381600087803b158015611a0157600080fd5b505af1158015611a15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a399190618096565b915081611a47575050611c41565b6000805b84811015611a7557858582818110611a5f57fe5b9050602002013582019150806001019050611a4b565b5080611a8357505050611c41565b6000806000805b89811015611c395784898983818110611a9f57fe5b90506020020135880281611aaf57fe5b0493508a8a82818110611abe57fe5b9050602002016020810190611ad39190617e3f565b6001600160a01b03811660009081526004602052604090205490935091508115611bef576000600180840381548110611b0857fe5b9060005260206000209060040201905080600201601c9054906101000a900460ff1615611b7557836001600160a01b03167fb9c75cbbfde137c4281689580799ef5f52144e78858f776a5979b2b212137d8586604051611b689190618ed8565b60405180910390a2611be9565b600354611b88908663ffffffff61622b16565b6003908155810154611ba0908663ffffffff61622b16565b60038201556040516001600160a01b038516907fcb0aad6cf9cd03bdf6137e359f541c42f38b39f007cae8e89e88aa7d8c6617b290611be0908890618ed8565b60405180910390a25b50611c31565b826001600160a01b03167fb9c75cbbfde137c4281689580799ef5f52144e78858f776a5979b2b212137d8585604051611c289190618ed8565b60405180910390a25b600101611a8a565b505050505050505b5050436010555050565b6001546000908210611c5f57506000611d15565b60006001600160a01b031660018381548110611c7757fe5b60009182526020909120600490910201546001600160a01b03161480611ca757506008541580611ca75750600a54155b80611cb6575060085460095410155b80611cc75750611cc582611d1a565b155b80611cf057506000600b8381548110611cdc57fe5b906000526020600020906016020160000154115b80611d0457506001611d006130a3565b5111155b15611d1157506000611d15565b5060015b919050565b6001546000908210611d2e57506000611d15565b600b548210611d6b5760018281548110611d4457fe5b9060005260206000209060040201600201601c9054906101000a900460ff16159050611d15565b60018281548110611d7857fe5b9060005260206000209060040201600201601c9054906101000a900460ff16158015611dc55750600b8281548110611dac57fe5b600091825260209091206001601690920201015460ff16155b92915050565b600b54611e8957611dda6179eb565b60015460005b81811015611e8557600b80546001810182556000919091528351600080516020618fe583398151915260169092029182019081556020808601516000805160206196148339815191528401805460ff1916911515919091179055604086015180518794611e6193600080516020619005833981519152909101920190617a1a565b506060820151611e779060038301906013617a94565b505050806001019050611de0565b5050505b336110011480611e9a575033612002145b611eb65760405162461bcd60e51b8152600401610e12906185dc565b6001600160a01b03811660009081526004602052604090205480611eda5750611f2d565b6001810390506000600b8281548110611eef57fe5b600091825260209091206001601690920201015460ff169050611f128383615150565b8015611f1b5750805b15610e32576009805460001901905550505b50565b60015460609081906000805b82811015611f835760018181548110611f5157fe5b9060005260206000209060040201600201601c9054906101000a900460ff16611f7b576001909101905b600101611f3c565b50606081604051908082528060200260200182016040528015611fb0578160200160208202803683370190505b509050606082604051908082528060200260200182016040528015611fe957816020015b6060815260200190600190039081611fd45790505b50600b54600094509091508414156121645760005b8481101561215e576001818154811061201357fe5b9060005260206000209060040201600201601c9054906101000a900460ff16612156576001818154811061204357fe5b600091825260209091206004909102015483516001600160a01b039091169084908690811061206e57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050600b818154811061209b57fe5b600091825260209182902060026016909202018101805460408051601f6000196101006001861615020190931694909404918201859004850284018501905280835291929091908301828280156121335780601f1061210857610100808354040283529160200191612133565b820191906000526020600020905b81548152906001019060200180831161211657829003601f168201915b505050505082858151811061214457fe5b60209081029190910101526001909301925b600101611ffe565b50612200565b60005b848110156121fe576001818154811061217c57fe5b9060005260206000209060040201600201601c9054906101000a900460ff166121f657600181815481106121ac57fe5b600091825260209091206004909102015483516001600160a01b03909116908490869081106121d757fe5b6001600160a01b03909216602092830291909101909101526001909301925b600101612167565b505b909450925050505b9091565b600181565b61100181565b60085481565b603881565b600881565b6060806000600e549050600080600c5411612243576015612247565b600c545b905060606122536130a3565b9050606061226082616250565b905082825111612277579094509250612208915050565b83838351031015612289578282510393505b83156122bf5760c843046122a583838388880360008a8a6163be565b6122bd8383838888038989038a8b8b8b5103016163be565b505b6060836040519080825280602002602001820160405280156122eb578160200160208202803683370190505b50905060608460405190808252806020026020018201604052801561232457816020015b606081526020019060019003908161230f5790505b50905060005b858110156123a55784818151811061233e57fe5b602002602001015183828151811061235257fe5b60200260200101906001600160a01b031690816001600160a01b03168152505083818151811061237e57fe5b602002602001015182828151811061239257fe5b602090810291909101015260010161232a565b509096509450505050509091565b60065481565b61200681565b61200081565b6001600160a01b038116600090815260046020526040812054806123ed576000915050611d15565b6000190161115e81611d1a565b6001600160a01b03811660009081526004602052604081205480612422576000915050611d15565b60018082038154811061243157fe5b906000526020600020906004020160030154915050919050565b600081565b606781565b600f5481565b6012818154811061246857fe5b600091825260209182902001805460408051601f60026000196101006001871615020190941693909304928301859004850281018501909152818152935090918301828280156124f95780601f106124ce576101008083540402835291602001916124f9565b820191906000526020600020905b8154815290600101906020018083116124dc57829003601f168201915b505050505081565b60105481565b6001818154811061251457fe5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509082169291821691600160a01b81046001600160401b031691600160e01b90910460ff169086565b61100581565b600281565b601081565b61100881565b6103e881565b600b81565b600c5481565b61200381565b606681565b61271081565b33612000146125c45760405162461bcd60e51b8152600401610e1290618ce5565b7f41ce201247b6ceb957dcdb217d0b8acb50b9ea0e12af9af4f5e7f389021016058383836040516125f793929190618f21565b60405180910390a1505050565b60025481565b60115481565b60145460ff1681565b600a5481565b6001600160a01b038116600090815260046020526040812054806126555760405162461bcd60e51b8152600401610e1290618c6d565b6000190192915050565b600b5461271d5761266e6179eb565b60015460005b8181101561271957600b80546001810182556000919091528351600080516020618fe583398151915260169092029182019081556020808601516000805160206196148339815191528401805460ff19169115159190911790556040860151805187946126f593600080516020619005833981519152909101920190617a1a565b50606082015161270b9060038301906013617a94565b505050806001019050612674565b5050505b60085461272a5760036008555b600a54612737576002600a555b60006127423361261f565b905061274d81611c4b565b6127695760405162461bcd60e51b8152600401610e129061895a565b611f2d3382616515565b600981565b61100781565b600381565b60c881565b61100681565b6040518061062001604052806105ef81526020016190256105ef913981565b60005460ff1681565b61200281565b61300081565b6402540be40081565b60005460ff166127ed5760405162461bcd60e51b8152600401610e12906185a5565b336110071461280e5760405162461bcd60e51b8152600401610e1290618a51565b61287884848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526013815272065787069726554696d655365636f6e6447617606c1b602082015291506165ad9050565b15612915576020811461289d5760405162461bcd60e51b8152600401610e1290618c27565b604080516020601f84018190048102820181019092528281526000916128db9185858083850183828082843760009201919091525061660692505050565b9050606481101580156128f15750620186a08111155b61290d5760405162461bcd60e51b8152600401610e129061884a565b600255613041565b61297584848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260098152686275726e526174696f60b81b602082015291506165ad9050565b15612a18576020811461299a5760405162461bcd60e51b8152600401610e12906183c3565b604080516020601f84018190048102820181019092528281526000916129d89185858083850183828082843760009201919091525061660692505050565b90506127106129f2600f548361622b90919063ffffffff16565b1115612a105760405162461bcd60e51b8152600401610e12906183fa565b600655613041565b612a8284848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260138152726d61784e756d4f664d61696e7461696e696e6760681b602082015291506165ad9050565b15612b1c5760208114612aa75760405162461bcd60e51b8152600401610e1290618462565b604080516020601f8401819004810282018101909252828152600091612ae59185858083850183828082843760009201919091525061660692505050565b600c5490915080612af4575060155b808210612b135760405162461bcd60e51b8152600401610e12906187a2565b50600855613041565b612b8584848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260128152716d61696e7461696e536c6173685363616c6560701b602082015291506165ad9050565b15612c1e5760208114612baa5760405162461bcd60e51b8152600401610e129061852b565b604080516020601f8401819004810282018101909252828152600091612be89185858083850183828082843760009201919091525061660692505050565b9050600081118015612bfa5750600a81105b612c165760405162461bcd60e51b8152600401610e1290618dc5565b600a55613041565b612c9284848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152601981527f6d61784e756d4f66576f726b696e6743616e6469646174657300000000000000602082015291506165ad9050565b15612d215760208114612cb75760405162461bcd60e51b8152600401610e12906184df565b604080516020601f8401819004810282018101909252828152600091612cf59185858083850183828082843760009201919091525061660692505050565b9050600d54811115612d195760405162461bcd60e51b8152600401610e12906188c0565b600e55613041565b612d8a84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260128152716d61784e756d4f6643616e6469646174657360701b602082015291506165ad9050565b15612e0c5760208114612daf5760405162461bcd60e51b8152600401610e1290618a9f565b604080516020601f8401819004810282018101909252828152600091612ded9185858083850183828082843760009201919091525061660692505050565b600d819055600e54909150811015612e0657600d54600e555b50613041565b612e7084848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600d81526c6e756d4f66436162696e65747360981b602082015291506165ad9050565b15612f1e5760208114612e955760405162461bcd60e51b8152600401610e1290618570565b604080516020601f8401819004810282018101909252828152600091612ed39185858083850183828082843760009201919091525061660692505050565b905060008111612ef55760405162461bcd60e51b8152600401610e129061864a565b6064811115612f165760405162461bcd60e51b8152600401610e1290618692565b600c55613041565b612f8684848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152601181527073797374656d526577617264526174696f60781b602082015291506165ad9050565b156130295760208114612fab5760405162461bcd60e51b8152600401610e1290618d81565b604080516020601f8401819004810282018101909252828152600091612fe99185858083850183828082843760009201919091525061660692505050565b90506127106130036006548361622b90919063ffffffff16565b11156130215760405162461bcd60e51b8152600401610e1290618b88565b600f55613041565b60405162461bcd60e51b8152600401610e1290618e22565b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040516130769493929190618391565b60405180910390a150505050565b60046020526000908152604090205481565b68056bc75e2d6310000081565b6001546060906000805b828110156130d2576130be81611d1a565b156130ca578160010191505b6001016130ad565b506060816040519080825280602002602001820160405280156130ff578160200160208202803683370190505b5090506000915060005b838110156131865761311a81611d1a565b1561317e576001818154811061312c57fe5b600091825260209091206004909102015482516001600160a01b039091169083908590811061315757fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508260010192505b600101613109565b50925050505b90565b601581565b61027181565b61100281565b6013818154811061246857fe5b60006131b76130a3565b519050600080600c54116131cc5760156131d0565b600c545b9050808211156131de578091505b816131e857600191505b5090565b67016345785d8a000081565b60055481565b61100381565b61200481565b60005460ff161561322d5760405162461bcd60e51b8152600401610e1290618b51565b613235617ac1565b600061325b6040518061062001604052806105ef81526020016190256105ef9139613d71565b915091508061327c5760405162461bcd60e51b8152600401610e1290618ca4565b60005b8260200151518110156133a15760018360200151828151811061329e57fe5b60209081029190910181015182546001818101855560009485528385208351600493840290910180546001600160a01b039283166001600160a01b03199182161782558587015182850180549185169183169190911790556040860151600283018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b199590981692909516919091179290921694909417161790915560a09093015160039093019290925591860151805191850193918590811061337457fe5b602090810291909101810151516001600160a01b031682528101919091526040016000205560010161327f565b50506103e8600255506000805460ff19166001179055565b600d5481565b601354600090815b818110156134c8576134b085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060138054909250859150811061341857fe5b600091825260209182902001805460408051601f60026000196101006001871615020190941693909304928301859004850281018501909152818152928301828280156134a65780601f1061347b576101008083540402835291602001916134a6565b820191906000526020600020905b81548152906001019060200180831161348957829003601f168201915b505050505061660b565b156134c057600192505050611dc5565b6001016133c7565b5060125460005b818110156135395761352086868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060128054909250859150811061341857fe5b156135315760019350505050611dc5565b6001016134cf565b50600095945050505050565b33611001146135665760405162461bcd60e51b8152600401610e1290618e49565b600b54613624576135756179eb565b60015460005b8181101561362057600b80546001810182556000919091528351600080516020618fe583398151915260169092029182019081556020808601516000805160206196148339815191528401805460ff19169115159190911790556040860151805187946135fc93600080516020619005833981519152909101920190617a1a565b5060608201516136129060038301906013617a94565b50505080600101905061357b565b5050505b600061362f8261666f565b905061363a81611c4b565b156118fe576118fe8282616515565b606581565b601181565b3341146136725760405162461bcd60e51b8152600401610e1290618d34565b60005460ff166136945760405162461bcd60e51b8152600401610e12906185a5565b600034116136b45760405162461bcd60e51b8152600401610e1290618891565b3a156136d25760405162461bcd60e51b8152600401610e1290618a23565b6001600160a01b03811660009081526004602052604090205460145434919060ff1661371257610271600f556103e86006556014805460ff191660011790555b60008211801561372457506000600f54115b156137d6576000613752612710613746600f54346167f290919063ffffffff16565b9063ffffffff61682c16565b905080156137d4576040516110029082156108fc029083906000818181858888f19350505050158015613789573d6000803e3d6000fd5b507f6ecc855f9440a9282c90913bbc91619fd44f5ec0b462af28d127b116f130aa4d816040516137b99190618ed8565b60405180910390a16137d1838263ffffffff6161e916565b92505b505b6000821180156137e857506000600654115b1561388e57600061380a612710613746600654346167f290919063ffffffff16565b9050801561388c5760405161dead9082156108fc029083906000818181858888f19350505050158015613841573d6000803e3d6000fd5b507f627059660ea01c4733a328effb2294d2f86905bf806da763a89cee254de8bee5816040516138719190618ed8565b60405180910390a1613889838263ffffffff6161e916565b92505b505b801561398c5760006001808303815481106138a557fe5b9060005260206000209060040201905080600201601c9054906101000a900460ff161561391257836001600160a01b03167ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4846040516139059190618ed8565b60405180910390a2613986565b600354613925908463ffffffff61622b16565b600390815581015461393d908463ffffffff61622b16565b60038201556040516001600160a01b038516907f93a090ecc682c002995fad3c85b30c5651d7fd29b0be5da9d784a3302aedc0559061397d908690618ed8565b60405180910390a25b50610e32565b826001600160a01b03167ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4836040516139c59190618ed8565b60405180910390a2505050565b600e5481565b61100081565b61dead81565b600b81815481106139f157fe5b6000918252602091829020601691909102018054600180830154600280850180546040805161010096831615969096026000190190911692909204601f810188900488028501880190925281845293965060ff90911694919291830182828015613a9c5780601f10613a7157610100808354040283529160200191613a9c565b820191906000526020600020905b815481529060010190602001808311613a7f57829003601f168201915b5050505050905083565b61100481565b6000600a5460001480613abd575081155b80613ac85750600954155b15613ad55750600061115e565b6000613b0f600a5461374685613746600b8981548110613af157fe5b6000918252602090912060169091020154439063ffffffff6161e916565b90506000806110016001600160a01b0316638256ace66040518163ffffffff1660e01b8152600401604080518083038186803b158015613b4e57600080fd5b505afa158015613b62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b8691906180ae565b9150915060009350808310613ce557613b9f8787615150565b5060405163436aa28360e11b8152600090612002906386d5450690613bc8908b906004016181eb565b60206040518083038186803b158015613be057600080fd5b505afa158015613bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c189190617e5b565b6001600160a01b031614613c84576040516313d13bdb60e31b815261100190639e89ded890613c4d908a9087906004016181ff565b600060405180830381600087803b158015613c6757600080fd5b505af1158015613c7b573d6000803e3d6000fd5b50505050613cdc565b6040516305bfb49960e41b815261100190635bfb499090613ca9908a906004016181eb565b600060405180830381600087803b158015613cc357600080fd5b505af1158015613cd7573d6000803e3d6000fd5b505050505b60019350613cf7565b818310613cf757613cf58761666f565b505b60098054600019019055600b80546000919088908110613d1357fe5b60009182526020822060169190910201600101805460ff1916921515929092179091556040516001600160a01b038916917fb9d38178dc641ff1817967a63c9078cbcd955a9f1fcd75e0e3636de615d44d3b91a25050509392505050565b613d79617ac1565b6000613d83617ac1565b613d8b617b5e565b613d9c613d978661686e565b616893565b90506000805b613dab836168dd565b15613f1f5780613dd057613dc6613dc1846168fe565b61694c565b60ff168452613f17565b8060011415613f12576060613dec613de7856168fe565b6169cc565b90508051604051908082528060200260200182016040528015613e2957816020015b613e16617ae5565b815260200190600190039081613e0e5790505b5085602001819052508051604051908082528060200260200182016040528015613e6757816020015b6060815260200190600190039081613e525790505b50604086015260005b8151811015613f0757613e81617ae5565b60606000613ea1858581518110613e9457fe5b6020026020010151616a9d565b92509250925080613ec1578860009a509a50505050505050505050613f28565b8289602001518581518110613ed257fe5b60200260200101819052508189604001518581518110613eee57fe5b6020026020010181905250505050806001019050613e70565b506001925050613f17565b613f1f565b600101613da2565b50919350909150505b915091565b604080516001808252818301909252606091829190816020015b6060815260200190600190039081613f47579050509050613f6d8363ffffffff16616bb7565b81600081518110613f7a57fe5b602002602001018190525061115e81616bca565b6000606483511115613fc557600080516020618fc5833981519152604051613fb5906186ef565b60405180910390a1506066611dc5565b60005b83518110156140635760005b8181101561405a57848181518110613fe857fe5b6020026020010151600001516001600160a01b031685838151811061400957fe5b6020026020010151600001516001600160a01b0316141561405257600080516020618fc583398151915260405161403f906187ff565b60405180910390a1606692505050611dc5565b600101613fd4565b50600101613fc8565b5060608060606015805480602002602001604051908101604052809291908181526020016000905b828210156141155760008481526020908190206040805160c0810182526004860290920180546001600160a01b039081168452600180830154821685870152600283015491821693850193909352600160a01b81046001600160401b03166060850152600160e01b900460ff16151560808401526003015460a0830152908352909201910161408b565b50505050905060606016805480602002602001604051908101604052809291908181526020016000905b828210156141ea5760008481526020908190208301805460408051601f60026000196101006001871615020190941693909304928301859004850281018501909152818152928301828280156141d65780601f106141ab576101008083540402835291602001916141d6565b820191906000526020600020905b8154815290600101906020018083116141b957829003601f168201915b50505050508152602001906001019061413f565b50505050905060005b82518110156142475782818151811061420857fe5b60200260200101516060015160030283828151811061422357fe5b60209081029190910101516001600160401b039091166060909101526001016141f3565b5060608061425789898686616c54565b915091506142658282615513565b600154604080518281526020808402820101909152929850909650600095508594509250606091508280156142a4578160200160208202803683370190505b50905060005b828110156144355760006001600160a01b03166120026001600160a01b03166386d54506600184815481106142db57fe5b60009182526020909120600491820201546040516001600160e01b031960e085901b168152614316926001600160a01b0390921691016181eb565b60206040518083038186803b15801561432e57600080fd5b505afa158015614342573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143669190617e5b565b6001600160a01b0316146143c857600182828151811061438257fe5b602002602001019060ff16908160ff1681525050600181815481106143a357fe5b9060005260206000209060040201600301546000146143c3578360010193505b61442d565b67016345785d8a0000600182815481106143de57fe5b906000526020600020906004020160030154106144005784600101945061442d565b6001818154811061440d57fe5b90600052602060002090600402016003015460001461442d578360010193505b6001016142aa565b50606084604051908082528060200260200182016040528015614462578160200160208202803683370190505b509050606085604051908082528060200260200182016040528015614491578160200160208202803683370190505b5090506060866040519080825280602002602001820160405280156144c0578160200160208202803683370190505b5090506060876040519080825280602002602001820160405280156144ef578160200160208202803683370190505b5090506000606088604051908082528060200260200182016040528015614520578160200160208202803683370190505b50905060608960405190808252806020026020018201604052801561454f578160200160208202803683370190505b50905060009a506000995060006110046001600160a01b031663149d14d96040518163ffffffff1660e01b815260040160206040518083038186803b15801561459757600080fd5b505afa1580156145ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145cf9190618096565b905067016345785d8a000081111561461b57600080516020618fc58339815191526040516145fc90618b10565b60405180910390a160689e505050505050505050505050505050611dc5565b60005b8a8110156149af5789818151811061463257fe5b602002602001015160ff1660011415614728576001818154811061465257fe5b906000526020600020906004020160030154600014614723576001818154811061467857fe5b600091825260209091206004909102015484516001600160a01b039091169085908e9081106146a357fe5b60200260200101906001600160a01b031690816001600160a01b031681525050600181815481106146d057fe5b906000526020600020906004020160030154838d815181106146ee57fe5b60200260200101818152505060018a8d8151811061470857fe5b602002602001019060ff16908160ff16815250508b6001019b505b6149a7565b67016345785d8a00006001828154811061473e57fe5b906000526020600020906004020160030154106148c3576001818154811061476257fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b0316898e8151811061479357fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006402540be400600183815481106147c857fe5b906000526020600020906004020160030154816147e157fe5b06600183815481106147ef57fe5b90600052602060002090600402016003015403905061481783826161e990919063ffffffff16565b898f8151811061482357fe5b6020026020010181815250506001828154811061483c57fe5b906000526020600020906004020160010160009054906101000a90046001600160a01b0316878f8151811061486d57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505081888f8151811061489a57fe5b60209081029190910101526148b5868263ffffffff61622b16565b95508d6001019d50506149a7565b600181815481106148d057fe5b9060005260206000209060040201600301546000146149a757600181815481106148f657fe5b906000526020600020906004020160010160009054906101000a90046001600160a01b0316848d8151811061492757fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506001818154811061495457fe5b906000526020600020906004020160030154838d8151811061497257fe5b60200260200101818152505060008a8d8151811061498c57fe5b602002602001019060ff16908160ff16815250508b6001019b505b60010161461e565b5060008415614c25576002546040516303702b2960e51b815261100491636e0565209188916149e9918e918e918d914201906004016182f9565b6020604051808303818588803b158015614a0257600080fd5b505af193505050508015614a33575060408051601f3d908101601f19168201909252614a3091810190617fc3565b60015b614baa576040516000815260443d1015614a4f57506000614aea565b60046000803e60005160e01c6308c379a08114614a70576000915050614aea565b60043d036004833e81513d60248201116001600160401b0382111715614a9b57600092505050614aea565b80830180516001600160401b03811115614abc576000945050505050614aea565b8060208301013d8601811115614ada57600095505050505050614aea565b601f01601f191660405250925050505b80614af55750614b37565b60019150857fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf28082604051614b29919061837e565b60405180910390a250614ba5565b3d808015614b61576040519150601f19603f3d011682016040523d82523d6000602084013e614b66565b606091505b5060019150857fbfa884552dd8921b6ce90bfe906952ae5b3b29be0cc1a951d4f62697635a3a4582604051614b9b919061837e565b60405180910390a2505b614c25565b8015614bec577fa217d08e65f80c73121cd9db834d81652d544bfbf452f6d04922b16c90a37b7086604051614bdf9190618ed8565b60405180910390a1614c23565b857fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280604051614c1a906184a8565b60405180910390a25b505b8015614ddb5760005b8751811015614dd9576000888281518110614c4557fe5b60200260200101519050600060018281548110614c5e57fe5b60009182526020909120600160049092020181015481546001600160a01b03909116916108fc9185908110614c8f57fe5b9060005260206000209060040201600301549081150290604051600060405180830381858888f1935050505090508015614d4b5760018281548110614cd057fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d9185908110614d1f57fe5b906000526020600020906004020160030154604051614d3e9190618ed8565b60405180910390a2614dcf565b60018281548110614d5857fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d9185908110614da757fe5b906000526020600020906004020160030154604051614dc69190618ed8565b60405180910390a25b5050600101614c2e565b505b835115614fd15760005b8451811015614fcf578a8181518110614dfa57fe5b602002602001015160ff1660011415614e99576120026001600160a01b031663092193ab858381518110614e2a57fe5b6020026020010151878481518110614e3e57fe5b60200260200101516040518363ffffffff1660e01b8152600401614e6291906181eb565b6000604051808303818588803b158015614e7b57600080fd5b505af1158015614e8f573d6000803e3d6000fd5b5050505050614fc7565b6000858281518110614ea757fe5b60200260200101516001600160a01b03166108fc868481518110614ec757fe5b60200260200101519081150290604051600060405180830381858888f1935050505090508015614f5d57858281518110614efd57fe5b60200260200101516001600160a01b03167f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d868481518110614f3b57fe5b6020026020010151604051614f509190618ed8565b60405180910390a2614fc5565b858281518110614f6957fe5b60200260200101516001600160a01b03167f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d868481518110614fa757fe5b6020026020010151604051614fbc9190618ed8565b60405180910390a25b505b600101614de5565b505b5050505050505050505050505060005b60015481101561503e5760018181548110614ff857fe5b9060005260206000209060040201600301546000146150365760006001828154811061502057fe5b9060005260206000209060040201600301819055505b600101614fe1565b5047156150ac577f6ecc855f9440a9282c90913bbc91619fd44f5ec0b462af28d127b116f130aa4d476040516150749190618ed8565b60405180910390a1604051611002904780156108fc02916000818181858888f193505050501580156150aa573d6000803e3d6000fd5b505b600060038190556005558151156150c7576150c782826159fa565b6110016001600160a01b031663fc4333cd6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561510457600080fd5b505af1158015615118573d6000803e3d6000fd5b50506040517fedd8d7296956dd970ab4de3f2fc03be2b0ffc615d20cd4c72c6e44f928630ebf925060009150a1506000949350505050565b6000806001838154811061516057fe5b9060005260206000209060040201600301549050600060018080549050039050600161518a6130a3565b51116151bf5760006001858154811061519f57fe5b906000526020600020906004020160030181905550600092505050611dc5565b846001600160a01b03167f3b6f9ef90462b512a1293ecec018670bf7b7f1876fb727590a8a6d7643130a70836040516151f89190618ed8565b60405180910390a26001600160a01b038516600090815260046020526040812055835b600154600019018110156153e5576001816001018154811061523957fe5b90600052602060002090600402016001828154811061525457fe5b60009182526020909120825460049092020180546001600160a01b03199081166001600160a01b0393841617825560018085015481840180548416918616919091179055600280860180549185018054909416919095161780835584546001600160401b03600160a01b91829004160267ffffffffffffffff60a01b1990911617808355935460ff600160e01b918290041615150260ff60e01b19909416939093179055600392830154920191909155600b80549091830190811061531557fe5b9060005260206000209060160201600b828154811061533057fe5b600091825260209091208254601690920201908155600180830154818301805460ff909216151560ff1990921691909117905560028084018054615387938386019390821615610100026000190190911604617b7e565b5061539a60038281019084016013617bf3565b509050508060010160046000600184815481106153b357fe5b600091825260208083206004909202909101546001600160a01b0316835282019290925260400190205560010161521b565b5060018054806153f157fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b0319169055600301559055600b80548061544457fe5b60008281526020812060166000199093019283020181815560018101805460ff19169055906154766002830182617b1a565b615484600383016000617c1d565b50509055600081838161549357fe5b04905080156155075760015460005b81811015615504576154db83600183815481106154bb57fe5b90600052602060002090600402016003015461622b90919063ffffffff16565b600182815481106154e857fe5b60009182526020909120600360049092020101556001016154a2565b50505b50600195945050505050565b6060806000808080806155246131ad565b6001549091505b801561575357600181039250600b838154811061554457fe5b600091825260209091206001601690920201015460ff166155645761574a565b6001838154811061557157fe5b60009182526020909120600490910201546001600160a01b03169450615598858484613aac565b9350836155a45761574a565b60405163436aa28360e11b81526000908190612002906386d54506906155ce908a906004016181eb565b60206040518083038186803b1580156155e657600080fd5b505afa1580156155fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061561e9190617e5b565b90506001600160a01b038116156156a7576040516302ceee9160e11b81526120029063059ddd22906156549084906004016181eb565b60206040518083038186803b15801561566c57600080fd5b505afa158015615680573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906156a49190617e5b565b91505b60005b8c5181101561574657876001600160a01b03168d82815181106156c957fe5b6020026020010151600001516001600160a01b031614806157125750826001600160a01b03168d82815181106156fb57fe5b6020026020010151600001516001600160a01b0316145b1561573e5760018d828151811061572557fe5b6020908102919091010151901515608090910152615746565b6001016156aa565b5050505b6000190161552b565b5060005b89518110156157c05789818151811061576c57fe5b602002602001015160800151806157ac575060006001600160a01b03168a828151811061579557fe5b6020026020010151600001516001600160a01b0316145b156157b8578560010195505b600101615757565b50885185106158a85760408051600180825281830190925290816020015b6157e6617ae5565b8152602001906001900390816157de575050604080516001808252818301909252919850602082015b606081526020019060019003908161580f5790505095508860008151811061583357fe5b60200260200101518760008151811061584857fe5b60200260200101819052508760008151811061586057fe5b60200260200101518660008151811061587557fe5b602002602001018190525060008760008151811061588f57fe5b60209081029190910101519015156080909101526159ed565b848951036040519080825280602002602001820160405280156158e557816020015b6158d2617ae5565b8152602001906001900390816158ca5790505b5096508489510360405190808252806020026020018201604052801561591f57816020015b606081526020019060019003908161590a5790505b5095506000915060005b89518110156159eb5789818151811061593e57fe5b602002602001015160800151158015615981575060006001600160a01b03168a828151811061596957fe5b6020026020010151600001516001600160a01b031614155b156159e35789818151811061599257fe5b60200260200101518884815181106159a657fe5b60200260200101819052508881815181106159bd57fe5b60200260200101518784815181106159d157fe5b60200260200101819052508260010192505b600101615929565b505b50505050505b9250929050565b600154825160005b82811015615b17576001615a14617ae5565b60018381548110615a2157fe5b600091825260208083206040805160c08101825260049490940290910180546001600160a01b0390811685526001820154811693850193909352600281015492831691840191909152600160a01b82046001600160401b03166060840152600160e01b90910460ff16151560808301526003015460a082015291505b84811015615aeb57878181518110615ab157fe5b6020026020010151600001516001600160a01b031682600001516001600160a01b03161415615ae35760009250615aeb565b600101615a9d565b508115615b0d5780516001600160a01b03166000908152600460205260408120555b5050600101615a02565b5080821115615bd657805b82811015615bd4576001805480615b3557fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b0319169055600301559055600b805480615b8857fe5b60008281526020812060166000199093019283020181815560018101805460ff1916905590615bba6002830182617b1a565b615bc8600383016000617c1d565b50509055600101615b22565b505b6000818310615be55781615be7565b825b905060005b81811015615f8b57615c99868281518110615c0357fe5b602002602001015160018381548110615c1857fe5b60009182526020918290206040805160c08101825260049390930290910180546001600160a01b0390811684526001820154811694840194909452600281015493841691830191909152600160a01b83046001600160401b03166060830152600160e01b90920460ff161515608082015260039091015460a0820152617020565b615e4d578060010160046000888481518110615cb157fe5b6020026020010151600001516001600160a01b03166001600160a01b0316815260200190815260200160002081905550858181518110615ced57fe5b602002602001015160018281548110615d0257fe5b6000918252602091829020835160049092020180546001600160a01b039283166001600160a01b0319918216178255928401516001820180549184169185169190911790556040840151600282018054606087015160808801511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909716929097169190911792909216939093171692909217905560a0909101516003909101558451859082908110615dbd57fe5b6020026020010151600b8281548110615dd257fe5b90600052602060002090601602016002019080519060200190615df6929190617a1a565b506000600b8281548110615e0657fe5b60009182526020822060169190910201600101805460ff191692151592909217909155600b805483908110615e3757fe5b6000918252602090912060169091020155615f83565b858181518110615e5957fe5b60200260200101516060015160018281548110615e7257fe5b906000526020600020906004020160020160146101000a8154816001600160401b0302191690836001600160401b03160217905550615f38858281518110615eb657fe5b6020026020010151600b8381548110615ecb57fe5b600091825260209182902060026016909202018101805460408051601f6000196101006001861615020190931694909404918201859004850284018501905280835291929091908301828280156134a65780601f1061347b576101008083540402835291602001916134a6565b615f8357848181518110615f4857fe5b6020026020010151600b8281548110615f5d57fe5b90600052602060002090601602016002019080519060200190615f81929190617a1a565b505b600101615bec565b508282111561616357615f9c6179eb565b835b8381101561616057858181518110615fb257fe5b602002602001015182604001819052506001878281518110615fd057fe5b6020908102919091018101518254600181810185556000948552838520835160049093020180546001600160a01b039384166001600160a01b0319918216178255848601518284018054918616918316919091179055604080860151600284018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909a1692909616919091179290921696909617169190911790935560a090930151600390930192909255600b8054928301815590935284516016909102600080516020618fe58339815191528101918255858301516000805160206196148339815191528201805491151560ff19909216919091179055928501518051869492936161069360008051602061900583398151915201920190617a1a565b50606082015161611c9060038301906013617a94565b505050806001016004600089848151811061613357fe5b602090810291909101810151516001600160a01b0316825281019190915260400160002055600101615f9e565b50505b61616b61707c565b616173617264565b6000600981905560015493505b838110156161e1576000600b828154811061619757fe5b60009182526020822060169190910201600101805460ff191692151592909217909155600b8054839081106161c857fe5b6000918252602090912060169091020155600101616180565b505050505050565b600061115e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250617452565b60008282018381101561115e5760405162461bcd60e51b8152600401610e1290618613565b60015481516040805182815260208084028201019091526060929190839082801561628f57816020015b606081526020019060019003908161627a5790505b50600b5490915083146162a6579250611d15915050565b60005b828110156163b557600b6001600460008985815181106162c557fe5b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205403815481106162f957fe5b600091825260209182902060026016909202018101805460408051601f6000196101006001861615020190931694909404918201859004850284018501905280835291929091908301828280156163915780601f1061636657610100808354040283529160200191616391565b820191906000526020600020905b81548152906001019060200180831161637457829003601f168201915b50505050508282815181106163a257fe5b60209081029190910101526001016162a9565b50949350505050565b60005b8281101561650b57600082878388016040516020016163e19291906181dd565b6040516020818303038152906040528051906020012060001c8161640157fe5b06905080850182870114616502576000898388018151811061641f57fe5b602002602001015190506060898489018151811061643957fe5b602002602001015190508a8388018151811061645157fe5b60200260200101518b858a018151811061646757fe5b60200260200101906001600160a01b031690816001600160a01b031681525050818b8489018151811061649657fe5b60200260200101906001600160a01b031690816001600160a01b03168152505089838801815181106164c457fe5b60200260200101518a858a01815181106164da57fe5b6020026020010181905250808a848901815181106164f457fe5b602002602001018190525050505b506001016163c1565b5050505050505050565b600980546001908101909155600b80548390811061652f57fe5b906000526020600020906016020160010160006101000a81548160ff02191690831515021790555043600b828154811061656557fe5b600091825260208220601690910201919091556040516001600160a01b038416917ff62981a567ec3cec866c6fa93c55bcdf841d6292d18b8d522ececa769375d82d91a25050565b6000816040516020016165c091906181c1565b60405160208183030381529060405280519060200120836040516020016165e791906181c1565b6040516020818303038152906040528051906020012014905092915050565b015190565b8151815160009160019181148083146166275760009250616665565b600160208701838101602088015b6002848385100114156166605780518351146166545760009650600093505b60209283019201616635565b505050505b5090949350505050565b6001600160a01b0381166000908152600460205260408120548061669857506000199050611d15565b6001810390506000600182815481106166ad57fe5b90600052602060002090600402016003015490506000600183815481106166d057fe5b6000918252602090912060036004909202010155600154604051600019909101906001600160a01b038616907f8cd4e147d8af98a9e3b6724021b8bf6aed2e5dac71c38f2dce8161b82585b25d90616729908590618ed8565b60405180910390a28061674157829350505050611d15565b600081838161674c57fe5b04905080156167e85760005b8481101561679a5761677182600183815481106154bb57fe5b6001828154811061677e57fe5b6000918252602090912060036004909202010155600101616758565b50600180549085015b818110156167e5576167bc83600183815481106154bb57fe5b600182815481106167c957fe5b60009182526020909120600360049092020101556001016167a3565b50505b5091949350505050565b60008261680157506000611dc5565b8282028284828161680e57fe5b041461115e5760405162461bcd60e51b8152600401610e12906189e2565b600061115e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061747e565b616876617c2c565b506040805180820190915281518152602082810190820152919050565b61689b617b5e565b6168a4826174b5565b6168ad57600080fd5b60006168bc83602001516174ef565b60208085015160408051808201909152868152920190820152915050919050565b60006168e7617c2c565b505080518051602091820151919092015191011190565b616906617c2c565b61690f826168dd565b61691857600080fd5b6020820151600061692882617552565b80830160209586015260408051808201909152908152938401919091525090919050565b80516000901580159061696157508151602110155b61696a57600080fd5b600061697983602001516174ef565b9050808360000151101561699f5760405162461bcd60e51b8152600401610e1290618bf0565b8251602080850151830180519284900392918310156163b557506020919091036101000a90049392505050565b60606169d7826174b5565b6169e057600080fd5b60006169eb83617633565b9050606081604051908082528060200260200182016040528015616a2957816020015b616a16617c2c565b815260200190600190039081616a0e5790505b5090506000616a3b85602001516174ef565b60208601510190506000805b84811015616a9257616a5883617552565b9150604051806040016040528083815260200184815250848281518110616a7b57fe5b602090810291909101015291810191600101616a47565b509195945050505050565b616aa5617ae5565b60606000616ab1617ae5565b6060616abb617b5e565b616ac487616893565b90506000805b616ad3836168dd565b15616ba85780616afe57616aee616ae9846168fe565b61768f565b6001600160a01b03168552616ba0565b8060011415616b2657616b13616ae9846168fe565b6001600160a01b03166020860152616ba0565b8060021415616b4e57616b3b616ae9846168fe565b6001600160a01b03166040860152616ba0565b8060031415616b7a57616b63613dc1846168fe565b6001600160401b0316606086015260019150616ba0565b8060041415616b9b57616b94616b8f846168fe565b6176a9565b9350616ba0565b616ba8565b600101616aca565b50929791965091945092505050565b6060611dc5616bc583617719565b6177ff565b6060815160001415616beb5750604080516000815260208101909152611d15565b606082600081518110616bfa57fe5b602002602001015190506000600190505b8351811015616c3b57616c3182858381518110616c2457fe5b6020026020010151617851565b9150600101616c0b565b5061115e616c4e825160c060ff166178ce565b82617851565b60608060006120026001600160a01b031663c473318f6040518163ffffffff1660e01b815260040160206040518083038186803b158015616c9457600080fd5b505afa158015616ca8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190616ccc9190618096565b90508085518851011015616ce1575083518651015b606081604051908082528060200260200182016040528015616d1d57816020015b616d0a617ae5565b815260200190600190039081616d025790505b509050606082604051908082528060200260200182016040528015616d5657816020015b6060815260200190600190039081616d415790505b50905060008060005b8b51831080616d6e5750895182105b8015616d7957508581105b1561700e578b51831415616de957898281518110616d9357fe5b6020026020010151858281518110616da757fe5b6020026020010181905250888281518110616dbe57fe5b6020026020010151848281518110616dd257fe5b602090810291909101015260019182019101616d5f565b8951821415616e54578b8381518110616dfe57fe5b6020026020010151858281518110616e1257fe5b60200260200101819052508a8381518110616e2957fe5b6020026020010151848281518110616e3d57fe5b602090810291909101015260019283019201616d5f565b898281518110616e6057fe5b6020026020010151606001516001600160401b03168c8481518110616e8157fe5b6020026020010151606001516001600160401b03161115616efd578b8381518110616ea857fe5b6020026020010151858281518110616ebc57fe5b60200260200101819052508a8381518110616ed357fe5b6020026020010151848281518110616ee757fe5b6020026020010181905250826001019250617006565b898281518110616f0957fe5b6020026020010151606001516001600160401b03168c8481518110616f2a57fe5b6020026020010151606001516001600160401b03161015616fa657898281518110616f5157fe5b6020026020010151858281518110616f6557fe5b6020026020010181905250888281518110616f7c57fe5b6020026020010151848281518110616f9057fe5b6020026020010181905250816001019150617006565b898281518110616fb257fe5b6020026020010151600001516001600160a01b03168c8481518110616fd357fe5b6020026020010151600001516001600160a01b03161015616ffa578b8381518110616ea857fe5b898281518110616d9357fe5b600101616d5f565b50929a91995090975050505050505050565b805182516000916001600160a01b03918216911614801561705a575081602001516001600160a01b031683602001516001600160a01b0316145b801561115e5750506040908101519101516001600160a01b0390811691161490565b601254601354808211156170c757805b828110156170c557601280548061709f57fe5b6001900381819060005260206000200160006170bb9190617b1a565b905560010161708c565b505b60008183106170d657816170d8565b825b905060005b818110156171f057617195601282815481106170f557fe5b600091825260209182902001805460408051601f60026000196101006001871615020190941693909304928301859004850281018501909152818152928301828280156171835780601f1061715857610100808354040283529160200191617183565b820191906000526020600020905b81548152906001019060200180831161716657829003601f168201915b50505050506013838154811061341857fe5b6171e857601381815481106171a657fe5b90600052602060002001601282815481106171bd57fe5b9060005260206000200190805460018160011615610100020316600290046171e6929190617b7e565b505b6001016170dd565b5082821115610e3257825b8281101561725e5760126013828154811061721257fe5b6000918252602080832084546001818101875595855291909320929091018054617255949390920192909160026101009282161592909202600019011604617b7e565b506001016171fb565b50505050565b601354600b54808211156172af57805b828110156172ad57601380548061728757fe5b6001900381819060005260206000200160006172a39190617b1a565b9055600101617274565b505b60008183106172be57816172c0565b825b905060005b818110156173df5761737d601382815481106172dd57fe5b600091825260209182902001805460408051601f600260001961010060018716150201909416939093049283018590048502810185019091528181529283018282801561736b5780601f106173405761010080835404028352916020019161736b565b820191906000526020600020905b81548152906001019060200180831161734e57829003601f168201915b5050505050600b8381548110615ecb57fe5b6173d757600b818154811061738e57fe5b9060005260206000209060160201600201601382815481106173ac57fe5b9060005260206000200190805460018160011615610100020316600290046173d5929190617b7e565b505b6001016172c5565b5082821115610e3257825b8281101561725e576013600b828154811061740157fe5b60009182526020808320845460018082018755958552919093206016929092029092016002908101805461744995939094019390926000199082161561010002011604617b7e565b506001016173ea565b600081848411156174765760405162461bcd60e51b8152600401610e12919061837e565b505050900390565b6000818361749f5760405162461bcd60e51b8152600401610e12919061837e565b5060008385816174ab57fe5b0495945050505050565b80516000906174c657506000611d15565b6020820151805160001a9060c08210156174e557600092505050611d15565b5060019392505050565b8051600090811a6080811015617509576000915050611d15565b60b8811080617524575060c08110801590617524575060f881105b15617533576001915050611d15565b60c08110156175475760b519019050611d15565b60f519019050611d15565b80516000908190811a608081101561756d576001915061762c565b60b881101561758257607e198101915061762c565b60c08110156175d357600060b78203600186019550806020036101000a8651049150600181018201935050808310156175cd5760405162461bcd60e51b8152600401610e129061892f565b5061762c565b60f88110156175e85760be198101915061762c565b600060f78203600186019550806020036101000a86510491506001810182019350508083101561762a5760405162461bcd60e51b8152600401610e129061892f565b505b5092915050565b805160009061764457506000611d15565b6000809050600061765884602001516174ef565b602085015185519181019250015b808210156176865761767782617552565b82019150826001019250617666565b50909392505050565b80516000906015146176a057600080fd5b611dc58261694c565b80516060906176b757600080fd5b60006176c683602001516174ef565b83516040805191839003808352601f19601f82011683016020019091529192506060908280156176fd576020820181803683370190505b50905060008160200190506163b58487602001510182856179a0565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff19841661775d57506018617781565b6fffffffffffffffffffffffffffffffff19841661777d57506010617781565b5060005b60208110156177b75781818151811061779657fe5b01602001516001600160f81b031916156177af576177b7565b600101617781565b60008160200390506060816040519080825280601f01601f1916602001820160405280156177ec576020820181803683370190505b5080830196909652508452509192915050565b6060815160011480156178315750607f60f81b8260008151811061781f57fe5b01602001516001600160f81b03191611155b1561783d575080611d15565b611dc561784f8351608060ff166178ce565b835b6060806040519050835180825260208201818101602087015b8183101561788257805183526020928301920161786a565b50855184518101855292509050808201602086015b818310156178af578051835260209283019201617897565b508651929092011591909101601f01601f191660405250905092915050565b60606801000000000000000083106178f85760405162461bcd60e51b8152600401610e129061877a565b604080516001808252818301909252606091602082018180368337019050509050603784116179525782840160f81b8160008151811061793457fe5b60200101906001600160f81b031916908160001a9053509050611dc5565b606061795d85617719565b90508381510160370160f81b8260008151811061797657fe5b60200101906001600160f81b031916908160001a9053506179978282617851565b95945050505050565b806179aa57610e32565b5b602081106179ca578251825260209283019290910190601f19016179ab565b915181516020939093036101000a6000190180199091169216919091179052565b60405180608001604052806000815260200160001515815260200160608152602001617a15617c46565b905290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10617a5b57805160ff1916838001178555617a88565b82800160010185558215617a88579182015b82811115617a88578251825591602001919060010190617a6d565b506131e8929150617c65565b8260138101928215617a885791602002820182811115617a88578251825591602001919060010190617a6d565b6040518060600160405280600060ff16815260200160608152602001606081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b50805460018160011615610100020316600290046000825580601f10617b405750611f2d565b601f016020900490600052602060002090810190611f2d9190617c65565b6040518060400160405280617b71617c2c565b8152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10617bb75780548555617a88565b82800160010185558215617a8857600052602060002091601f016020900482015b82811115617a88578254825591600101919060010190617bd8565b8260138101928215617a885791820182811115617a88578254825591600101919060010190617bd8565b50611f2d906013810190617c65565b604051806040016040528060008152602001600081525090565b6040518061026001604052806013906020820280368337509192915050565b61318c91905b808211156131e85760008155600101617c6b565b8035611dc581618faf565b60008083601f840112617c9b578182fd5b5081356001600160401b03811115617cb1578182fd5b60208301915083602080830285010111156159f357600080fd5b6000601f8381840112617cdc578182fd5b8235617cef617cea82618f64565b618f3e565b818152925060208084019085810160005b84811015617d81578135880189603f820112617d1b57600080fd5b838101356001600160401b03811115617d3357600080fd5b617d44818901601f19168601618f3e565b81815260408c81848601011115617d5a57600080fd5b82818501888401375060009181018601919091528552509282019290820190600101617d00565b50505050505092915050565b600082601f830112617d9d578081fd5b8135617dab617cea82618f64565b818152915060208083019084810181840286018201871015617dcc57600080fd5b6000805b85811015617d815782356001600160401b0381168114617dee578283fd5b85529383019391830191600101617dd0565b60008083601f840112617e11578182fd5b5081356001600160401b03811115617e27578182fd5b6020830191508360208285010111156159f357600080fd5b600060208284031215617e50578081fd5b813561115e81618faf565b600060208284031215617e6c578081fd5b815161115e81618faf565b60008060008060408587031215617e8c578283fd5b84356001600160401b0380821115617ea2578485fd5b617eae88838901617c8a565b90965094506020870135915080821115617ec6578384fd5b50617ed387828801617c8a565b95989497509550505050565b600080600060608486031215617ef3578283fd5b83356001600160401b0380821115617f09578485fd5b81860187601f820112617f1a578586fd5b80359250617f2a617cea84618f64565b80848252602080830192508084018b828389028701011115617f4a57898afd5b8994505b86851015617f7457617f608c82617c7f565b845260019490940193928101928101617f4e565b509097508801359350505080821115617f8b578384fd5b617f9787838801617d8d565b93506040860135915080821115617fac578283fd5b50617fb986828701617ccb565b9150509250925092565b600060208284031215617fd4578081fd5b8151801515811461115e578182fd5b60008060208385031215617ff5578182fd5b82356001600160401b0381111561800a578283fd5b61801685828601617e00565b90969095509350505050565b60008060008060408587031215618037578384fd5b84356001600160401b038082111561804d578586fd5b61805988838901617e00565b90965094506020870135915080821115618071578384fd5b50617ed387828801617e00565b60006020828403121561808f578081fd5b5035919050565b6000602082840312156180a7578081fd5b5051919050565b600080604083850312156180c0578182fd5b505080516020909101519092909150565b6000806000604084860312156180e5578081fd5b833560ff811681146180f5578182fd5b925060208401356001600160401b0381111561810f578182fd5b61811b86828701617e00565b9497909650939450505050565b6000815180845260208085019450808401835b838110156181605781516001600160a01b03168752958201959082019060010161813b565b509495945050505050565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b600081518084526181ad816020860160208601618f83565b601f01601f19169290920160200192915050565b600082516181d3818460208701618f83565b9190910192915050565b918252602082015260400190565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03968716815294861660208601529290941660408401526001600160401b03166060830152911515608082015260a081019190915260c00190565b6001600160a01b0392909216825260ff16602082015260400190565b60006020825261115e6020830184618128565b60006040825261829c6040830185618128565b602083820381850152818551808452828401915082838202850101838801865b838110156182ea57601f198784030185526182d8838351618195565b948601949250908501906001016182bc565b50909998505050505050505050565b60006080825261830c6080830187618128565b828103602084810191909152865180835287820192820190845b8181101561834257845183529383019391830191600101618326565b505084810360408601526183568188618128565b93505050506001600160401b038316606083015295945050505050565b901515815260200190565b60006020825261115e6020830184618195565b6000604082526183a560408301868861816b565b82810360208401526183b881858761816b565b979650505050505050565b6020808252601c908201527f6c656e677468206f66206275726e526174696f206d69736d6174636800000000604082015260600190565b60208082526042908201527f746865206275726e526174696f20706c75732073797374656d5265776172645260408201527f6174696f206d757374206265206e6f2067726561746572207468616e20313030606082015261030360f41b608082015260a00190565b60208082526026908201527f6c656e677468206f66206d61784e756d4f664d61696e7461696e696e67206d696040820152650e6dac2e8c6d60d31b606082015260800190565b6020808252601b908201527f6261746368207472616e736665722072657475726e2066616c73650000000000604082015260600190565b6020808252602c908201527f6c656e677468206f66206d61784e756d4f66576f726b696e6743616e6469646160408201526b0e8cae640dad2e6dac2e8c6d60a31b606082015260800190565b60208082526025908201527f6c656e677468206f66206d61696e7461696e536c6173685363616c65206d69736040820152640dac2e8c6d60db1b606082015260800190565b6020808252818101527f6c656e677468206f66206e756d4f66436162696e657473206d69736d61746368604082015260600190565b60208082526019908201527f74686520636f6e7472616374206e6f7420696e69742079657400000000000000604082015260600190565b6020808252601f908201527f6f6e6c7920736c617368206f72207374616b6548756220636f6e747261637400604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526028908201527f746865206e756d4f66436162696e657473206d75737420626520677265617465604082015267072207468616e20360c41b606082015260800190565b60208082526039908201527f746865206e756d4f66436162696e657473206d757374206265206c657373207460408201527f68616e204d41585f4e554d5f4f465f56414c494441544f525300000000000000606082015260800190565b60208082526029908201527f746865206e756d626572206f662076616c696461746f727320657863656564206040820152681d1a19481b1a5b5a5d60ba1b606082015260800190565b60208082526022908201527f63616e206e6f7420646f207468697320747769636520696e206f6e6520626c6f604082015261636b60f01b606082015260800190565b6020808252600e908201526d696e70757420746f6f206c6f6e6760901b604082015260600190565b60208082526037908201527f746865206d61784e756d4f664d61696e7461696e696e67206d7573742062652060408201527f6c657373207468616e206e756d4f66436162696e657473000000000000000000606082015260800190565b6020808252602b908201527f6475706c696361746520636f6e73656e7375732061646472657373206f66207660408201526a185b1a59185d1bdc94d95d60aa1b606082015260800190565b60208082526027908201527f7468652065787069726554696d655365636f6e64476170206973206f7574206f604082015266662072616e676560c81b606082015260800190565b6020808252601590820152746465706f7369742076616c7565206973207a65726f60581b604082015260600190565b60208082526049908201527f746865206d61784e756d4f66576f726b696e6743616e64696461746573206d7560408201527f7374206265206e6f742067726561746572207468616e206d61784e756d4f6643606082015268616e6469646174657360b81b608082015260a00190565b6020808252601190820152706164646974696f6e206f766572666c6f7760781b604082015260600190565b60208082526023908201527f63616e206e6f7420656e7465722054656d706f72617279204d61696e74656e616040820152626e636560e81b606082015260800190565b60208082526025908201527f6c656e677468206f66206a61696c2076616c696461746f7273206d757374206260408201526465206f6e6560d81b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252601490820152736761737072696365206973206e6f74207a65726f60601b604082015260600190565b6020808252602e908201527f746865206d6573736167652073656e646572206d75737420626520676f76657260408201526d1b985b98d94818dbdb9d1c9858dd60921b606082015260800190565b60208082526025908201527f6c656e677468206f66206d61784e756d4f6643616e64696461746573206d69736040820152640dac2e8c6d60db1b606082015260800190565b6020808252601290820152716e6f7420696e206d61696e74656e616e636560701b604082015260600190565b60208082526021908201527f666565206973206c6172676572207468616e2044555354595f494e434f4d494e6040820152604760f81b606082015260800190565b60208082526019908201527f74686520636f6e747261637420616c726561647920696e697400000000000000604082015260600190565b60208082526042908201527f7468652073797374656d526577617264526174696f20706c7573206275726e5260408201527f6174696f206d757374206265206e6f2067726561746572207468616e20313030606082015261030360f41b608082015260a00190565b6020808252601a908201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604082015260600190565b60208082526026908201527f6c656e677468206f662065787069726554696d655365636f6e64476170206d696040820152650e6dac2e8c6d60d31b606082015260800190565b60208082526017908201527f6f6e6c792063757272656e742076616c696461746f7273000000000000000000604082015260600190565b60208082526021908201527f6661696c656420746f20706172736520696e69742076616c696461746f7253656040820152601d60fa1b606082015260800190565b6020808252602f908201527f746865206d6573736167652073656e646572206d7573742062652063726f737360408201526e0818da185a5b8818dbdb9d1c9858dd608a1b606082015260800190565b6020808252602d908201527f746865206d6573736167652073656e646572206d75737420626520746865206260408201526c3637b1b590383937b23ab1b2b960991b606082015260800190565b60208082526024908201527f6c656e677468206f662073797374656d526577617264526174696f206d69736d6040820152630c2e8c6d60e31b606082015260800190565b6020808252603e908201527f746865206d61696e7461696e536c6173685363616c65206d757374206265206760408201527f726561746572207468616e203020616e64206c657373207468616e2031300000606082015260800190565b6020808252600d908201526c756e6b6e6f776e20706172616d60981b604082015260600190565b60208082526029908201527f746865206d6573736167652073656e646572206d75737420626520736c6173686040820152680818dbdb9d1c9858dd60ba1b606082015260800190565b6020808252601f908201527f746865206d73672073656e646572206d757374206265207374616b6548756200604082015260600190565b61ffff91909116815260200190565b90815260200190565b60008482528315156020830152606060408301526179976060830184618195565b63ffffffff91909116815260200190565b60ff91909116815260200190565b600060ff851682526040602083015261799760408301848661816b565b6040518181016001600160401b0381118282101715618f5c57600080fd5b604052919050565b60006001600160401b03821115618f79578081fd5b5060209081020190565b60005b83811015618f9e578181015183820152602001618f86565b8381111561725e5750506000910152565b6001600160a01b0381168114611f2d57600080fdfe70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb20175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbbf905ec80f905e8f846942a7cdd959bfe8d9487b2a43b33565295a698f7e294b6a7edd747c0554875d3fc531d19ba1497992c5e941ff80f3f7f110ffd8920a3ac38fdef318fe94a3f86048c27395000f846946488aa4d1955ee33403f8ccb1d4de5fb97c7ade294220f003d8bdfaadf52aa1e55ae4cc485e6794875941a87e90e440a39c99aa9cb5cea0ad6a3f0b2407b86048c27395000f846949ef9f4360c606c7ab4db26b016007d3ad0ab86a0946103af86a874b705854033438383c82575f25bc29418e2db06cbff3e3c5f856410a1838649e760175786048c27395000f84694ee01c3b1283aa067c58eab4709f85e99d46de5fe94ee4b9bfb1871c64e2bcabb1dc382dc8b7c4218a29415904ab26ab0e99d70b51c220ccdcccabee6e29786048c27395000f84694685b1ded8013785d6623cc18d214320b6bb6475994a20ef4e5e4e7e36258dbf51f4d905114cb1b34bc9413e39085dc88704f4394d35209a02b1a9520320c86048c27395000f8469478f3adfc719c99674c072166708589033e2d9afe9448a30d5eaa7b64492a160f139e2da2800ec3834e94055838358c29edf4dcc1ba1985ad58aedbb6be2b86048c27395000f84694c2be4ec20253b8642161bc3f444f53679c1f3d479466f50c616d737e60d7ca6311ff0d9c434197898a94d1d678a2506eeaa365056fe565df8bc8659f28b086048c27395000f846942f7be8361c80a4c1e7e9aaf001d0877f1cfde218945f93992ac37f3e61db2ef8a587a436a161fd210b94ecbc4fb1a97861344dad0867ca3cba2b860411f086048c27395000f84694ce2fd7544e0b2cc94692d4a704debef7bcb613289444abc67b4b2fba283c582387f54c9cba7c34bafa948acc2ab395ded08bb75ce85bf0f95ad2abc51ad586048c27395000f84694b8f7166496996a7da21cf1f1b04d9b3e26a3d077946770572763289aac606e4f327c2f6cc1aa3b3e3b94882d745ed97d4422ca8da1c22ec49d880c4c097286048c27395000f846942d4c407bbe49438ed859fe965b140dcf1aab71a9943ad0939e120f33518fbba04631afe7a3ed6327b194b2bbb170ca4e499a2b0f3cc85ebfa6e8c4dfcbea86048c27395000f846946bbad7cf34b5fa511d8e963dbba288b1960e75d694853b0f6c324d1f4e76c8266942337ac1b0af1a229442498946a51ca5924552ead6fc2af08b94fcba648601d1a94a2000f846944430b3230294d12c6ab2aac5c2cd68e80b16b581947b107f4976a252a6939b771202c28e64e03f52d694795811a7f214084116949fc4f53cedbf189eeab28601d1a94a2000f84694ea0a6e3c511bbd10f4519ece37dc24887e11b55d946811ca77acfb221a49393c193f3a22db829fcc8e9464feb7c04830dd9ace164fc5c52b3f5a29e5018a8601d1a94a2000f846947ae2f5b9e386cd1b50a4550696d957cb4900f03a94e83bcc5077e6b873995c24bac871b5ad856047e19464e48d4057a90b233e026c1041e6012ada897fe88601d1a94a2000f8469482012708dafc9e1b880fd083b32182b869be8e09948e5adc73a2d233a1b496ed3115464dd6c7b887509428b383d324bc9a37f4e276190796ba5a8947f5ed8601d1a94a2000f8469422b81f8e175ffde54d797fe11eb03f9e3bf75f1d94a1c3ef7ca38d8ba80cce3bfc53ebd2903ed21658942767f7447f7b9b70313d4147b795414aecea54718601d1a94a2000f8469468bf0b8b6fb4e317a0f9d6f03eaf8ce6675bc60d94675cfe570b7902623f47e7f59c9664b5f5065dcf94d84f0d2e50bcf00f2fc476e1c57f5ca2d57f625b8601d1a94a2000f846948c4d90829ce8f72d0163c1d5cf348a862d5506309485c42a7b34309bee2ed6a235f86d16f059deec5894cc2cedc53f0fa6d376336efb67e43d167169f3b78601d1a94a2000f8469435e7a025f4da968de7e4d7e4004197917f4070f194b1182abaeeb3b4d8eba7e6a4162eac7ace23d57394c4fd0d870da52e73de2dd8ded19fe3d26f43a1138601d1a94a2000f84694d6caa02bbebaebb5d7e581e4b66559e635f805ff94c07335cf083c1c46a487f0325769d88e163b653694efaff03b42e41f953a925fc43720e45fb61a19938601d1a94a20000175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbaa164736f6c6343000604000a";
uint32 public constant ERROR_UNKNOWN_PACKAGE_TYPE = 101;
uint32 public constant ERROR_FAIL_CHECK_VALIDATORS = 102;
uint32 public constant ERROR_LEN_OF_VAL_MISMATCH = 103;
uint32 public constant ERROR_RELAYFEE_TOO_LARGE = 104;
uint256 public constant INIT_NUM_OF_CABINETS = 21;
uint256 public constant EPOCH = 200;
/*----------------- state of the contract -----------------*/
Validator[] public currentValidatorSet;
uint256 public expireTimeSecondGap;
uint256 public totalInComing;
// key is the `consensusAddress` of `Validator`,
// value is the index of the element in `currentValidatorSet`.
mapping(address => uint256) public currentValidatorSetMap;
uint256 public numOfJailed;
uint256 public constant BLOCK_FEES_RATIO_SCALE = 10000;
address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;
uint256 public constant INIT_BURN_RATIO = 1000;
uint256 public burnRatio;
bool public burnRatioInitialized; // deprecated
// BEP-127 Temporary Maintenance
uint256 public constant INIT_MAX_NUM_OF_MAINTAINING = 3;
uint256 public constant INIT_MAINTAIN_SLASH_SCALE = 2;
uint256 public maxNumOfMaintaining;
uint256 public numOfMaintaining;
uint256 public maintainSlashScale;
// Corresponds strictly to currentValidatorSet
// validatorExtraSet[index] = the `ValidatorExtra` info of currentValidatorSet[index]
ValidatorExtra[] public validatorExtraSet;
// BEP-131 candidate validator
uint256 public numOfCabinets;
uint256 public maxNumOfCandidates;
uint256 public maxNumOfWorkingCandidates;
// BEP-126 Fast Finality
uint256 public constant INIT_SYSTEM_REWARD_RATIO = 625; // 625/10000 is 1/16
uint256 public constant MAX_SYSTEM_REWARD_BALANCE = 100 ether;
uint256 public systemRewardRatio;
uint256 public previousHeight;
uint256 public previousBalanceOfSystemReward; // deprecated
bytes[] public previousVoteAddrFullSet;
bytes[] public currentVoteAddrFullSet;
bool public isSystemRewardIncluded;
// BEP-294 BC-fusion
Validator[] private _tmpMigratedValidatorSet;
bytes[] private _tmpMigratedVoteAddrs;
struct Validator {
address consensusAddress;
address payable feeAddress;
address BBCFeeAddress;
uint64 votingPower;
// only in state
bool jailed;
uint256 incoming;
}
struct ValidatorExtra {
// BEP-127 Temporary Maintenance
uint256 enterMaintenanceHeight; // the height from where the validator enters Maintenance
bool isMaintaining;
// BEP-126 Fast Finality
bytes voteAddress;
// reserve for future use
uint256[19] slots;
}
/*----------------- cross chain package -----------------*/
struct IbcValidatorSetPackage {
uint8 packageType;
Validator[] validatorSet;
bytes[] voteAddrs;
}
/*----------------- modifiers -----------------*/
modifier noEmptyDeposit() {
require(msg.value > 0, "deposit value is zero");
_;
}
modifier initValidatorExtraSet() {
if (validatorExtraSet.length == 0) {
ValidatorExtra memory validatorExtra;
// init validatorExtraSet
uint256 validatorsNum = currentValidatorSet.length;
for (uint256 i; i < validatorsNum; ++i) {
validatorExtraSet.push(validatorExtra);
}
}
_;
}
modifier oncePerBlock() {
require(block.number > previousHeight, "can not do this twice in one block");
_;
previousHeight = block.number;
}
/*----------------- events -----------------*/
event validatorSetUpdated();
event validatorJailed(address indexed validator);
event validatorEmptyJailed(address indexed validator);
event batchTransfer(uint256 amount);
event batchTransferFailed(uint256 indexed amount, string reason);
event batchTransferLowerFailed(uint256 indexed amount, bytes reason);
event systemTransfer(uint256 amount);
event directTransfer(address payable indexed validator, uint256 amount);
event directTransferFail(address payable indexed validator, uint256 amount);
event deprecatedDeposit(address indexed validator, uint256 amount);
event validatorDeposit(address indexed validator, uint256 amount);
event validatorMisdemeanor(address indexed validator, uint256 amount);
event validatorFelony(address indexed validator, uint256 amount);
event failReasonWithStr(string message);
event unexpectedPackage(uint8 channelId, bytes msgBytes);
event paramChange(string key, bytes value);
event feeBurned(uint256 amount);
event validatorEnterMaintenance(address indexed validator);
event validatorExitMaintenance(address indexed validator);
event finalityRewardDeposit(address indexed validator, uint256 amount);
event deprecatedFinalityRewardDeposit(address indexed validator, uint256 amount);
event tmpValidatorSetUpdated(uint256 validatorsNum);
/*----------------- init -----------------*/
function init() external onlyNotInit {
(IbcValidatorSetPackage memory validatorSetPkg, bool valid) =
decodeValidatorSetSynPackage(INIT_VALIDATORSET_BYTES);
require(valid, "failed to parse init validatorSet");
for (uint256 i; i < validatorSetPkg.validatorSet.length; ++i) {
currentValidatorSet.push(validatorSetPkg.validatorSet[i]);
currentValidatorSetMap[validatorSetPkg.validatorSet[i].consensusAddress] = i + 1;
}
expireTimeSecondGap = EXPIRE_TIME_SECOND_GAP;
alreadyInit = true;
}
receive() external payable { }
/*----------------- Cross Chain App Implement -----------------*/
function handleSynPackage(
uint8,
bytes calldata msgBytes
) external override onlyInit onlyCrossChainContract initValidatorExtraSet returns (bytes memory responsePayload) {
(IbcValidatorSetPackage memory validatorSetPackage, bool ok) = decodeValidatorSetSynPackage(msgBytes);
if (!ok) {
return CmnPkg.encodeCommonAckPackage(ERROR_FAIL_DECODE);
}
uint32 resCode;
if (validatorSetPackage.packageType == VALIDATORS_UPDATE_MESSAGE_TYPE) {
resCode = updateValidatorSet(validatorSetPackage.validatorSet, validatorSetPackage.voteAddrs);
} else if (validatorSetPackage.packageType == JAIL_MESSAGE_TYPE) {
if (validatorSetPackage.validatorSet.length != 1) {
emit failReasonWithStr("length of jail validators must be one");
resCode = ERROR_LEN_OF_VAL_MISMATCH;
} else {
address validator = validatorSetPackage.validatorSet[0].consensusAddress;
uint256 index = currentValidatorSetMap[validator];
if (index == 0 || currentValidatorSet[index - 1].jailed) {
emit validatorEmptyJailed(validator);
} else {
// felony will failed if the validator is the only one in the validator set
bool success = _felony(validator, index - 1);
if (!success) {
emit validatorEmptyJailed(validator);
}
}
resCode = CODE_OK;
}
} else {
resCode = ERROR_UNKNOWN_PACKAGE_TYPE;
}
if (resCode == CODE_OK) {
return new bytes(0);
} else {
return CmnPkg.encodeCommonAckPackage(resCode);
}
}
function handleAckPackage(uint8 channelId, bytes calldata msgBytes) external override onlyCrossChainContract {
// should not happen
emit unexpectedPackage(channelId, msgBytes);
}
function handleFailAckPackage(uint8 channelId, bytes calldata msgBytes) external override onlyCrossChainContract {
// should not happen
emit unexpectedPackage(channelId, msgBytes);
}
/*----------------- External Functions -----------------*/
/**
* @dev Update validator set method after fusion fork.
*/
function updateValidatorSetV2(
address[] memory _consensusAddrs,
uint64[] memory _votingPowers,
bytes[] memory _voteAddrs
) public onlyCoinbase onlyZeroGasPrice {
uint256 _length = _consensusAddrs.length;
Validator[] memory _validatorSet = new Validator[](_length);
for (uint256 i; i < _length; ++i) {
_validatorSet[i] = Validator({
consensusAddress: _consensusAddrs[i],
feeAddress: payable(address(0)),
BBCFeeAddress: address(0),
votingPower: _votingPowers[i],
jailed: false,
incoming: 0
});
}
// if staking channel is not closed, store the migrated validator set and return
if (
ICrossChain(CROSS_CHAIN_CONTRACT_ADDR).registeredContractChannelMap(
VALIDATOR_CONTRACT_ADDR, STAKING_CHANNELID
)
) {
uint256 newLength = _validatorSet.length;
uint256 oldLength = _tmpMigratedValidatorSet.length;
if (oldLength > newLength) {
for (uint256 i = newLength; i < oldLength; ++i) {
_tmpMigratedValidatorSet.pop();
_tmpMigratedVoteAddrs.pop();
}
}
for (uint256 i; i < newLength; ++i) {
if (i >= oldLength) {
_tmpMigratedValidatorSet.push(_validatorSet[i]);
_tmpMigratedVoteAddrs.push(_voteAddrs[i]);
} else {
_tmpMigratedValidatorSet[i] = _validatorSet[i];
_tmpMigratedVoteAddrs[i] = _voteAddrs[i];
}
}
emit tmpValidatorSetUpdated(newLength);
return;
}
// step 0: force all maintaining validators to exit `Temporary Maintenance`
// - 1. validators exit maintenance
// - 2. clear all maintainInfo
// - 3. get unjailed validators from validatorSet
(Validator[] memory validatorSetTemp, bytes[] memory voteAddrsTemp) =
_forceMaintainingValidatorsExit(_validatorSet, _voteAddrs);
// step 1: distribute incoming
for (uint256 i; i < currentValidatorSet.length; ++i) {
uint256 incoming = currentValidatorSet[i].incoming;
if (incoming != 0) {
currentValidatorSet[i].incoming = 0;
IStakeHub(STAKE_HUB_ADDR).distributeReward{ value: incoming }(currentValidatorSet[i].consensusAddress);
}
}
// step 2: do dusk transfer
if (address(this).balance > 0) {
emit systemTransfer(address(this).balance);
address(uint160(SYSTEM_REWARD_ADDR)).transfer(address(this).balance);
}
// step 3: do update validator set state
totalInComing = 0;
numOfJailed = 0;
if (validatorSetTemp.length != 0) {
doUpdateState(validatorSetTemp, voteAddrsTemp);
}
// step 3: clean slash contract
ISlashIndicator(SLASH_CONTRACT_ADDR).clean();
emit validatorSetUpdated();
}
/**
* @dev Collect all fee of transactions from the current block and deposit it to the contract
*
* @param valAddr The validator address who produced the current block
*/
function deposit(address valAddr) external payable onlyCoinbase onlyInit noEmptyDeposit onlyZeroGasPrice {
uint256 value = msg.value;
uint256 index = currentValidatorSetMap[valAddr];
if (isSystemRewardIncluded == false) {
systemRewardRatio = INIT_SYSTEM_REWARD_RATIO;
burnRatio = INIT_BURN_RATIO;
isSystemRewardIncluded = true;
}
if (value > 0 && systemRewardRatio > 0) {
uint256 toSystemReward = msg.value.mul(systemRewardRatio).div(BLOCK_FEES_RATIO_SCALE);
if (toSystemReward > 0) {
address(uint160(SYSTEM_REWARD_ADDR)).transfer(toSystemReward);
emit systemTransfer(toSystemReward);
value = value.sub(toSystemReward);
}
}
if (value > 0 && burnRatio > 0) {
uint256 toBurn = msg.value.mul(burnRatio).div(BLOCK_FEES_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) {
emit deprecatedDeposit(valAddr, value);
} else {
totalInComing = totalInComing.add(value);
validator.incoming = validator.incoming.add(value);
emit validatorDeposit(valAddr, value);
}
} else {
// get incoming from deprecated validator;
emit deprecatedDeposit(valAddr, value);
}
}
function distributeFinalityReward(
address[] calldata valAddrs,
uint256[] calldata weights
) external onlyCoinbase oncePerBlock onlyZeroGasPrice onlyInit {
uint256 totalValue;
uint256 balanceOfSystemReward = address(SYSTEM_REWARD_ADDR).balance;
if (balanceOfSystemReward > MAX_SYSTEM_REWARD_BALANCE) {
// when a slash happens, theres will no rewards in some epochs,
// it's tolerated because slash happens rarely
totalValue = balanceOfSystemReward.sub(MAX_SYSTEM_REWARD_BALANCE);
} else {
return;
}
totalValue = ISystemReward(SYSTEM_REWARD_ADDR).claimRewards(payable(address(this)), totalValue);
if (totalValue == 0) {
return;
}
uint256 totalWeight;
for (uint256 i; i < weights.length; ++i) {
totalWeight += weights[i];
}
if (totalWeight == 0) {
return;
}
uint256 value;
address valAddr;
uint256 index;
for (uint256 i; i < valAddrs.length; ++i) {
value = (totalValue * weights[i]) / totalWeight;
valAddr = valAddrs[i];
index = currentValidatorSetMap[valAddr];
if (index > 0) {
Validator storage validator = currentValidatorSet[index - 1];
if (validator.jailed) {
emit deprecatedFinalityRewardDeposit(valAddr, value);
} else {
totalInComing = totalInComing.add(value);
validator.incoming = validator.incoming.add(value);
emit finalityRewardDeposit(valAddr, value);
}
} else {
// get incoming from deprecated validator;
emit deprecatedFinalityRewardDeposit(valAddr, value);
}
}
}
/*----------------- View Functions -----------------*/
/**
* @notice Return the vote address and consensus address of the validators in `currentValidatorSet` that are not jailed
*/
function getLivingValidators() external view override returns (address[] memory, bytes[] memory) {
uint256 n = currentValidatorSet.length;
uint256 living;
for (uint256 i; i < n; ++i) {
if (!currentValidatorSet[i].jailed) {
living++;
}
}
address[] memory consensusAddrs = new address[](living);
bytes[] memory voteAddrs = new bytes[](living);
living = 0;
if (validatorExtraSet.length == n) {
for (uint256 i; i < n; ++i) {
if (!currentValidatorSet[i].jailed) {
consensusAddrs[living] = currentValidatorSet[i].consensusAddress;
voteAddrs[living] = validatorExtraSet[i].voteAddress;
living++;
}
}
} else {
for (uint256 i; i < n; ++i) {
if (!currentValidatorSet[i].jailed) {
consensusAddrs[living] = currentValidatorSet[i].consensusAddress;
living++;
}
}
}
return (consensusAddrs, voteAddrs);
}
/**
* @notice Return the vote address and consensus address of mining validators
*
* Mining validators are block producers in the current epoch
* including most of the cabinets and a few of the candidates
*/
function getMiningValidators() external view override returns (address[] memory, bytes[] memory) {
uint256 _maxNumOfWorkingCandidates = maxNumOfWorkingCandidates;
uint256 _numOfCabinets = numOfCabinets > 0 ? numOfCabinets : INIT_NUM_OF_CABINETS;
address[] memory validators = getValidators();
bytes[] memory voteAddrs = getVoteAddresses(validators);
if (validators.length <= _numOfCabinets) {
return (validators, voteAddrs);
}
if ((validators.length - _numOfCabinets) < _maxNumOfWorkingCandidates) {
_maxNumOfWorkingCandidates = validators.length - _numOfCabinets;
}
if (_maxNumOfWorkingCandidates > 0) {
uint256 epochNumber = block.number / EPOCH;
shuffle(
validators,
voteAddrs,
epochNumber,
_numOfCabinets - _maxNumOfWorkingCandidates,
0,
_maxNumOfWorkingCandidates,
_numOfCabinets
);
shuffle(
validators,
voteAddrs,
epochNumber,
_numOfCabinets - _maxNumOfWorkingCandidates,
_numOfCabinets - _maxNumOfWorkingCandidates,
_maxNumOfWorkingCandidates,
validators.length - _numOfCabinets + _maxNumOfWorkingCandidates
);
}
address[] memory miningValidators = new address[](_numOfCabinets);
bytes[] memory miningVoteAddrs = new bytes[](_numOfCabinets);
for (uint256 i; i < _numOfCabinets; ++i) {
miningValidators[i] = validators[i];
miningVoteAddrs[i] = voteAddrs[i];
}
return (miningValidators, miningVoteAddrs);
}
/**
* @notice Return the consensus address of the validators in `currentValidatorSet` that are not jailed and not maintaining
*/
function getValidators() public view returns (address[] memory) {
uint256 n = currentValidatorSet.length;
uint256 valid = 0;
for (uint256 i; i < n; ++i) {
if (isWorkingValidator(i)) {
++valid;
}
}
address[] memory consensusAddrs = new address[](valid);
valid = 0;
for (uint256 i; i < n; ++i) {
if (isWorkingValidator(i)) {
consensusAddrs[valid] = currentValidatorSet[i].consensusAddress;
++valid;
}
}
return consensusAddrs;
}
/**
* @notice Return the current incoming of the validator
*/
function getIncoming(address validator) external view returns (uint256) {
uint256 index = currentValidatorSetMap[validator];
if (index <= 0) {
return 0;
}
return currentValidatorSet[index - 1].incoming;
}
/**
* @notice Return whether the validator is a working validator(not jailed or maintaining) by index
*
* @param index The index of the validator in `currentValidatorSet`(from 0 to `currentValidatorSet.length-1`)
*/
function isWorkingValidator(uint256 index) public view returns (bool) {
if (index >= currentValidatorSet.length) {
return false;
}
// validatorExtraSet[index] should not be used before it has been init.
if (index >= validatorExtraSet.length) {
return !currentValidatorSet[index].jailed;
}
return !currentValidatorSet[index].jailed && !validatorExtraSet[index].isMaintaining;
}
/**
* @notice Return whether the validator is a working validator(not jailed or maintaining) by consensus address
* Will return false if the validator is not in `currentValidatorSet`
*/
function isCurrentValidator(address validator) external view override returns (bool) {
uint256 index = currentValidatorSetMap[validator];
if (index <= 0) {
return false;
}
// the actual index
index = index - 1;
return isWorkingValidator(index);
}
/**
* @notice Return the index of the validator in `currentValidatorSet`(from 0 to `currentValidatorSet.length-1`)
*/
function getCurrentValidatorIndex(address validator) public view returns (uint256) {
uint256 index = currentValidatorSetMap[validator];
require(index > 0, "only current validators");
// the actual index
return index - 1;
}
/**
* @notice Return the number of mining validators.
* The function name is misleading, it should be `getMiningValidatorCount`. But it's kept for compatibility.
*/
function getWorkingValidatorCount() public view returns (uint256 workingValidatorCount) {
workingValidatorCount = getValidators().length;
uint256 _numOfCabinets = numOfCabinets > 0 ? numOfCabinets : INIT_NUM_OF_CABINETS;
if (workingValidatorCount > _numOfCabinets) {
workingValidatorCount = _numOfCabinets;
}
if (workingValidatorCount == 0) {
workingValidatorCount = 1;
}
}
/*----------------- For slash -----------------*/
function misdemeanor(address validator) external override onlySlash initValidatorExtraSet {
uint256 validatorIndex = _misdemeanor(validator);
if (canEnterMaintenance(validatorIndex)) {
_enterMaintenance(validator, validatorIndex);
}
}
function felony(address validator) external override initValidatorExtraSet {
require(msg.sender == SLASH_CONTRACT_ADDR || msg.sender == STAKE_HUB_ADDR, "only slash or stakeHub contract");
uint256 index = currentValidatorSetMap[validator];
if (index <= 0) {
return;
}
// the actual index
index = index - 1;
bool isMaintaining = validatorExtraSet[index].isMaintaining;
if (_felony(validator, index) && isMaintaining) {
--numOfMaintaining;
}
}
function removeTmpMigratedValidator(address validator) external onlyStakeHub {
for (uint256 i; i < _tmpMigratedValidatorSet.length; ++i) {
if (_tmpMigratedValidatorSet[i].consensusAddress == validator) {
_tmpMigratedValidatorSet[i].jailed = true;
break;
}
}
}
/*----------------- For Temporary Maintenance -----------------*/
/**
* @notice Return whether the validator at index could enter maintenance
*/
function canEnterMaintenance(uint256 index) public view returns (bool) {
if (index >= currentValidatorSet.length) {
return false;
}
if (
currentValidatorSet[index].consensusAddress == address(0) // - 0. check if empty validator
|| (maxNumOfMaintaining == 0 || maintainSlashScale == 0) // - 1. check if not start
|| numOfMaintaining >= maxNumOfMaintaining // - 2. check if reached upper limit
|| !isWorkingValidator(index) // - 3. check if not working(not jailed and not maintaining)
|| validatorExtraSet[index].enterMaintenanceHeight > 0 // - 5. check if has Maintained during current 24-hour period
// current validators are selected every 24 hours(from 00:00:00 UTC to 23:59:59 UTC)
|| getValidators().length <= 1 // - 6. check num of remaining working validators
) {
return false;
}
return true;
}
/**
* @dev Enter maintenance for current validators. refer to https://github.com/bnb-chain/BEPs/blob/master/BEP127.md
*/
function enterMaintenance() external initValidatorExtraSet {
// check maintain config
if (maxNumOfMaintaining == 0) {
maxNumOfMaintaining = INIT_MAX_NUM_OF_MAINTAINING;
}
if (maintainSlashScale == 0) {
maintainSlashScale = INIT_MAINTAIN_SLASH_SCALE;
}
uint256 index = getCurrentValidatorIndex(msg.sender);
require(canEnterMaintenance(index), "can not enter Temporary Maintenance");
_enterMaintenance(msg.sender, index);
}
/**
* @dev Exit maintenance for current validators. refer to https://github.com/bnb-chain/BEPs/blob/master/BEP127.md
*/
function exitMaintenance() external {
uint256 index = getCurrentValidatorIndex(msg.sender);
// jailed validators are allowed to exit maintenance
require(validatorExtraSet[index].isMaintaining, "not in maintenance");
uint256 miningValidatorCount = getWorkingValidatorCount();
_exitMaintenance(msg.sender, index, miningValidatorCount);
}
/*----------------- Param update -----------------*/
function updateParam(string calldata key, bytes calldata value) external override onlyInit onlyGov {
if (Memory.compareStrings(key, "expireTimeSecondGap")) {
require(value.length == 32, "length of expireTimeSecondGap mismatch");
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.add(systemRewardRatio) <= BLOCK_FEES_RATIO_SCALE,
"the burnRatio plus systemRewardRatio must be no greater than 10000"
);
burnRatio = newBurnRatio;
} else if (Memory.compareStrings(key, "maxNumOfMaintaining")) {
require(value.length == 32, "length of maxNumOfMaintaining mismatch");
uint256 newMaxNumOfMaintaining = BytesToTypes.bytesToUint256(32, value);
uint256 _numOfCabinets = numOfCabinets;
if (_numOfCabinets == 0) {
_numOfCabinets = INIT_NUM_OF_CABINETS;
}
require(newMaxNumOfMaintaining < _numOfCabinets, "the maxNumOfMaintaining must be less than numOfCabinets");
maxNumOfMaintaining = newMaxNumOfMaintaining;
} else if (Memory.compareStrings(key, "maintainSlashScale")) {
require(value.length == 32, "length of maintainSlashScale mismatch");
uint256 newMaintainSlashScale = BytesToTypes.bytesToUint256(32, value);
require(
newMaintainSlashScale > 0 && newMaintainSlashScale < 10,
"the maintainSlashScale must be greater than 0 and less than 10"
);
maintainSlashScale = newMaintainSlashScale;
} else if (Memory.compareStrings(key, "maxNumOfWorkingCandidates")) {
require(value.length == 32, "length of maxNumOfWorkingCandidates mismatch");
uint256 newMaxNumOfWorkingCandidates = BytesToTypes.bytesToUint256(32, value);
require(
newMaxNumOfWorkingCandidates <= maxNumOfCandidates,
"the maxNumOfWorkingCandidates must be not greater than maxNumOfCandidates"
);
maxNumOfWorkingCandidates = newMaxNumOfWorkingCandidates;
} else if (Memory.compareStrings(key, "maxNumOfCandidates")) {
require(value.length == 32, "length of maxNumOfCandidates mismatch");
uint256 newMaxNumOfCandidates = BytesToTypes.bytesToUint256(32, value);
maxNumOfCandidates = newMaxNumOfCandidates;
if (maxNumOfWorkingCandidates > maxNumOfCandidates) {
maxNumOfWorkingCandidates = maxNumOfCandidates;
}
} else if (Memory.compareStrings(key, "numOfCabinets")) {
require(value.length == 32, "length of numOfCabinets mismatch");
uint256 newNumOfCabinets = BytesToTypes.bytesToUint256(32, value);
require(newNumOfCabinets > 0, "the numOfCabinets must be greater than 0");
require(
newNumOfCabinets <= MAX_NUM_OF_VALIDATORS, "the numOfCabinets must be less than MAX_NUM_OF_VALIDATORS"
);
numOfCabinets = newNumOfCabinets;
} else if (Memory.compareStrings(key, "systemRewardRatio")) {
require(value.length == 32, "length of systemRewardRatio mismatch");
uint256 newSystemRewardRatio = BytesToTypes.bytesToUint256(32, value);
require(
newSystemRewardRatio.add(burnRatio) <= BLOCK_FEES_RATIO_SCALE,
"the systemRewardRatio plus burnRatio must be no greater than 10000"
);
systemRewardRatio = newSystemRewardRatio;
} else {
require(false, "unknown param");
}
emit paramChange(key, value);
}
/*----------------- Internal Functions -----------------*/
function updateValidatorSet(Validator[] memory validatorSet, bytes[] memory voteAddrs) internal returns (uint32) {
{
// do verify.
if (validatorSet.length > MAX_NUM_OF_VALIDATORS) {
emit failReasonWithStr("the number of validators exceed the limit");
return ERROR_FAIL_CHECK_VALIDATORS;
}
for (uint256 i; i < validatorSet.length; ++i) {
for (uint256 j; j < i; ++j) {
if (validatorSet[i].consensusAddress == validatorSet[j].consensusAddress) {
emit failReasonWithStr("duplicate consensus address of validatorSet");
return ERROR_FAIL_CHECK_VALIDATORS;
}
}
}
}
// step 0: force all maintaining validators to exit `Temporary Maintenance`
// - 1. validators exit maintenance
// - 2. clear all maintainInfo
// - 3. get unjailed validators from validatorSet
Validator[] memory validatorSetTemp;
bytes[] memory voteAddrsTemp;
{
// get migrated validators
Validator[] memory bscValidatorSet = _tmpMigratedValidatorSet;
bytes[] memory bscVoteAddrs = _tmpMigratedVoteAddrs;
for (uint256 i; i < bscValidatorSet.length; ++i) {
bscValidatorSet[i].votingPower = bscValidatorSet[i].votingPower * 3; // amplify the voting power for BSC validators
}
(Validator[] memory mergedValidators, bytes[] memory mergedVoteAddrs) =
_mergeValidatorSet(validatorSet, voteAddrs, bscValidatorSet, bscVoteAddrs);
(validatorSetTemp, voteAddrsTemp) = _forceMaintainingValidatorsExit(mergedValidators, mergedVoteAddrs);
}
{
//step 1: do calculate distribution, do not make it as an internal function for saving gas.
uint256 crossSize;
uint256 directSize;
uint256 validatorsNum = currentValidatorSet.length;
uint8[] memory isMigrated = new uint8[](validatorsNum);
for (uint256 i; i < validatorsNum; ++i) {
if (
IStakeHub(STAKE_HUB_ADDR).consensusToOperator(currentValidatorSet[i].consensusAddress) != address(0)
) {
isMigrated[i] = 1;
if (currentValidatorSet[i].incoming != 0) {
++directSize;
}
} else if (currentValidatorSet[i].incoming >= DUSTY_INCOMING) {
++crossSize;
} else if (currentValidatorSet[i].incoming != 0) {
++directSize;
}
}
//cross transfer
address[] memory crossAddrs = new address[](crossSize);
uint256[] memory crossAmounts = new uint256[](crossSize);
uint256[] memory crossIndexes = new uint256[](crossSize);
address[] memory crossRefundAddrs = new address[](crossSize);
uint256 crossTotal;
// direct transfer
address payable[] memory directAddrs = new address payable[](directSize);
uint256[] memory directAmounts = new uint256[](directSize);
crossSize = 0;
directSize = 0;
uint256 relayFee = ITokenHub(TOKEN_HUB_ADDR).getMiniRelayFee();
if (relayFee > DUSTY_INCOMING) {
emit failReasonWithStr("fee is larger than DUSTY_INCOMING");
return ERROR_RELAYFEE_TOO_LARGE;
}
for (uint256 i; i < validatorsNum; ++i) {
if (isMigrated[i] == 1) {
if (currentValidatorSet[i].incoming != 0) {
directAddrs[directSize] = payable(currentValidatorSet[i].consensusAddress);
directAmounts[directSize] = currentValidatorSet[i].incoming;
isMigrated[directSize] = 1; // directSize must be less than i. so we can use directSize as index
++directSize;
}
} else if (currentValidatorSet[i].incoming >= DUSTY_INCOMING) {
crossAddrs[crossSize] = currentValidatorSet[i].BBCFeeAddress;
uint256 value = currentValidatorSet[i].incoming - currentValidatorSet[i].incoming % PRECISION;
crossAmounts[crossSize] = value.sub(relayFee);
crossRefundAddrs[crossSize] = currentValidatorSet[i].feeAddress;
crossIndexes[crossSize] = i;
crossTotal = crossTotal.add(value);
++crossSize;
} else if (currentValidatorSet[i].incoming != 0) {
directAddrs[directSize] = currentValidatorSet[i].feeAddress;
directAmounts[directSize] = currentValidatorSet[i].incoming;
isMigrated[directSize] = 0;
++directSize;
}
}
//step 2: do cross chain transfer
bool failCross = false;
if (crossTotal > 0) {
try ITokenHub(TOKEN_HUB_ADDR).batchTransferOutBNB{ value: crossTotal }(
crossAddrs, crossAmounts, crossRefundAddrs, uint64(block.timestamp + expireTimeSecondGap)
) returns (bool success) {
if (success) {
emit batchTransfer(crossTotal);
} else {
emit batchTransferFailed(crossTotal, "batch transfer return false");
}
} catch Error(string memory reason) {
failCross = true;
emit batchTransferFailed(crossTotal, reason);
} catch (bytes memory lowLevelData) {
failCross = true;
emit batchTransferLowerFailed(crossTotal, lowLevelData);
}
}
if (failCross) {
for (uint256 i; i < crossIndexes.length; ++i) {
uint256 idx = crossIndexes[i];
bool success = currentValidatorSet[idx].feeAddress.send(currentValidatorSet[idx].incoming);
if (success) {
emit directTransfer(currentValidatorSet[idx].feeAddress, currentValidatorSet[idx].incoming);
} else {
emit directTransferFail(currentValidatorSet[idx].feeAddress, currentValidatorSet[idx].incoming);
}
}
}
// step 3: direct transfer
if (directAddrs.length > 0) {
for (uint256 i; i < directAddrs.length; ++i) {
if (isMigrated[i] == 1) {
IStakeHub(STAKE_HUB_ADDR).distributeReward{ value: directAmounts[i] }(directAddrs[i]);
} else {
bool success = directAddrs[i].send(directAmounts[i]);
if (success) {
emit directTransfer(directAddrs[i], directAmounts[i]);
} else {
emit directTransferFail(directAddrs[i], directAmounts[i]);
}
}
}
}
}
for (uint256 i; i < currentValidatorSet.length; ++i) {
if (currentValidatorSet[i].incoming != 0) {
currentValidatorSet[i].incoming = 0;
}
}
// step 4: do dusk transfer
if (address(this).balance > 0) {
emit systemTransfer(address(this).balance);
address(uint160(SYSTEM_REWARD_ADDR)).transfer(address(this).balance);
}
// step 5: do update validator set state
totalInComing = 0;
numOfJailed = 0;
if (validatorSetTemp.length > 0) {
doUpdateState(validatorSetTemp, voteAddrsTemp);
}
// step 6: clean slash contract
ISlashIndicator(SLASH_CONTRACT_ADDR).clean();
emit validatorSetUpdated();
return CODE_OK;
}
function doUpdateState(Validator[] memory newValidatorSet, bytes[] memory newVoteAddrs) private {
uint256 n = currentValidatorSet.length;
uint256 m = newValidatorSet.length;
// delete stale validators
for (uint256 i; i < n; ++i) {
bool stale = true;
Validator memory oldValidator = currentValidatorSet[i];
for (uint256 j; j < m; ++j) {
if (oldValidator.consensusAddress == newValidatorSet[j].consensusAddress) {
stale = false;
break;
}
}
if (stale) {
delete currentValidatorSetMap[oldValidator.consensusAddress];
}
}
// if old validator set is larger than new validator set, pop the extra validators
if (n > m) {
for (uint256 i = m; i < n; ++i) {
currentValidatorSet.pop();
validatorExtraSet.pop();
}
}
uint256 k = n < m ? n : m;
for (uint256 i; i < k; ++i) {
// if the validator is not the same, update the validator set directly
if (!isSameValidator(newValidatorSet[i], currentValidatorSet[i])) {
currentValidatorSetMap[newValidatorSet[i].consensusAddress] = i + 1;
currentValidatorSet[i] = newValidatorSet[i];
validatorExtraSet[i].voteAddress = newVoteAddrs[i];
validatorExtraSet[i].isMaintaining = false;
validatorExtraSet[i].enterMaintenanceHeight = 0;
} else {
currentValidatorSet[i].votingPower = newValidatorSet[i].votingPower;
// update the vote address if it is different
if (!BytesLib.equal(newVoteAddrs[i], validatorExtraSet[i].voteAddress)) {
validatorExtraSet[i].voteAddress = newVoteAddrs[i];
}
}
}
if (m > n) {
ValidatorExtra memory _validatorExtra;
for (uint256 i = n; i < m; ++i) {
_validatorExtra.voteAddress = newVoteAddrs[i];
currentValidatorSet.push(newValidatorSet[i]);
validatorExtraSet.push(_validatorExtra);
currentValidatorSetMap[newValidatorSet[i].consensusAddress] = i + 1;
}
}
// update vote addr full set
setPreviousVoteAddrFullSet();
setCurrentVoteAddrFullSet();
// make sure all new validators are cleared maintainInfo
// should not happen, still protect
numOfMaintaining = 0;
n = currentValidatorSet.length;
for (uint256 i; i < n; ++i) {
validatorExtraSet[i].isMaintaining = false;
validatorExtraSet[i].enterMaintenanceHeight = 0;
}
}
/**
* @dev With each epoch, there will be a partial rotation between cabinets and candidates. Rotation is determined by this function
*/
function shuffle(
address[] memory validators,
bytes[] memory voteAddrs,
uint256 epochNumber,
uint256 startIdx,
uint256 offset,
uint256 limit,
uint256 modNumber
) internal pure {
for (uint256 i; i < limit; ++i) {
uint256 random = uint256(keccak256(abi.encodePacked(epochNumber, startIdx + i))) % modNumber;
if ((startIdx + i) != (offset + random)) {
address tmpAddr = validators[startIdx + i];
bytes memory tmpBLS = voteAddrs[startIdx + i];
validators[startIdx + i] = validators[offset + random];
validators[offset + random] = tmpAddr;
voteAddrs[startIdx + i] = voteAddrs[offset + random];
voteAddrs[offset + random] = tmpBLS;
}
}
}
/**
* @dev Check if two validators are the same
*
* Vote address is not considered
*/
function isSameValidator(Validator memory v1, Validator memory v2) private pure returns (bool) {
return v1.consensusAddress == v2.consensusAddress && v1.feeAddress == v2.feeAddress
&& v1.BBCFeeAddress == v2.BBCFeeAddress;
}
function getVoteAddresses(address[] memory validators) internal view returns (bytes[] memory) {
uint256 n = currentValidatorSet.length;
uint256 length = validators.length;
bytes[] memory voteAddrs = new bytes[](length);
// check if validatorExtraSet has been initialized
if (validatorExtraSet.length != n) {
return voteAddrs;
}
for (uint256 i; i < length; ++i) {
voteAddrs[i] = validatorExtraSet[currentValidatorSetMap[validators[i]] - 1].voteAddress;
}
return voteAddrs;
}
function setPreviousVoteAddrFullSet() private {
uint256 n = previousVoteAddrFullSet.length;
uint256 m = currentVoteAddrFullSet.length;
if (n > m) {
for (uint256 i = m; i < n; ++i) {
previousVoteAddrFullSet.pop();
}
}
uint256 k = n < m ? n : m;
for (uint256 i; i < k; ++i) {
if (!BytesLib.equal(previousVoteAddrFullSet[i], currentVoteAddrFullSet[i])) {
previousVoteAddrFullSet[i] = currentVoteAddrFullSet[i];
}
}
if (m > n) {
for (uint256 i = n; i < m; ++i) {
previousVoteAddrFullSet.push(currentVoteAddrFullSet[i]);
}
}
}
function setCurrentVoteAddrFullSet() private {
uint256 n = currentVoteAddrFullSet.length;
uint256 m = validatorExtraSet.length;
if (n > m) {
for (uint256 i = m; i < n; ++i) {
currentVoteAddrFullSet.pop();
}
}
uint256 k = n < m ? n : m;
for (uint256 i; i < k; ++i) {
if (!BytesLib.equal(currentVoteAddrFullSet[i], validatorExtraSet[i].voteAddress)) {
currentVoteAddrFullSet[i] = validatorExtraSet[i].voteAddress;
}
}
if (m > n) {
for (uint256 i = n; i < m; ++i) {
currentVoteAddrFullSet.push(validatorExtraSet[i].voteAddress);
}
}
}
function isMonitoredForMaliciousVote(bytes calldata voteAddr) external view override returns (bool) {
uint256 m = currentVoteAddrFullSet.length;
for (uint256 i; i < m; ++i) {
if (BytesLib.equal(voteAddr, currentVoteAddrFullSet[i])) {
return true;
}
}
uint256 n = previousVoteAddrFullSet.length;
for (uint256 i; i < n; ++i) {
if (BytesLib.equal(voteAddr, previousVoteAddrFullSet[i])) {
return true;
}
}
return false;
}
function _misdemeanor(address validator) private returns (uint256) {
uint256 index = currentValidatorSetMap[validator];
if (index <= 0) {
return ~uint256(0);
}
// the actually index
index = index - 1;
uint256 income = currentValidatorSet[index].incoming;
currentValidatorSet[index].incoming = 0;
uint256 rest = currentValidatorSet.length - 1;
emit validatorMisdemeanor(validator, income);
if (rest == 0) {
// should not happen, but still protect
return index;
}
// averageDistribute*rest may less than income, but it is ok, the dust income will go to system reward eventually.
uint256 averageDistribute = income / rest;
if (averageDistribute != 0) {
for (uint256 i; i < index; ++i) {
currentValidatorSet[i].incoming = currentValidatorSet[i].incoming.add(averageDistribute);
}
uint256 n = currentValidatorSet.length;
for (uint256 i = index + 1; i < n; ++i) {
currentValidatorSet[i].incoming = currentValidatorSet[i].incoming.add(averageDistribute);
}
}
return index;
}
function _felony(address validator, uint256 index) private returns (bool) {
uint256 income = currentValidatorSet[index].incoming;
uint256 rest = currentValidatorSet.length - 1;
if (getValidators().length <= 1) {
// will not remove the validator if it is the only one validator.
currentValidatorSet[index].incoming = 0;
return false;
}
emit validatorFelony(validator, income);
// remove the validator from currentValidatorSet
delete currentValidatorSetMap[validator];
// remove felony validator
for (uint256 i = index; i < (currentValidatorSet.length - 1); ++i) {
currentValidatorSet[i] = currentValidatorSet[i + 1];
validatorExtraSet[i] = validatorExtraSet[i + 1];
currentValidatorSetMap[currentValidatorSet[i].consensusAddress] = i + 1;
}
currentValidatorSet.pop();
validatorExtraSet.pop();
// averageDistribute*rest may less than income, but it is ok, the dust income will go to system reward eventually.
uint256 averageDistribute = income / rest;
if (averageDistribute != 0) {
uint256 n = currentValidatorSet.length;
for (uint256 i; i < n; ++i) {
currentValidatorSet[i].incoming = currentValidatorSet[i].incoming.add(averageDistribute);
}
}
return true;
}
function _forceMaintainingValidatorsExit(
Validator[] memory _validatorSet,
bytes[] memory _voteAddrs
) private returns (Validator[] memory unjailedValidatorSet, bytes[] memory unjailedVoteAddrs) {
uint256 numOfFelony = 0;
address validator;
bool isFelony;
// 1. validators exit maintenance
uint256 i;
// caution: it must calculate miningValidatorCount before _exitMaintenance loop
// because the miningValidatorCount will be changed in _exitMaintenance
uint256 miningValidatorCount = getWorkingValidatorCount();
// caution: it must loop from the endIndex to startIndex in currentValidatorSet
// because the validators order in currentValidatorSet may be changed by _felony(validator)
for (uint256 index = currentValidatorSet.length; index > 0; --index) {
i = index - 1; // the actual index
if (!validatorExtraSet[i].isMaintaining) {
continue;
}
// only maintaining validators
validator = currentValidatorSet[i].consensusAddress;
// exit maintenance
isFelony = _exitMaintenance(validator, i, miningValidatorCount);
if (!isFelony) {
continue;
}
// get the latest consensus address
address latestConsensusAddress;
address operatorAddress = IStakeHub(STAKE_HUB_ADDR).consensusToOperator(validator);
if (operatorAddress != address(0)) {
latestConsensusAddress = IStakeHub(STAKE_HUB_ADDR).getValidatorConsensusAddress(operatorAddress);
}
// record the jailed validator in validatorSet
for (uint256 j; j < _validatorSet.length; ++j) {
if (
_validatorSet[j].consensusAddress == validator
|| _validatorSet[j].consensusAddress == latestConsensusAddress
) {
_validatorSet[j].jailed = true;
break;
}
}
}
// count the number of felony validators
for (uint256 k; k < _validatorSet.length; ++k) {
if (_validatorSet[k].jailed || _validatorSet[k].consensusAddress == address(0)) {
++numOfFelony;
}
}
// 2. get unjailed validators from validatorSet
if (numOfFelony >= _validatorSet.length) {
// make sure there is at least one validator
unjailedValidatorSet = new Validator[](1);
unjailedVoteAddrs = new bytes[](1);
unjailedValidatorSet[0] = _validatorSet[0];
unjailedVoteAddrs[0] = _voteAddrs[0];
unjailedValidatorSet[0].jailed = false;
} else {
unjailedValidatorSet = new Validator[](_validatorSet.length - numOfFelony);
unjailedVoteAddrs = new bytes[](_validatorSet.length - numOfFelony);
i = 0;
for (uint256 index; index < _validatorSet.length; ++index) {
if (!_validatorSet[index].jailed && _validatorSet[index].consensusAddress != address(0)) {
unjailedValidatorSet[i] = _validatorSet[index];
unjailedVoteAddrs[i] = _voteAddrs[index];
++i;
}
}
}
return (unjailedValidatorSet, unjailedVoteAddrs);
}
function _enterMaintenance(address validator, uint256 index) private {
++numOfMaintaining;
validatorExtraSet[index].isMaintaining = true;
validatorExtraSet[index].enterMaintenanceHeight = block.number;
emit validatorEnterMaintenance(validator);
}
function _exitMaintenance(
address validator,
uint256 index,
uint256 miningValidatorCount
) private returns (bool isFelony) {
if (maintainSlashScale == 0 || miningValidatorCount == 0 || numOfMaintaining == 0) {
// should not happen, still protect
return false;
}
// step 1: calculate slashCount
uint256 slashCount = block.number.sub(validatorExtraSet[index].enterMaintenanceHeight).div(miningValidatorCount)
.div(maintainSlashScale);
// step2: slash the validator
(uint256 misdemeanorThreshold, uint256 felonyThreshold) =
ISlashIndicator(SLASH_CONTRACT_ADDR).getSlashThresholds();
isFelony = false;
if (slashCount >= felonyThreshold) {
_felony(validator, index);
if (IStakeHub(STAKE_HUB_ADDR).consensusToOperator(validator) != address(0)) {
ISlashIndicator(SLASH_CONTRACT_ADDR).downtimeSlash(validator, slashCount);
} else {
ISlashIndicator(SLASH_CONTRACT_ADDR).sendFelonyPackage(validator);
}
isFelony = true;
} else if (slashCount >= misdemeanorThreshold) {
_misdemeanor(validator);
}
// step 3: modify global storage
--numOfMaintaining;
validatorExtraSet[index].isMaintaining = false;
emit validatorExitMaintenance(validator);
}
function _mergeValidatorSet(
Validator[] memory validatorSet1,
bytes[] memory voteAddrSet1,
Validator[] memory validatorSet2,
bytes[] memory voteAddrSet2
) internal view returns (Validator[] memory, bytes[] memory) {
uint256 _length = IStakeHub(STAKE_HUB_ADDR).maxElectedValidators();
if (validatorSet1.length + validatorSet2.length < _length) {
_length = validatorSet1.length + validatorSet2.length;
}
Validator[] memory mergedValidatorSet = new Validator[](_length);
bytes[] memory mergedVoteAddrSet = new bytes[](_length);
uint256 i;
uint256 j;
uint256 k;
while ((i < validatorSet1.length || j < validatorSet2.length) && k < _length) {
if (i == validatorSet1.length) {
mergedValidatorSet[k] = validatorSet2[j];
mergedVoteAddrSet[k] = voteAddrSet2[j];
++j;
++k;
continue;
}
if (j == validatorSet2.length) {
mergedValidatorSet[k] = validatorSet1[i];
mergedVoteAddrSet[k] = voteAddrSet1[i];
++i;
++k;
continue;
}
if (validatorSet1[i].votingPower > validatorSet2[j].votingPower) {
mergedValidatorSet[k] = validatorSet1[i];
mergedVoteAddrSet[k] = voteAddrSet1[i];
++i;
} else if (validatorSet1[i].votingPower < validatorSet2[j].votingPower) {
mergedValidatorSet[k] = validatorSet2[j];
mergedVoteAddrSet[k] = voteAddrSet2[j];
++j;
} else {
if (validatorSet1[i].consensusAddress < validatorSet2[j].consensusAddress) {
mergedValidatorSet[k] = validatorSet1[i];
mergedVoteAddrSet[k] = voteAddrSet1[i];
++i;
} else {
mergedValidatorSet[k] = validatorSet2[j];
mergedVoteAddrSet[k] = voteAddrSet2[j];
++j;
}
}
++k;
}
return (mergedValidatorSet, mergedVoteAddrSet);
}
//rlp encode & decode function
function decodeValidatorSetSynPackage(bytes memory msgBytes)
internal
pure
returns (IbcValidatorSetPackage memory, bool)
{
IbcValidatorSetPackage memory validatorSetPkg;
RLPDecode.Iterator memory iter = msgBytes.toRLPItem().iterator();
bool success = false;
uint256 idx = 0;
while (iter.hasNext()) {
if (idx == 0) {
validatorSetPkg.packageType = uint8(iter.next().toUint());
} else if (idx == 1) {
RLPDecode.RLPItem[] memory items = iter.next().toList();
validatorSetPkg.validatorSet = new Validator[](items.length);
validatorSetPkg.voteAddrs = new bytes[](items.length);
for (uint256 j; j < items.length; ++j) {
(Validator memory val, bytes memory voteAddr, bool ok) = decodeValidator(items[j]);
if (!ok) {
return (validatorSetPkg, false);
}
validatorSetPkg.validatorSet[j] = val;
validatorSetPkg.voteAddrs[j] = voteAddr;
}
success = true;
} else {
break;
}
++idx;
}
return (validatorSetPkg, success);
}
function decodeValidator(RLPDecode.RLPItem memory itemValidator)
internal
pure
returns (Validator memory, bytes memory, bool)
{
Validator memory validator;
bytes memory voteAddr;
RLPDecode.Iterator memory iter = itemValidator.iterator();
bool success = false;
uint256 idx = 0;
while (iter.hasNext()) {
if (idx == 0) {
validator.consensusAddress = iter.next().toAddress();
} else if (idx == 1) {
validator.feeAddress = address(uint160(iter.next().toAddress()));
} else if (idx == 2) {
validator.BBCFeeAddress = iter.next().toAddress();
} else if (idx == 3) {
validator.votingPower = uint64(iter.next().toUint());
success = true;
} else if (idx == 4) {
voteAddr = iter.next().toBytes();
} else {
break;
}
++idx;
}
return (validator, voteAddr, success);
}
}