Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
- Contract name:
- Asset
- Optimization enabled
- true
- Compiler version
- v0.8.9+commit.e5eed63a
- Optimization runs
- 200
- EVM Version
- london
- Verified at
- 2022-09-18T10:53:01.988890Z
Constructor Arguments
0x000000000000000000000000000000009b180ab66abe3dc0a13f04169eb34bfa000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000065553442f2f43000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000
Arg [0] (uint128) : 206155171747923808840527191840316935162
Arg [1] (string) : USD//C
Arg [2] (string) : USDC
contracts/Asset.sol
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; import {IRegistry, Registrable} from "./Registrable.sol"; interface IERC20 { function balanceOf(address who) external view returns (uint256); function transfer(address to, uint256 value) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function transferFrom( address from, address to, uint256 value ) external returns (bool); function approve(address spender, uint256 value) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval( address indexed owner, address indexed spender, uint256 value ); } abstract contract StandardToken is IERC20 { mapping(address => uint256) balances; mapping(address => mapping(address => uint256)) allowed; function balanceOf(address _owner) public view override returns (uint256 balance) { return balances[_owner]; } function _transfer( address _from, address _to, uint256 _value ) internal { balances[_from] = balances[_from] - _value; balances[_to] = balances[_to] + _value; emit Transfer(_from, _to, _value); } function _transferFrom( address _from, address _to, uint256 _value ) internal { uint256 _allowance = allowed[_from][msg.sender]; allowed[_from][msg.sender] = _allowance - _value; _transfer(_from, _to, _value); } function approve(address _spender, uint256 _value) public override returns (bool) { // To change the approve amount you first have to reduce the addresses` // allowance to zero by calling `approve(_spender, 0)` if it is not // already 0 to mitigate the race condition described here: // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 require( (_value == 0) || (allowed[msg.sender][_spender] == 0), "approve on a non-zero allowance" ); allowed[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } function allowance(address _owner, address _spender) public view override returns (uint256 remaining) { return allowed[_owner][_spender]; } } contract Asset is Registrable, StandardToken { uint128 public immutable id; string public name; string public symbol; uint256 public totalSupply; uint8 public constant decimals = 8; constructor( uint128 _id, string memory _name, string memory _symbol ) { id = _id; name = _name; symbol = _symbol; } function transferWithExtra( address to, uint256 value, bytes memory extra ) public returns (bool) { _transfer(msg.sender, to, value); IRegistry(registry).burn(to, value, extra); return true; } function transfer(address to, uint256 value) public override returns (bool) { return transferWithExtra(to, value, new bytes(0)); } function transferFrom( address from, address to, uint256 value ) public override returns (bool) { _transferFrom(from, to, value); IRegistry(registry).burn(to, value, new bytes(0)); return true; } function mint(address to, uint256 value) external onlyRegistry { balances[to] = balances[to] + value; totalSupply = totalSupply + value; emit Transfer(registry, to, value); } function burn(address to, uint256 value) external onlyRegistry { balances[to] = balances[to] - value; totalSupply = totalSupply - value; emit Transfer(to, registry, value); } }
contracts/Factory.sol
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; import {Asset} from "./Asset.sol"; import {User} from "./User.sol"; abstract contract Factory { uint256 public constant VERSION = 1; event UserCreated(address indexed at, bytes members); event AssetCreated(address indexed at, uint256 id); mapping(address => bytes) public users; mapping(address => uint128) public assets; mapping(uint256 => address) public contracts; function getOrCreateAssetContract( uint128 id, string memory symbol, string memory name ) internal returns (address) { address old = contracts[id]; if (old != address(0)) { return old; } bytes memory code = getAssetContractCode(id, symbol, name); address asset = getContractAddress(code); if (assets[asset] > 0) { return asset; } address addr = deploy(code, VERSION); require(addr == asset, "malformed asset contract address"); assets[asset] = id; contracts[id] = asset; emit AssetCreated(asset, id); return asset; } function getOrCreateUserContract(bytes memory members) internal returns (address) { uint256 id = uint256(keccak256(members)); address old = contracts[id]; if (old != address(0)) { return old; } bytes memory code = getUserContractCode(members); address user = getContractAddress(code); if (users[user].length > 0) { return user; } address addr = deploy(code, VERSION); require(addr == user, "malformed user contract address"); users[user] = members; contracts[id] = user; emit UserCreated(user, members); return user; } function getUserContractCode(bytes memory members) internal pure returns (bytes memory) { bytes memory code = type(User).creationCode; bytes memory args = abi.encode(members); return abi.encodePacked(code, args); } function getAssetContractCode( uint256 id, string memory symbol, string memory name ) internal pure returns (bytes memory) { bytes memory code = type(Asset).creationCode; bytes memory args = abi.encode(id, name, symbol); return abi.encodePacked(code, args); } function getContractAddress(bytes memory code) internal view returns (address) { code = abi.encodePacked( bytes1(0xff), address(this), VERSION, keccak256(code) ); return address(uint160(uint256(keccak256(code)))); } function deploy(bytes memory bytecode, uint256 _salt) internal returns (address) { address addr; assembly { addr := create2( callvalue(), add(bytecode, 0x20), mload(bytecode), _salt ) if iszero(extcodesize(addr)) { revert(0, 0) } } return addr; } }
contracts/Registrable.sol
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; interface IRegistry { function claim(address asset, uint256 amount) external returns (bool); function burn(address user, uint256 amount, bytes memory extra) external returns (bool); } abstract contract Registrable { address public registry; modifier onlyRegistry() { require(msg.sender == registry, "not registry"); _; } constructor() { registry = msg.sender; } }
contracts/Registry.sol
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; import {Integer} from "./libs/Integer.sol"; import {Bytes} from "./libs/Bytes.sol"; import {BLS} from "./libs/BLS.sol"; import {Storage} from "./Storage.sol"; import {IRegistry, Registrable} from "./Registrable.sol"; import {Factory} from "./Factory.sol"; import {Asset} from "./Asset.sol"; import {User} from "./User.sol"; contract Registry is IRegistry, Factory { using Bytes for bytes; using BLS for uint256[2]; using BLS for bytes; event Halted(bool state); event Iterated(uint256[4] from, uint256[4] to); event MixinTransaction(bytes raw); event MixinEvent( uint64 indexed nonce, address indexed user, address indexed asset, uint256 amount, bytes extra, uint64 timestamp ); uint128 public immutable PID; uint256[4] public GROUP; uint64 public INBOUND = 0; uint64 public OUTBOUND = 0; bool public HALTED = false; mapping(uint128 => uint256) public balances; struct Event { uint64 nonce; address user; address asset; uint256 amount; bytes extra; uint64 timestamp; uint256[2] sig; } constructor(bytes memory raw, uint128 pid) { require(raw.length == 128); require(pid > 0); GROUP = [ raw.toUint256(0), raw.toUint256(32), raw.toUint256(64), raw.toUint256(96) ]; PID = pid; } function iterate(bytes memory raw) public { require(HALTED, "invalid state"); require(raw.length == 256, "invalid input size"); uint256[4] memory group = [ raw.toUint256(0), raw.toUint256(32), raw.toUint256(64), raw.toUint256(96) ]; uint256[2] memory sig1 = [raw.toUint256(128), raw.toUint256(160)]; uint256[2] memory sig2 = [raw.toUint256(192), raw.toUint256(224)]; uint256[2] memory message = raw.slice(0, 128).hashToPoint(); require(sig1.verifySingle(GROUP, message), "invalid signature"); require(sig2.verifySingle(group, message), "invalid signature"); emit Iterated(GROUP, group); GROUP = group; } function halt(bytes memory raw) public { bytes memory input = bytes("HALT").concat( Integer.uint64ToFixedBytes(INBOUND) ); uint256[2] memory sig = [raw.toUint256(0), raw.toUint256(32)]; uint256[2] memory message = input.hashToPoint(); require(sig.verifySingle(GROUP, message), "invalid signature"); HALTED = !HALTED; emit Halted(HALTED); } function claim(address asset, uint256 amount) external returns (bool) { require(users[msg.sender].length > 0, "invalid user"); require(assets[asset] > 0, "invalid asset"); Asset(asset).burn(msg.sender, amount); sendMixinTransaction(msg.sender, asset, amount, new bytes(0)); return true; } function burn( address user, uint256 amount, bytes memory extra ) external returns (bool) { require(assets[msg.sender] > 0, "invalid asset"); if (users[user].length == 0) { return true; } Asset(msg.sender).burn(user, amount); sendMixinTransaction(user, msg.sender, amount, extra); return true; } function sendMixinTransaction( address user, address asset, uint256 amount, bytes memory extra ) internal { uint256 balance = balances[assets[asset]]; bytes memory log = buildMixinTransaction( OUTBOUND, users[user], assets[asset], amount, extra ); emit MixinTransaction(log); balances[assets[asset]] = balance - amount; OUTBOUND = OUTBOUND + 1; } // process || nonce || asset || amount || extra || timestamp || members || threshold || sig function buildMixinTransaction( uint64 nonce, bytes memory receiver, uint128 asset, uint256 amount, bytes memory extra ) internal returns (bytes memory) { if (extra.length >= 68 && extra.toUint128(0) == PID) { Storage stg = Storage(extra.toAddress(16)); bytes memory data = extra.slice(68, extra.length - 68); stg.write(extra.toUint256(36), data); extra = extra.slice(0, 68); } bytes memory raw = Integer.uint128ToFixedBytes(PID); raw = raw.concat(Integer.uint64ToFixedBytes(nonce)); raw = raw.concat(Integer.uint128ToFixedBytes(asset)); (bytes memory ab, uint16 al) = Integer.uint256ToVarBytes(amount); raw = raw.concat(Integer.uint16ToFixedBytes(al)); raw = raw.concat(ab); raw = raw.concat(Integer.uint16ToFixedBytes(uint16(extra.length))); raw = raw.concat(extra); raw = raw.concat(Integer.uint64ToFixedBytes(uint64(block.timestamp))); raw = raw.concat(receiver); raw = raw.concat(new bytes(2)); return raw; } // process || nonce || asset || amount || extra || timestamp || members || threshold || sig function mixin(bytes memory raw) public returns (bool) { require(!HALTED, "invalid state"); require(raw.length >= 141, "event data too small"); Event memory evt; uint256 offset = 0; uint128 id = raw.toUint128(offset); require(id == PID, "invalid process"); offset = offset + 16; evt.nonce = raw.toUint64(offset); require(evt.nonce == INBOUND, "invalid nonce"); INBOUND = INBOUND + 1; offset = offset + 8; (offset, id, evt.amount) = parseEventAsset(raw, offset); (offset, evt.extra, evt.timestamp) = parseEventExtra(raw, offset); (offset, evt.user) = parseEventUser(raw, offset); (evt.asset, evt.extra) = parseEventInput(id, evt.extra); offset = offset + 2; evt.sig = [raw.toUint256(offset), raw.toUint256(offset + 32)]; uint256[2] memory message = raw .slice(0, offset - 2) .concat(new bytes(2)) .hashToPoint(); require(evt.sig.verifySingle(GROUP, message), "invalid signature"); offset = offset + 64; require(raw.length == offset, "malformed event encoding"); uint256 balance = balances[assets[evt.asset]]; balances[assets[evt.asset]] = balance + evt.amount; emit MixinEvent( evt.nonce, evt.user, evt.asset, evt.amount, evt.extra, evt.timestamp ); Asset(evt.asset).mint(evt.user, evt.amount); return User(evt.user).run(evt.asset, evt.amount, evt.extra); } function parseEventExtra(bytes memory raw, uint256 offset) internal pure returns ( uint256, bytes memory, uint64 ) { uint256 size = raw.toUint16(offset); offset = offset + 2; bytes memory extra = raw.slice(offset, size); offset = offset + size; uint64 timestamp = raw.toUint64(offset); offset = offset + 8; return (offset, extra, timestamp); } function parseEventAsset(bytes memory raw, uint256 offset) internal pure returns ( uint256, uint128, uint256 ) { uint128 id = raw.toUint128(offset); require(id > 0, "invalid asset"); offset = offset + 16; uint256 size = raw.toUint16(offset); offset = offset + 2; require(size <= 32, "integer out of bounds"); uint256 amount = new bytes(32 - size) .concat(raw.slice(offset, size)) .toUint256(0); offset = offset + size; return (offset, id, amount); } function parseEventUser(bytes memory raw, uint256 offset) internal returns (uint256, address) { uint16 size = raw.toUint16(offset); size = 2 + size * 16 + 2; bytes memory members = raw.slice(offset, size); offset = offset + size; address user = getOrCreateUserContract(members); return (offset, user); } function parseEventInput(uint128 id, bytes memory extra) internal returns (address, bytes memory) { uint256 offset = 0; uint16 size = extra.toUint16(offset); offset = offset + 2; string memory symbol = string(extra.slice(offset, size)); offset = offset + size; size = extra.toUint16(offset); offset = offset + 2; string memory name = string(extra.slice(offset, size)); offset = offset + size; bytes memory input = extra.slice(offset, extra.length - offset); if (input.length == 68 && input.toUint128(0) == PID) { input = Storage(input.toAddress(16)).read(input.toUint256(36)); } address asset = getOrCreateAssetContract(id, symbol, name); return (asset, input); } }
contracts/Storage.sol
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; contract Storage { mapping(uint256 => bytes) internal values; function read(uint256 _key) public view returns (bytes memory) { return values[_key]; } function write(uint256 _key, bytes memory raw) public { uint256 key = uint256(keccak256(raw)); require(key == _key, "invalid key or raw"); values[_key] = raw; } }
contracts/User.sol
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; import {Bytes} from "./libs/Bytes.sol"; import {IRegistry, Registrable} from "./Registrable.sol"; import {IERC20} from "./Asset.sol"; contract User is Registrable { using Bytes for bytes; event ProcessCalled( address indexed process, bytes input, bool result, bytes output ); bytes public members; constructor(bytes memory _members) { members = _members; } function run( address asset, uint256 amount, bytes memory extra ) external onlyRegistry returns (bool) { if (extra.length < 28) { IRegistry(registry).claim(asset, amount); return true; } uint16 count = extra.toUint16(0); if (count < 1 || count > 16) { IRegistry(registry).claim(asset, amount); return true; } for (uint256 offset = 2; count >= 0 && offset < extra.length; count--) { bool primary = offset == 2; bytes memory data = extra.slice(offset, extra.length - offset); (uint256 size, bool success) = handle(data, asset, amount, primary); if (!success) { break; } offset = offset + size; } try IRegistry(registry).claim(asset, amount) {} catch {} return true; } function handle( bytes memory extra, address asset, uint256 amount, bool primary ) internal returns (uint256, bool) { uint256 offset = 0; if (offset + 20 > extra.length) { return (offset, false); } address process = extra.toAddress(offset); offset = offset + 20; if (primary) { IERC20(asset).approve(process, 0); IERC20(asset).approve(process, amount); } if (offset + 2 > extra.length) { return (offset, false); } uint256 size = extra.toUint16(offset); offset = offset + 2; if (offset + size > extra.length) { return (offset, false); } bytes memory input = extra.slice(offset, size); (bool result, bytes memory output) = process.call(input); offset = offset + size; emit ProcessCalled(process, input, result, output); return (offset, result); } }
contracts/libs/BLS.sol
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; library BLS { // Field order uint256 constant N = 21888242871839275222246405745257275088696311157297823662689037894645226208583; // Negated genarator of G2 uint256 constant nG2x1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; uint256 constant nG2x0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; uint256 constant nG2y1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052; uint256 constant nG2y0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653; function verifySingle( uint256[2] memory signature, uint256[4] memory pubkey, uint256[2] memory message ) internal view returns (bool) { uint256[12] memory input = [ signature[0], signature[1], nG2x1, nG2x0, nG2y1, nG2y0, message[0], message[1], pubkey[1], pubkey[0], pubkey[3], pubkey[2] ]; uint256[1] memory out; bool success; // solium-disable-next-line security/no-inline-assembly assembly { success := staticcall(sub(gas(), 2000), 8, input, 384, out, 0x20) // use invalid() to make gas estimation work switch success case 0 { invalid() } } require(success, "BLS: paring check call failed"); return out[0] != 0; } function hashToPoint(bytes memory data) internal view returns (uint256[2] memory p) { return mapToPoint(keccak256(data)); } function mapToPoint(bytes32 _x) internal view returns (uint256[2] memory p) { uint256 x = uint256(_x) % N; uint256 y; bool found = false; while (true) { y = mulmod(x, x, N); y = mulmod(y, x, N); y = addmod(y, 3, N); (y, found) = sqrt(y); if (found) { p[0] = x; p[1] = y; break; } x = addmod(x, 1, N); } } function sqrt(uint256 xx) internal view returns (uint256 x, bool hasRoot) { bool success; // solium-disable-next-line security/no-inline-assembly assembly { let freemem := mload(0x40) mstore(freemem, 0x20) mstore(add(freemem, 0x20), 0x20) mstore(add(freemem, 0x40), 0x20) mstore(add(freemem, 0x60), xx) // (N + 1) / 4 = 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52 mstore( add(freemem, 0x80), 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52 ) // N = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 mstore( add(freemem, 0xA0), 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 ) success := staticcall( sub(gas(), 2000), 5, freemem, 0xC0, freemem, 0x20 ) switch success case 0 { invalid() } x := mload(freemem) hasRoot := eq(xx, mulmod(x, x, N)) } require(success, "BLS: sqrt modexp call failed"); } }
contracts/libs/Bytes.sol
// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <goncalo.sa@consensys.net> * * @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. */ pragma solidity >=0.8.0 <0.9.0; library Bytes { 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(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); 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) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); 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 , "toUint8_outOfBounds"); 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, "toUint16_outOfBounds"); 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, "toUint32_outOfBounds"); 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, "toUint64_outOfBounds"); 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, "toUint96_outOfBounds"); 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, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); 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, "toBytes32_outOfBounds"); 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(uint256(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(uint256(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/libs/Integer.sol
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; import {Bytes} from "./Bytes.sol"; library Integer { using Bytes for bytes; function uint16ToFixedBytes(uint16 x) internal pure returns (bytes memory) { bytes memory c = new bytes(2); bytes2 b = bytes2(x); for (uint256 i = 0; i < 2; i++) { c[i] = b[i]; } return c; } function uint64ToFixedBytes(uint64 x) internal pure returns (bytes memory) { bytes memory c = new bytes(8); bytes8 b = bytes8(x); for (uint256 i = 0; i < 8; i++) { c[i] = b[i]; } return c; } function uint128ToFixedBytes(uint128 x) internal pure returns (bytes memory) { bytes memory c = new bytes(16); bytes16 b = bytes16(x); for (uint256 i = 0; i < 16; i++) { c[i] = b[i]; } return c; } function uint256ToVarBytes(uint256 x) internal pure returns (bytes memory, uint16) { bytes memory c = new bytes(32); bytes32 b = bytes32(x); uint16 offset = 0; for (uint16 i = 0; i < 32; i++) { c[i] = b[i]; if (c[i] > 0 && offset == 0) { offset = i; } } uint16 size = 32 - offset; return (c.slice(offset, 32 - offset), size); } }
Contract ABI
[{"type":"constructor","inputs":[{"type":"uint128","name":"_id","internalType":"uint128"},{"type":"string","name":"_name","internalType":"string"},{"type":"string","name":"_symbol","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"remaining","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"address","name":"_spender","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"_spender","internalType":"address"},{"type":"uint256","name":"_value","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"balance","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"_owner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"burn","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint128","name":"","internalType":"uint128"}],"name":"id","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"mint","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"registry","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"from","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferWithExtra","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"bytes","name":"extra","internalType":"bytes"}]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","indexed":true},{"type":"address","name":"spender","indexed":true},{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","indexed":true},{"type":"address","name":"to","indexed":true},{"type":"uint256","name":"value","indexed":false}],"anonymous":false}]
Contract Creation Code
0x60a06040523480156200001157600080fd5b5060405162000df338038062000df38339810160408190526200003491620001fb565b600080546001600160a01b031916331790556001600160801b03831660805281516200006890600390602085019062000088565b5080516200007e90600490602084019062000088565b50505050620002c2565b828054620000969062000285565b90600052602060002090601f016020900481019282620000ba576000855562000105565b82601f10620000d557805160ff191683800117855562000105565b8280016001018555821562000105579182015b8281111562000105578251825591602001919060010190620000e8565b506200011392915062000117565b5090565b5b8082111562000113576000815560010162000118565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200015657600080fd5b81516001600160401b03808211156200017357620001736200012e565b604051601f8301601f19908116603f011681019082821181831017156200019e576200019e6200012e565b81604052838152602092508683858801011115620001bb57600080fd5b600091505b83821015620001df5785820183015181830184015290820190620001c0565b83821115620001f15760008385830101525b9695505050505050565b6000806000606084860312156200021157600080fd5b83516001600160801b03811681146200022957600080fd5b60208501519093506001600160401b03808211156200024757600080fd5b620002558783880162000144565b935060408601519150808211156200026c57600080fd5b506200027b8682870162000144565b9150509250925092565b600181811c908216806200029a57607f821691505b60208210811415620002bc57634e487b7160e01b600052602260045260246000fd5b50919050565b608051610b15620002de60003960006102230152610b156000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c806370a082311161008c5780639dc29fac116100665780639dc29fac146101f8578063a9059cbb1461020b578063af640d0f1461021e578063dd62ed3e1461026657600080fd5b806370a082311461019c5780637b103999146101c557806395d89b41146101f057600080fd5b80631f6847fe116100c85780631f6847fe1461014757806323b872dd1461015a578063313ce5671461016d57806340c10f191461018757600080fd5b806306fdde03146100ef578063095ea7b31461010d57806318160ddd14610130575b600080fd5b6100f761029f565b604051610104919061084a565b60405180910390f35b61012061011b366004610879565b61032d565b6040519015158152602001610104565b61013960055481565b604051908152602001610104565b6101206101553660046108b9565b610412565b610120610168366004610984565b6104b0565b610175600881565b60405160ff9091168152602001610104565b61019a610195366004610879565b6104fb565b005b6101396101aa3660046109c0565b6001600160a01b031660009081526001602052604090205490565b6000546101d8906001600160a01b031681565b6040516001600160a01b039091168152602001610104565b6100f76105db565b61019a610206366004610879565b6105e8565b610120610219366004610879565b6106c1565b6102457f000000000000000000000000000000000000000000000000000000000000000081565b6040516fffffffffffffffffffffffffffffffff9091168152602001610104565b6101396102743660046109db565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b600380546102ac90610a0e565b80601f01602080910402602001604051908101604052809291908181526020018280546102d890610a0e565b80156103255780601f106102fa57610100808354040283529160200191610325565b820191906000526020600020905b81548152906001019060200180831161030857829003601f168201915b505050505081565b600081158061035d57503360009081526002602090815260408083206001600160a01b0387168452909152902054155b6103ae5760405162461bcd60e51b815260206004820152601f60248201527f617070726f7665206f6e2061206e6f6e2d7a65726f20616c6c6f77616e63650060448201526064015b60405180910390fd5b3360008181526002602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350600192915050565b600061041f3385856106e5565b6000546040516344d1718760e01b81526001600160a01b03909116906344d171879061045390879087908790600401610a49565b602060405180830381600087803b15801561046d57600080fd5b505af1158015610481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a59190610a79565b506001949350505050565b60006104bd84848461079a565b600080546040805192835260208301908190526344d1718760e01b90526001600160a01b0316906344d1718790610453908690869060248101610a49565b6000546001600160a01b031633146105445760405162461bcd60e51b815260206004820152600c60248201526b6e6f7420726567697374727960a01b60448201526064016103a5565b6001600160a01b038216600090815260016020526040902054610568908290610ab1565b6001600160a01b03831660009081526001602052604090205560055461058f908290610ab1565b6005556000546040518281526001600160a01b038481169216907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b600480546102ac90610a0e565b6000546001600160a01b031633146106315760405162461bcd60e51b815260206004820152600c60248201526b6e6f7420726567697374727960a01b60448201526064016103a5565b6001600160a01b038216600090815260016020526040902054610655908290610ac9565b6001600160a01b03831660009081526001602052604090205560055461067c908290610ac9565b6005556000546040518281526001600160a01b03918216918416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016105cf565b604080516000808252602082019092526106de9084908490610412565b9392505050565b6001600160a01b038316600090815260016020526040902054610709908290610ac9565b6001600160a01b038085166000908152600160205260408082209390935590841681522054610739908290610ab1565b6001600160a01b0380841660008181526001602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061078d9085815260200190565b60405180910390a3505050565b6001600160a01b03831660009081526002602090815260408083203384529091529020546107c88282610ac9565b6001600160a01b03851660009081526002602090815260408083203384529091529020556107f78484846106e5565b50505050565b6000815180845260005b8181101561082357602081850181015186830182015201610807565b81811115610835576000602083870101525b50601f01601f19169290920160200192915050565b6020815260006106de60208301846107fd565b80356001600160a01b038116811461087457600080fd5b919050565b6000806040838503121561088c57600080fd5b6108958361085d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156108ce57600080fd5b6108d78461085d565b925060208401359150604084013567ffffffffffffffff808211156108fb57600080fd5b818601915086601f83011261090f57600080fd5b813581811115610921576109216108a3565b604051601f8201601f19908116603f01168101908382118183101715610949576109496108a3565b8160405282815289602084870101111561096257600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60008060006060848603121561099957600080fd5b6109a28461085d565b92506109b06020850161085d565b9150604084013590509250925092565b6000602082840312156109d257600080fd5b6106de8261085d565b600080604083850312156109ee57600080fd5b6109f78361085d565b9150610a056020840161085d565b90509250929050565b600181811c90821680610a2257607f821691505b60208210811415610a4357634e487b7160e01b600052602260045260246000fd5b50919050565b60018060a01b0384168152826020820152606060408201526000610a7060608301846107fd565b95945050505050565b600060208284031215610a8b57600080fd5b815180151581146106de57600080fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115610ac457610ac4610a9b565b500190565b600082821015610adb57610adb610a9b565b50039056fea265627a7a72315820e4d33a6aec92022b9335cb5ab741e8642db27bf8eedbdc8f2e4317e41206159964736f6c63430008090032000000000000000000000000000000009b180ab66abe3dc0a13f04169eb34bfa000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000065553442f2f43000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c806370a082311161008c5780639dc29fac116100665780639dc29fac146101f8578063a9059cbb1461020b578063af640d0f1461021e578063dd62ed3e1461026657600080fd5b806370a082311461019c5780637b103999146101c557806395d89b41146101f057600080fd5b80631f6847fe116100c85780631f6847fe1461014757806323b872dd1461015a578063313ce5671461016d57806340c10f191461018757600080fd5b806306fdde03146100ef578063095ea7b31461010d57806318160ddd14610130575b600080fd5b6100f761029f565b604051610104919061084a565b60405180910390f35b61012061011b366004610879565b61032d565b6040519015158152602001610104565b61013960055481565b604051908152602001610104565b6101206101553660046108b9565b610412565b610120610168366004610984565b6104b0565b610175600881565b60405160ff9091168152602001610104565b61019a610195366004610879565b6104fb565b005b6101396101aa3660046109c0565b6001600160a01b031660009081526001602052604090205490565b6000546101d8906001600160a01b031681565b6040516001600160a01b039091168152602001610104565b6100f76105db565b61019a610206366004610879565b6105e8565b610120610219366004610879565b6106c1565b6102457f000000000000000000000000000000009b180ab66abe3dc0a13f04169eb34bfa81565b6040516fffffffffffffffffffffffffffffffff9091168152602001610104565b6101396102743660046109db565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b600380546102ac90610a0e565b80601f01602080910402602001604051908101604052809291908181526020018280546102d890610a0e565b80156103255780601f106102fa57610100808354040283529160200191610325565b820191906000526020600020905b81548152906001019060200180831161030857829003601f168201915b505050505081565b600081158061035d57503360009081526002602090815260408083206001600160a01b0387168452909152902054155b6103ae5760405162461bcd60e51b815260206004820152601f60248201527f617070726f7665206f6e2061206e6f6e2d7a65726f20616c6c6f77616e63650060448201526064015b60405180910390fd5b3360008181526002602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350600192915050565b600061041f3385856106e5565b6000546040516344d1718760e01b81526001600160a01b03909116906344d171879061045390879087908790600401610a49565b602060405180830381600087803b15801561046d57600080fd5b505af1158015610481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a59190610a79565b506001949350505050565b60006104bd84848461079a565b600080546040805192835260208301908190526344d1718760e01b90526001600160a01b0316906344d1718790610453908690869060248101610a49565b6000546001600160a01b031633146105445760405162461bcd60e51b815260206004820152600c60248201526b6e6f7420726567697374727960a01b60448201526064016103a5565b6001600160a01b038216600090815260016020526040902054610568908290610ab1565b6001600160a01b03831660009081526001602052604090205560055461058f908290610ab1565b6005556000546040518281526001600160a01b038481169216907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b600480546102ac90610a0e565b6000546001600160a01b031633146106315760405162461bcd60e51b815260206004820152600c60248201526b6e6f7420726567697374727960a01b60448201526064016103a5565b6001600160a01b038216600090815260016020526040902054610655908290610ac9565b6001600160a01b03831660009081526001602052604090205560055461067c908290610ac9565b6005556000546040518281526001600160a01b03918216918416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016105cf565b604080516000808252602082019092526106de9084908490610412565b9392505050565b6001600160a01b038316600090815260016020526040902054610709908290610ac9565b6001600160a01b038085166000908152600160205260408082209390935590841681522054610739908290610ab1565b6001600160a01b0380841660008181526001602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061078d9085815260200190565b60405180910390a3505050565b6001600160a01b03831660009081526002602090815260408083203384529091529020546107c88282610ac9565b6001600160a01b03851660009081526002602090815260408083203384529091529020556107f78484846106e5565b50505050565b6000815180845260005b8181101561082357602081850181015186830182015201610807565b81811115610835576000602083870101525b50601f01601f19169290920160200192915050565b6020815260006106de60208301846107fd565b80356001600160a01b038116811461087457600080fd5b919050565b6000806040838503121561088c57600080fd5b6108958361085d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156108ce57600080fd5b6108d78461085d565b925060208401359150604084013567ffffffffffffffff808211156108fb57600080fd5b818601915086601f83011261090f57600080fd5b813581811115610921576109216108a3565b604051601f8201601f19908116603f01168101908382118183101715610949576109496108a3565b8160405282815289602084870101111561096257600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60008060006060848603121561099957600080fd5b6109a28461085d565b92506109b06020850161085d565b9150604084013590509250925092565b6000602082840312156109d257600080fd5b6106de8261085d565b600080604083850312156109ee57600080fd5b6109f78361085d565b9150610a056020840161085d565b90509250929050565b600181811c90821680610a2257607f821691505b60208210811415610a4357634e487b7160e01b600052602260045260246000fd5b50919050565b60018060a01b0384168152826020820152606060408201526000610a7060608301846107fd565b95945050505050565b600060208284031215610a8b57600080fd5b815180151581146106de57600080fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115610ac457610ac4610a9b565b500190565b600082821015610adb57610adb610a9b565b50039056fea265627a7a72315820e4d33a6aec92022b9335cb5ab741e8642db27bf8eedbdc8f2e4317e41206159964736f6c63430008090032