The evm-semantics
only defines ranges and constants for a few solidity types. A couple of extra
ones are required for these specs.
syntax Int ::= "pow32"
rule pow32 => 4294967296 [macro]
syntax Int ::= "pow112"
rule pow112 => 5192296858534827628530496329220096 [macro]
syntax Int ::= "pow224"
rule pow224 => 26959946667150639794667015087019630673637144422540572481103610249216 [macro]
syntax Int ::= "maxUInt32"
rule maxUInt32 => 4294967295 [macro]
syntax Int ::= "maxUInt112"
rule maxUInt112 => 5192296858534827628530496329220095 [macro]
syntax Int ::= "maxUInt224"
rule maxUInt224 => 26959946667150639794667015087019630673637144422540572481103610249215 [macro]
syntax Int ::= "notMaxUInt112"
rule notMaxUInt112 => 115792089237316195423570985008687907853269979473343705504629955477416800419840 [macro]
syntax Int ::= "notMaxUInt160"
rule notMaxUInt160 => 115792089237316195423570985007226406215939081747436879206741300988257197096960 [macro]
syntax Int ::= "notMaxUInt224"
rule notMaxUInt224 => 115792089210356248756420345214020892766250353992003419616917011526809519390720 [macro]
rule #rangeUInt(32, X) => #range(0 <= X <= maxUInt32) [macro]
rule #rangeUInt(112, X) => #range(0 <= X <= maxUInt112) [macro]
0
divided by anything is 0
.
rule 0 /Int X => 0
requires notBool (X ==Int 0)
Helper for cleaner storage conditions.
syntax Int ::= "#min" "(" Int "," Int ")" [function]
rule #min(X, Y) => #if (X <Int Y) #then X #else Y #fi
These lemmas allow K
to translate the under/overflow checking as implemented in the SafeMath.sol
library to the logical #rangeUInt
conditions expressed within the specs.
// sub
rule A -Word B <=Int A => #rangeUInt(256, A -Int B)
requires #rangeUInt(256, A)
andBool #rangeUInt(256, B)
// add
rule (chop(X +Int Y) >=Int X) => #rangeUInt(256, X +Int Y)
requires #rangeUInt(256, X)
andBool #rangeUInt(256, Y)
rule (X <=Int chop(X +Int Y)) => #rangeUInt(256, X +Int Y)
requires #rangeUInt(256, X)
andBool #rangeUInt(256, Y)
// mul
rule (chop(X *Int Y) /Int Y ==K X) => #rangeUInt(256, X *Int Y)
requires #rangeUInt(256, X)
andBool #rangeUInt(256, Y)
The solidity optimizer compiles block.time % 2**32
into TIME AND maxUInt32
instead of TIME MOD pow32
. K
is then unable to reason about the size of the result and so cannot apply further
simplifications. We therefore rewrite it back to modInt pow32
.
rule (maxUInt32 &Int X) => (X modInt pow32)
Repeated application of modInt pow32
can be simplified as follows. This lets us clean the storage
conditions in a few specs.
rule ((X modInt pow32) modInt pow32) => (X modInt pow32)
Simplify idempotent applications of the modulo operation:
rule X modInt Y => X
requires X <Int Y
K
doesn't know that bitwise AND
is commutative, so we give it a little helping hand.
rule (X &Int maxUInt32) => (maxUInt32 &Int X)
rule (X &Int maxUInt112) => (maxUInt112 &Int X)
rule (X &Int maxUInt160) => (maxUInt160 &Int X)
rule (X &Int notMaxUInt160) => (notMaxUInt160 &Int X)
rule (X &Int notMaxUInt224) => (notMaxUInt224 &Int X)
allPairs
is an array which stores the address of every exchange pair created
using the Factory
.
pair0
represents the storage key of the first array element, the keccak
hash of slot 3: keccak(uint256(3))
.
syntax Int ::= "pair0"
rule pair0 => 87903029871075914254377627908054574944891091886930582284385770809450030037083 [macro]
Subsequent array elements are stored at a uint256
offset from this key:
pair0 + index
. The maximum allowable index before integer overflow is
therefore maxUInt256 - pair0
and the valid index range is zero to max.
index:
Valid index range: allPairs[0]...allPairs[maxUInt256 - pair0]
The maximum number of addresses that can be stored by the allPairs
array
is max. index plus one.
syntax Int ::= "maxPairs"
rule maxPairs => (maxUInt256 -Int pair0) +Int 1 [macro]
Important to note is that that there is no guarentee that the storage keys of
allPairs
will not collide with storage keys of getPair
. We make the
low probablity assumption that there will be no such collision in the factory.
rule N +Int pair0 => pair0 +Int N
rule keccakIntList(X) ==K pair0 +Int N => false
rule pair0 +Int N ==K keccakIntList(X) => false
rule keccak(X) ==K pair0 +Int N => false
rule pair0 +Int N ==K keccak(X) => false
We make the probabalistic assumption that the array will not overflow. This is not enforced by Solidity.
rule chop(pair0 +Int N) => pair0 +Int N
rule chop(N +Int pair0) => pair0 +Int N
The packing routine for abi.encodePacked(address, address)
in the factory
contract, formats both addresses with a left shift and then writes them as
overlapping words to memory. The first 40 bytes is then read back from memory
to provide the packed result. These rules handle the writing of the shifted
addresses to memory and the reduction of the resulting byte array.
rule chop(A <<Int 96) => A <<Int 96
requires #rangeAddress(A)
rule #padToWidth(32, #asByteStack(A <<Int 96))
=> #asByteStackInWidth(A <<Int 96, 32)
rule takeWordStack(20, #asByteStack(X)) =>
( nthbyteof(X, 0, 32)
: nthbyteof(X, 1, 32)
: nthbyteof(X, 2, 32)
: nthbyteof(X, 3, 32)
: nthbyteof(X, 4, 32)
: nthbyteof(X, 5, 32)
: nthbyteof(X, 6, 32)
: nthbyteof(X, 7, 32)
: nthbyteof(X, 8, 32)
: nthbyteof(X, 9, 32)
: nthbyteof(X, 10, 32)
: nthbyteof(X, 11, 32)
: nthbyteof(X, 12, 32)
: nthbyteof(X, 13, 32)
: nthbyteof(X, 14, 32)
: nthbyteof(X, 15, 32)
: nthbyteof(X, 16, 32)
: nthbyteof(X, 17, 32)
: nthbyteof(X, 18, 32)
: nthbyteof(X, 19, 32)
: .WordStack
)
Define the symbolic term representing packed storage:
syntax Int ::= "#WordPackUInt112UInt112UInt32" "(" Int "," Int "," Int ")" [function]
Solidity reads from packed storage locations with the following sequence:
SLOAD
to get the packed word- Bitshift the word (e.g.
/Int pow112
)to bring the target of the read to the lower order (rightmost) side - Bitwise
AND
withmaxUInt
for the target type to zero out the rest of the word (e.g.AND maxUInt32
for auint32
)
Example: read Reserve1
These lemmas define the read operations specific to each packed storage location.
// Reserve0
rule maxUInt112 &Int #WordPackUInt112UInt112UInt32(A, B, C) => A
// Reserve1
rule maxUInt112 &Int (#WordPackUInt112UInt112UInt32(A, B, C) /Int pow112 ) => B
// BlockTimestampLast
rule #WordPackUInt112UInt112UInt32(A, B, C) /Int pow224 => C
Solidity writes to packed storage locations with the following sequence:
SLOAD
to get the current value of the word to be written- Produce a bit mask by bitshifting
maxUInt
for the target type and taking the one's complement (e.g.NOT (maxUInt32 * pow224)
) AND
the mask and the current value of storage to zero out the target region of the word- Bitshift the new value into place and
OR
with the word produced by the previous step to write the new value to the target region SSTORE
the new value of the word
Example: write Balance0
to Reserve0
This produces some pretty gnarly expressions, and K
needs help simplifying them. Note that
multiple lemmas are needed below to match the cases where individual regions within the word are
known to be zero. In this case K
will simplify the 0
out of the expression, meaning we have
to match on a few different expressions for each write operation.
The ordering of arguments differs between the various cases to match the bytecode produced by solidity.
Mask target range to zero:
rule notMaxUInt112 &Int #WordPackUInt112UInt112UInt32(A, B, C) => #WordPackUInt112UInt112UInt32(0, B, C)
Write new value:
rule X |Int #WordPackUInt112UInt112UInt32(0, B, C) => #WordPackUInt112UInt112UInt32(X, B, C)
requires #rangeUInt(112, X)
The below constant represents not(maxUInt112 * pow112)
, in hex 0xffffffff0000000000000000000000000000ffffffffffffffffffffffffffff
:
syntax Int ::= "notMaxUInt112xPow112"
rule notMaxUInt112xPow112 => 115792089210356248756420345214020892766250359184300278151744640057305848610815 [macro]
Mask target range to zero:
rule notMaxUInt112xPow112 &Int #WordPackUInt112UInt112UInt32(A, B, C) => #WordPackUInt112UInt112UInt32(A, 0, C)
Write new value:
rule (pow112 *Int X) |Int #WordPackUInt112UInt112UInt32(A, 0, C) => #WordPackUInt112UInt112UInt32(A, X, C)
requires #rangeUInt(112, X)
Mask target range to zero. Note that solidity uses a slightly different approach here than with the
other words, and directly applies a mask of &Int pow224
, instead of bitshifting and inverting as
for reserve0
and reserve1
. This only happens when the optimizer is enabled.
rule maxUInt224 &Int #WordPackUInt112UInt112UInt32(A, B, C) => #WordPackUInt112UInt112UInt32(A, B, 0)
write new value:
rule (X *Int pow224) |Int #WordPackUInt112UInt112UInt32(A, B, 0) => #WordPackUInt112UInt112UInt32(A, B, X)
requires #rangeUInt(32, X)
Address type storage routine.
When writing addresses to storage, solidity masks the existing value to zero using the address type one's compliment and inserts the new value with a bitwise OR.
The inclusion of a rangeUInt
constraint on existing address A
allows for the _
(Junk bytes)
expectation in storage specs.
// Overwrite A with B
rule ((notMaxUInt160 &Int A)) |Int B => B
requires #rangeAddress(B)
andBool (#rangeAddress(A) orBool #rangeUInt(256, A))
rule (B |Int (notMaxUInt160 &Int A)) => B
requires #rangeAddress(B)
andBool (#rangeAddress(A) orBool #rangeUInt(256, A))
Sometimes solidity will try and read a Word from memory containing unaligned data. In that case K
needs help simplifying the resulting expressions:
masking:
// mask first four bytes to zero
rule maxUInt224 &Int #asWord(WS) => #asWord(#padToWidth(32, #drop(4, WS)))
requires #sizeWordStack(WS) ==Int 32
// mask everything except first four bytes to zero
rule notMaxUInt224 &Int #asWord(WS) => #asWord(#padRightToWidth(32, #take(4, WS)))
requires #sizeWordStack(WS) ==Int 32
writes:
// write first four bytes
rule X |Int #asWord(#padToWidth(32, WS)) => #asWord(#take(4, #asByteStack(X)) ++ WS)
requires X &Int notMaxUInt224 ==Int X
andBool #rangeUInt(256, X)
andBool #sizeWordStack(WS) ==Int 28
We teach K how to write some expressions involving division to memory. This is used when writing the expression for fee liquidity into memory.
rule #padToWidth(32, #asByteStack(X /Int Y)) => #asByteStackInWidth(X /Int Y, 32)
requires #rangeUInt(256, X)
andBool #rangeUInt(256, Y)
Placeholder rewrite rule for Math.sqrt
. This leaves the result of the call to Math.sqrt
as
symbolic for now, meaning that the specs are all assuming that Math.sqrt
is correctly implemented
and does what it is supposed to.
syntax Int ::= "#sqrt" "(" Int ")" [smtlib(smt_sqrt), smt-prelude, function]
rule <k> #execute ~> CONTINUATION => #execute ~> CONTINUATION </k>
<program> UniswapV2Pair_bytecode </program>
<jumpDests> #computeValidJumpDests(UniswapV2Pair_bytecode) </jumpDests>
<wordStack> X : JumpTo : WS => JumpTo : #sqrt(X) : WS </wordStack>
<pc> 10360 => 10441 </pc>
requires #rangeUInt(256, X)
[trusted]
A concrete evaluation of sqrt(0)
is provided to help simplification of a few terms.
rule #sqrt(0) => 0
The full bytecode of the Pair is unfortunately required here to ensure for the place holder #sqrt
rewrite rule to be applied only in UniswapV2Pair
.
syntax WordStack ::= "UniswapV2Pair_bytecode"
rule UniswapV2Pair_bytecode => #parseByteStack("0x608060405234801561001057600080fd5b50600436106101b95760003560e01c80636a627842116100f9578063ba9a7a5611610097578063d21220a711610071578063d21220a7146105da578063d505accf146105e2578063dd62ed3e14610640578063fff6cae91461067b576101b9565b8063ba9a7a5614610597578063bc25cf771461059f578063c45a0155146105d2576101b9565b80637ecebe00116100d35780637ecebe00146104d757806389afcb441461050a57806395d89b4114610556578063a9059cbb1461055e576101b9565b80636a6278421461046957806370a082311461049c5780637464fc3d146104cf576101b9565b806323b872dd116101665780633644e515116101405780633644e51514610416578063485cc9551461041e5780635909c0d5146104595780635a3d549314610461576101b9565b806323b872dd146103ad57806330adf81f146103f0578063313ce567146103f8576101b9565b8063095ea7b311610197578063095ea7b3146103155780630dfe16811461036257806318160ddd14610393576101b9565b8063022c0d9f146101be57806306fdde03146102595780630902f1ac146102d6575b600080fd5b610257600480360360808110156101d457600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516919081019060808101606082013564010000000081111561021857600080fd5b82018360208201111561022a57600080fd5b8035906020019184600183028401116401000000008311171561024c57600080fd5b509092509050610683565b005b610261610d57565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561029b578181015183820152602001610283565b50505050905090810190601f1680156102c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102de610d90565b604080516dffffffffffffffffffffffffffff948516815292909316602083015263ffffffff168183015290519081900360600190f35b61034e6004803603604081101561032b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610de5565b604080519115158252519081900360200190f35b61036a610dfc565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61039b610e18565b60408051918252519081900360200190f35b61034e600480360360608110156103c357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610e1e565b61039b610efd565b610400610f21565b6040805160ff9092168252519081900360200190f35b61039b610f26565b6102576004803603604081101561043457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610f2c565b61039b611005565b61039b61100b565b61039b6004803603602081101561047f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611011565b61039b600480360360208110156104b257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113cb565b61039b6113dd565b61039b600480360360208110156104ed57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113e3565b61053d6004803603602081101561052057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113f5565b6040805192835260208301919091528051918290030190f35b610261611892565b61034e6004803603604081101561057457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356118cb565b61039b6118d8565b610257600480360360208110156105b557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166118de565b61036a611ad4565b61036a611af0565b610257600480360360e08110156105f857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611b0c565b61039b6004803603604081101561065657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516611dd8565b610257611df5565b600c546001146106f457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55841515806107075750600084115b61075c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180612b2f6025913960400191505060405180910390fd5b600080610767610d90565b5091509150816dffffffffffffffffffffffffffff168710801561079a5750806dffffffffffffffffffffffffffff1686105b6107ef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180612b786021913960400191505060405180910390fd5b600654600754600091829173ffffffffffffffffffffffffffffffffffffffff91821691908116908916821480159061085457508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b6108bf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f556e697377617056323a20494e56414c49445f544f0000000000000000000000604482015290519081900360640190fd5b8a156108d0576108d0828a8d611fdb565b89156108e1576108e1818a8c611fdb565b86156109c3578873ffffffffffffffffffffffffffffffffffffffff166310d1e85c338d8d8c8c6040518663ffffffff1660e01b8152600401808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156109aa57600080fd5b505af11580156109be573d6000803e3d6000fd5b505050505b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8416916370a08231916024808301926020929190829003018186803b158015610a2f57600080fd5b505afa158015610a43573d6000803e3d6000fd5b505050506040513d6020811015610a5957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191955073ffffffffffffffffffffffffffffffffffffffff8316916370a0823191602480820192602092909190829003018186803b158015610acb57600080fd5b505afa158015610adf573d6000803e3d6000fd5b505050506040513d6020811015610af557600080fd5b5051925060009150506dffffffffffffffffffffffffffff85168a90038311610b1f576000610b35565b89856dffffffffffffffffffffffffffff160383035b9050600089856dffffffffffffffffffffffffffff16038311610b59576000610b6f565b89856dffffffffffffffffffffffffffff160383035b90506000821180610b805750600081115b610bd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180612b546024913960400191505060405180910390fd5b6000610c09610beb84600363ffffffff6121e816565b610bfd876103e863ffffffff6121e816565b9063ffffffff61226e16565b90506000610c21610beb84600363ffffffff6121e816565b9050610c59620f4240610c4d6dffffffffffffffffffffffffffff8b8116908b1663ffffffff6121e816565b9063ffffffff6121e816565b610c69838363ffffffff6121e816565b1015610cd657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e697377617056323a204b0000000000000000000000000000000000000000604482015290519081900360640190fd5b5050610ce4848488886122e0565b60408051838152602081018390528082018d9052606081018c9052905173ffffffffffffffffffffffffffffffffffffffff8b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600c55505050505050505050565b6040518060400160405280600a81526020017f556e69737761702056320000000000000000000000000000000000000000000081525081565b6008546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000008304909116917c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b6000610df233848461259c565b5060015b92915050565b60065473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610ee85773ffffffffffffffffffffffffffffffffffffffff84166000908152600260209081526040808320338452909152902054610eb6908363ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff851660009081526002602090815260408083203384529091529020555b610ef384848461260b565b5060019392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60035481565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fb257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff9384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560078054929093169116179055565b60095481565b600a5481565b6000600c5460011461108457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611094610d90565b50600654604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905193955091935060009273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561110e57600080fd5b505afa158015611122573d6000803e3d6000fd5b505050506040513d602081101561113857600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905192935060009273ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b1580156111b157600080fd5b505afa1580156111c5573d6000803e3d6000fd5b505050506040513d60208110156111db57600080fd5b505190506000611201836dffffffffffffffffffffffffffff871663ffffffff61226e16565b90506000611225836dffffffffffffffffffffffffffff871663ffffffff61226e16565b9050600061123387876126ec565b600054909150806112705761125c6103e8610bfd611257878763ffffffff6121e816565b612878565b985061126b60006103e86128ca565b6112cd565b6112ca6dffffffffffffffffffffffffffff8916611294868463ffffffff6121e816565b8161129b57fe5b046dffffffffffffffffffffffffffff89166112bd868563ffffffff6121e816565b816112c457fe5b0461297a565b98505b60008911611326576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612bc16028913960400191505060405180910390fd5b6113308a8a6128ca565b61133c86868a8a6122e0565b811561137e5760085461137a906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600c5550949695505050505050565b60016020526000908152604090205481565b600b5481565b60046020526000908152604090205481565b600080600c5460011461146957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611479610d90565b50600654600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905194965092945073ffffffffffffffffffffffffffffffffffffffff9182169391169160009184916370a08231916024808301926020929190829003018186803b1580156114fb57600080fd5b505afa15801561150f573d6000803e3d6000fd5b505050506040513d602081101561152557600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191925060009173ffffffffffffffffffffffffffffffffffffffff8516916370a08231916024808301926020929190829003018186803b15801561159957600080fd5b505afa1580156115ad573d6000803e3d6000fd5b505050506040513d60208110156115c357600080fd5b5051306000908152600160205260408120549192506115e288886126ec565b600054909150806115f9848763ffffffff6121e816565b8161160057fe5b049a5080611614848663ffffffff6121e816565b8161161b57fe5b04995060008b11801561162e575060008a115b611683576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612b996028913960400191505060405180910390fd5b61168d3084612992565b611698878d8d611fdb565b6116a3868d8c611fdb565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8916916370a08231916024808301926020929190829003018186803b15801561170f57600080fd5b505afa158015611723573d6000803e3d6000fd5b505050506040513d602081101561173957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191965073ffffffffffffffffffffffffffffffffffffffff8816916370a0823191602480820192602092909190829003018186803b1580156117ab57600080fd5b505afa1580156117bf573d6000803e3d6000fd5b505050506040513d60208110156117d557600080fd5b505193506117e585858b8b6122e0565b811561182757600854611823906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b604080518c8152602081018c9052815173ffffffffffffffffffffffffffffffffffffffff8f169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a35050505050505050506001600c81905550915091565b6040518060400160405280600681526020017f554e492d5632000000000000000000000000000000000000000000000000000081525081565b6000610df233848461260b565b6103e881565b600c5460011461194f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654600754600854604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff9485169490931692611a2b9285928792611a26926dffffffffffffffffffffffffffff169185916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b505afa158015611a02573d6000803e3d6000fd5b505050506040513d6020811015611a1857600080fd5b50519063ffffffff61226e16565b611fdb565b600854604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611aca9284928792611a26926e01000000000000000000000000000090046dffffffffffffffffffffffffffff169173ffffffffffffffffffffffffffffffffffffffff8616916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b50506001600c5550565b60055473ffffffffffffffffffffffffffffffffffffffff1681565b60075473ffffffffffffffffffffffffffffffffffffffff1681565b42841015611b7b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e697377617056323a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b60035473ffffffffffffffffffffffffffffffffffffffff80891660008181526004602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015611cdc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611d5757508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611dc257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f556e697377617056323a20494e56414c49445f5349474e415455524500000000604482015290519081900360640190fd5b611dcd89898961259c565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b600c54600114611e6657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611fd49273ffffffffffffffffffffffffffffffffffffffff16916370a08231916024808301926020929190829003018186803b158015611edd57600080fd5b505afa158015611ef1573d6000803e3d6000fd5b505050506040513d6020811015611f0757600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015611f7a57600080fd5b505afa158015611f8e573d6000803e3d6000fd5b505050506040513d6020811015611fa457600080fd5b50516008546dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004166122e0565b6001600c55565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602091820152815173ffffffffffffffffffffffffffffffffffffffff85811660248301526044808301869052845180840390910181526064909201845291810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251815160009460609489169392918291908083835b602083106120e157805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016120a4565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612143576040519150601f19603f3d011682016040523d82523d6000602084013e612148565b606091505b5091509150818015612176575080511580612176575080806020019051602081101561217357600080fd5b50515b6121e157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f556e697377617056323a205452414e534645525f4641494c4544000000000000604482015290519081900360640190fd5b5050505050565b60008115806122035750508082028282828161220057fe5b04145b610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b80820382811115610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6dffffffffffffffffffffffffffff841180159061230c57506dffffffffffffffffffffffffffff8311155b61237757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f556e697377617056323a204f564552464c4f5700000000000000000000000000604482015290519081900360640190fd5b60085463ffffffff428116917c0100000000000000000000000000000000000000000000000000000000900481168203908116158015906123c757506dffffffffffffffffffffffffffff841615155b80156123e257506dffffffffffffffffffffffffffff831615155b15612492578063ffffffff16612425856123fb86612a57565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169063ffffffff612a7b16565b600980547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092169290920201905563ffffffff8116612465846123fb87612a57565b600a80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216929092020190555b600880547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff888116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e0100000000000000000000000000008883168102919091177bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff871602179283905560408051848416815291909304909116602082015281517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1929181900390910190a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054612641908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600160205260408082209390935590841681522054612683908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b15801561275757600080fd5b505afa15801561276b573d6000803e3d6000fd5b505050506040513d602081101561278157600080fd5b5051600b5473ffffffffffffffffffffffffffffffffffffffff821615801594509192509061286457801561285f5760006127d86112576dffffffffffffffffffffffffffff88811690881663ffffffff6121e816565b905060006127e583612878565b90508082111561285c576000612813612804848463ffffffff61226e16565b6000549063ffffffff6121e816565b905060006128388361282c86600563ffffffff6121e816565b9063ffffffff612abc16565b9050600081838161284557fe5b04905080156128585761285887826128ca565b5050505b50505b612870565b8015612870576000600b555b505092915050565b600060038211156128bb575080600160028204015b818110156128b5578091506002818285816128a457fe5b0401816128ad57fe5b04905061288d565b506128c5565b81156128c5575060015b919050565b6000546128dd908263ffffffff612abc16565b600090815573ffffffffffffffffffffffffffffffffffffffff8316815260016020526040902054612915908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000818310612989578161298b565b825b9392505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160205260409020546129c8908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001602052604081209190915554612a02908263ffffffff61226e16565b600090815560408051838152905173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a35050565b6dffffffffffffffffffffffffffff166e0100000000000000000000000000000290565b60006dffffffffffffffffffffffffffff82167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841681612ab457fe5b049392505050565b80820182811015610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fdfe556e697377617056323a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f494e5055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f4c4951554944495459556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4255524e4544556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4d494e544544a265627a7a723158207dca18479e58487606bf70c79e44d8dee62353c9ee6d01f9a9d70885b8765f2264736f6c63430005100032") [macro]