Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
96a7781a
Unverified
Commit
96a7781a
authored
Oct 28, 2023
by
Mark Tyneway
Committed by
GitHub
Oct 28, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #7540 from ethereum-optimism/jm/safe-liveness
Safe liveness checking module and guard
parents
cfc08e23
43cb263a
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
2480 additions
and
6 deletions
+2480
-6
.gitmodules
.gitmodules
+0
-3
codecov.yml
codecov.yml
+2
-1
mips_more.go
op-bindings/bindings/mips_more.go
+1
-1
preimageoracle_more.go
op-bindings/bindings/preimageoracle_more.go
+1
-1
.gas-snapshot
packages/contracts-bedrock/.gas-snapshot
+27
-0
semver-lock.json
packages/contracts-bedrock/semver-lock.json
+2
-0
LivenessGuard.sol
packages/contracts-bedrock/src/Safe/LivenessGuard.sol
+159
-0
LivenessModule.sol
packages/contracts-bedrock/src/Safe/LivenessModule.sol
+231
-0
SafeSigners.sol
packages/contracts-bedrock/src/Safe/SafeSigners.sol
+86
-0
LivenessGuard.t.sol
packages/contracts-bedrock/test/LivenessGuard.t.sol
+327
-0
LivenessModule.t.sol
packages/contracts-bedrock/test/LivenessModule.t.sol
+512
-0
SafeSigners.t.sol
packages/contracts-bedrock/test/SafeSigners.t.sol
+112
-0
CompatibilityFallbackHandler_1_3_0.sol
...ck/test/safe-tools/CompatibilityFallbackHandler_1_3_0.sol
+213
-0
SafeTestTools.sol
packages/contracts-bedrock/test/safe-tools/SafeTestTools.sol
+645
-0
safe-liveness-checking.md
specs/safe-liveness-checking.md
+162
-0
No files found.
.gitmodules
View file @
96a7781a
...
@@ -17,6 +17,3 @@
...
@@ -17,6 +17,3 @@
path = packages/contracts-bedrock/lib/safe-contracts
path = packages/contracts-bedrock/lib/safe-contracts
url = https://github.com/safe-global/safe-contracts
url = https://github.com/safe-global/safe-contracts
branch = v1.4.0
branch = v1.4.0
codecov.yml
View file @
96a7781a
...
@@ -9,8 +9,9 @@ comment:
...
@@ -9,8 +9,9 @@ comment:
ignore
:
ignore
:
-
"
op-e2e"
-
"
op-e2e"
-
"
**/*.t.sol"
-
"
op-bindings/bindings/*.go"
-
"
op-bindings/bindings/*.go"
-
"
**/*.t.sol"
-
"
packages/contracts-bedrock/test/**/*.sol"
-
"
packages/contracts-bedrock/contracts/vendor/WETH9.sol"
-
"
packages/contracts-bedrock/contracts/vendor/WETH9.sol"
-
'
packages/contracts-bedrock/contracts/EAS/**/*.sol'
-
'
packages/contracts-bedrock/contracts/EAS/**/*.sol'
coverage
:
coverage
:
...
...
op-bindings/bindings/mips_more.go
View file @
96a7781a
...
@@ -15,7 +15,7 @@ var MIPSStorageLayout = new(solc.StorageLayout)
...
@@ -15,7 +15,7 @@ var MIPSStorageLayout = new(solc.StorageLayout)
var
MIPSDeployedBin
=
"0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d01461006b578063836e7b32146100af575b600080fd5b610051634000000081565b60405163ffffffff90911681526020015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610062565b6100c26100bd366004611d2e565b6100d0565b604051908152602001610062565b60006100da611c5b565b608081146100e757600080fd5b604051610600146100f757600080fd5b6084871461010457600080fd5b6101a4851461011257600080fd5b8635608052602087013560a052604087013560e090811c60c09081526044890135821c82526048890135821c61010052604c890135821c610120526050890135821c61014052605489013590911c61016052605888013560f890811c610180526059890135901c6101a052605a880135901c6101c0526102006101e0819052606288019060005b60208110156101bd57823560e01c8252600490920191602090910190600101610199565b505050806101200151156101db576101d361061b565b915050610612565b6101408101805160010167ffffffffffffffff16905260608101516000906102039082610737565b9050603f601a82901c16600281148061022257508063ffffffff166003145b156102775760006002836303ffffff1663ffffffff16901b846080015163f00000001617905061026c8263ffffffff1660021461026057601f610263565b60005b60ff16826107f3565b945050505050610612565b6101608301516000908190601f601086901c81169190601587901c16602081106102a3576102a3611da2565b602002015192508063ffffffff851615806102c457508463ffffffff16601c145b156102fb578661016001518263ffffffff16602081106102e6576102e6611da2565b6020020151925050601f600b86901c166103b7565b60208563ffffffff16101561035d578463ffffffff16600c148061032557508463ffffffff16600d145b8061033657508463ffffffff16600e145b15610347578561ffff1692506103b7565b6103568661ffff1660106108e4565b92506103b7565b60288563ffffffff1610158061037957508463ffffffff166022145b8061038a57508463ffffffff166026145b156103b7578661016001518263ffffffff16602081106103ac576103ac611da2565b602002015192508190505b60048563ffffffff16101580156103d4575060088563ffffffff16105b806103e557508463ffffffff166001145b15610404576103f685878487610957565b975050505050505050610612565b63ffffffff6000602087831610610469576104248861ffff1660106108e4565b9095019463fffffffc861661043a816001610737565b915060288863ffffffff161015801561045a57508763ffffffff16603014155b1561046757809250600093505b505b600061047789888885610b67565b63ffffffff9081169150603f8a1690891615801561049c575060088163ffffffff1610155b80156104ae5750601c8163ffffffff16105b1561058b578063ffffffff16600814806104ce57508063ffffffff166009145b15610505576104f38163ffffffff166008146104ea57856104ed565b60005b896107f3565b9b505050505050505050505050610612565b8063ffffffff16600a03610525576104f3858963ffffffff8a16156112f7565b8063ffffffff16600b03610546576104f3858963ffffffff8a1615156112f7565b8063ffffffff16600c0361055d576104f38d6113dd565b60108163ffffffff161015801561057a5750601c8163ffffffff16105b1561058b576104f381898988611914565b8863ffffffff1660381480156105a6575063ffffffff861615155b156105db5760018b61016001518763ffffffff16602081106105ca576105ca611da2565b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146105f8576105f884600184611b0e565b610604858360016112f7565b9b5050505050505050505050505b95945050505050565b60408051608051815260a051602082015260dc519181019190915260fc51604482015261011c51604882015261013c51604c82015261015c51605082015261017c5160548201526101805161019f5160588301526101a0516101bf5160598401526101d851605a840152600092610200929091606283019190855b60208110156106ba57601c8601518452602090950194600490930192600101610696565b506000835283830384a06000945080600181146106da5760039550610702565b8280156106f257600181146106fb5760029650610700565b60009650610700565b600196505b505b50505081900390207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660f89190911b17919050565b60008061074383611bb2565b9050600384161561075357600080fd5b6020810190358460051c8160005b601b8110156107b95760208501943583821c6001168015610789576001811461079e576107af565b600084815260208390526040902093506107af565b600082815260208590526040902093505b5050600101610761565b5060805191508181146107d457630badf00d60005260206000fd5b5050601f94909416601c0360031b9390931c63ffffffff169392505050565b60006107fd611c5b565b60809050806060015160040163ffffffff16816080015163ffffffff1614610886576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6a756d7020696e2064656c617920736c6f74000000000000000000000000000060448201526064015b60405180910390fd5b60608101805160808301805163ffffffff9081169093528583169052908516156108dc57806008018261016001518663ffffffff16602081106108cb576108cb611da2565b63ffffffff90921660209290920201525b61061261061b565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b0182610941576000610943565b815b90861663ffffffff16179250505092915050565b6000610961611c5b565b608090506000816060015160040163ffffffff16826080015163ffffffff16146109e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6272616e636820696e2064656c617920736c6f74000000000000000000000000604482015260640161087d565b8663ffffffff1660041480610a0257508663ffffffff166005145b15610a7e5760008261016001518663ffffffff1660208110610a2657610a26611da2565b602002015190508063ffffffff168563ffffffff16148015610a4e57508763ffffffff166004145b80610a7657508063ffffffff168563ffffffff1614158015610a7657508763ffffffff166005145b915050610afb565b8663ffffffff16600603610a9b5760008460030b13159050610afb565b8663ffffffff16600703610ab75760008460030b139050610afb565b8663ffffffff16600103610afb57601f601087901c166000819003610ae05760008560030b1291505b8063ffffffff16600103610af95760008560030b121591505b505b606082018051608084015163ffffffff169091528115610b41576002610b268861ffff1660106108e4565b63ffffffff90811690911b8201600401166080840152610b53565b60808301805160040163ffffffff1690525b610b5b61061b565b98975050505050505050565b6000603f601a86901c16801580610b96575060088163ffffffff1610158015610b965750600f8163ffffffff16105b15610fec57603f86168160088114610bdd5760098114610be657600a8114610bef57600b8114610bf857600c8114610c0157600d8114610c0a57600e8114610c1357610c18565b60209150610c18565b60219150610c18565b602a9150610c18565b602b9150610c18565b60249150610c18565b60259150610c18565b602691505b508063ffffffff16600003610c3f5750505063ffffffff8216601f600686901c161b6112ef565b8063ffffffff16600203610c655750505063ffffffff8216601f600686901c161c6112ef565b8063ffffffff16600303610c9b57601f600688901c16610c9163ffffffff8716821c60208390036108e4565b93505050506112ef565b8063ffffffff16600403610cbd5750505063ffffffff8216601f84161b6112ef565b8063ffffffff16600603610cdf5750505063ffffffff8216601f84161c6112ef565b8063ffffffff16600703610d1257610d098663ffffffff168663ffffffff16901c876020036108e4565b925050506112ef565b8063ffffffff16600803610d2a5785925050506112ef565b8063ffffffff16600903610d425785925050506112ef565b8063ffffffff16600a03610d5a5785925050506112ef565b8063ffffffff16600b03610d725785925050506112ef565b8063ffffffff16600c03610d8a5785925050506112ef565b8063ffffffff16600f03610da25785925050506112ef565b8063ffffffff16601003610dba5785925050506112ef565b8063ffffffff16601103610dd25785925050506112ef565b8063ffffffff16601203610dea5785925050506112ef565b8063ffffffff16601303610e025785925050506112ef565b8063ffffffff16601803610e1a5785925050506112ef565b8063ffffffff16601903610e325785925050506112ef565b8063ffffffff16601a03610e4a5785925050506112ef565b8063ffffffff16601b03610e625785925050506112ef565b8063ffffffff16602003610e7b575050508282016112ef565b8063ffffffff16602103610e94575050508282016112ef565b8063ffffffff16602203610ead575050508183036112ef565b8063ffffffff16602303610ec6575050508183036112ef565b8063ffffffff16602403610edf575050508282166112ef565b8063ffffffff16602503610ef8575050508282176112ef565b8063ffffffff16602603610f11575050508282186112ef565b8063ffffffff16602703610f2b57505050828217196112ef565b8063ffffffff16602a03610f5c578460030b8660030b12610f4d576000610f50565b60015b60ff16925050506112ef565b8063ffffffff16602b03610f84578463ffffffff168663ffffffff1610610f4d576000610f50565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e00000000000000000000000000604482015260640161087d565b50610f84565b8063ffffffff16601c0361107057603f86166002819003611012575050508282026112ef565b8063ffffffff166020148061102d57508063ffffffff166021145b15610fe6578063ffffffff16602003611044579419945b60005b6380000000871615611066576401fffffffe600197881b169601611047565b92506112ef915050565b8063ffffffff16600f0361109257505065ffffffff0000601083901b166112ef565b8063ffffffff166020036110ce576110c68560031660080260180363ffffffff168463ffffffff16901c60ff1660086108e4565b9150506112ef565b8063ffffffff16602103611103576110c68560021660080260100363ffffffff168463ffffffff16901c61ffff1660106108e4565b8063ffffffff1660220361113257505063ffffffff60086003851602811681811b198416918316901b176112ef565b8063ffffffff1660230361114957829150506112ef565b8063ffffffff1660240361117b578460031660080260180363ffffffff168363ffffffff16901c60ff169150506112ef565b8063ffffffff166025036111ae578460021660080260100363ffffffff168363ffffffff16901c61ffff169150506112ef565b8063ffffffff166026036111e057505063ffffffff60086003851602601803811681811c198416918316901c176112ef565b8063ffffffff1660280361121657505060ff63ffffffff60086003861602601803811682811b9091188316918416901b176112ef565b8063ffffffff1660290361124d57505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b176112ef565b8063ffffffff16602a0361127c57505063ffffffff60086003851602811681811c198316918416901c176112ef565b8063ffffffff16602b0361129357839150506112ef565b8063ffffffff16602e036112c557505063ffffffff60086003851602601803811681811b198316918416901b176112ef565b8063ffffffff166030036112dc57829150506112ef565b8063ffffffff16603803610f8457839150505b949350505050565b6000611301611c5b565b506080602063ffffffff861610611374576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c6964207265676973746572000000000000000000000000000000000000604482015260640161087d565b63ffffffff8516158015906113865750825b156113ba57838161016001518663ffffffff16602081106113a9576113a9611da2565b63ffffffff90921660209290920201525b60808101805163ffffffff8082166060850152600490910116905261061261061b565b60006113e7611c5b565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa036114615781610fff81161561143057610fff811661100003015b8363ffffffff166000036114575760e08801805163ffffffff83820116909152955061145b565b8395505b506118d3565b8563ffffffff16610fcd0361147c57634000000094506118d3565b8563ffffffff166110180361149457600194506118d3565b8563ffffffff16611096036114ca57600161012088015260ff83166101008801526114bd61061b565b9998505050505050505050565b8563ffffffff16610fa3036117365763ffffffff8316156118d3577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb63ffffffff8416016116f05760006115258363fffffffc166001610737565b60208901519091508060001a60010361159457604080516000838152336020528d83526060902091527effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790505b6040808a015190517fe03110e10000000000000000000000000000000000000000000000000000000081526004810183905263ffffffff9091166024820152600090819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063e03110e1906044016040805180830381865afa158015611635573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116599190611dd1565b91509150600386168060040382811015611671578092505b508186101561167e578591505b8260088302610100031c9250826008828460040303021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119871617955050506116d58663fffffffc16600186611b0e565b60408b018051820163ffffffff169052975061173192505050565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd63ffffffff841601611725578094506118d3565b63ffffffff9450600993505b6118d3565b8563ffffffff16610fa4036118275763ffffffff831660011480611760575063ffffffff83166002145b80611771575063ffffffff83166004145b1561177e578094506118d3565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa63ffffffff8416016117255760006117be8363fffffffc166001610737565b602089015190915060038416600403838110156117d9578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b176020880152600060408801529350836118d3565b8563ffffffff16610fd7036118d3578163ffffffff166003036118c75763ffffffff8316158061185d575063ffffffff83166005145b8061186e575063ffffffff83166003145b1561187c57600094506118d3565b63ffffffff831660011480611897575063ffffffff83166002145b806118a8575063ffffffff83166006145b806118b9575063ffffffff83166004145b1561172557600194506118d3565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b015260040190911690526114bd61061b565b600061191e611c5b565b506080600063ffffffff871660100361193c575060c0810151611aa5565b8663ffffffff1660110361195b5763ffffffff861660c0830152611aa5565b8663ffffffff16601203611974575060a0810151611aa5565b8663ffffffff166013036119935763ffffffff861660a0830152611aa5565b8663ffffffff166018036119c75763ffffffff600387810b9087900b02602081901c821660c08501521660a0830152611aa5565b8663ffffffff166019036119f85763ffffffff86811681871602602081901c821660c08501521660a0830152611aa5565b8663ffffffff16601a03611a4e578460030b8660030b81611a1b57611a1b611df5565b0763ffffffff1660c0830152600385810b9087900b81611a3d57611a3d611df5565b0563ffffffff1660a0830152611aa5565b8663ffffffff16601b03611aa5578463ffffffff168663ffffffff1681611a7757611a77611df5565b0663ffffffff90811660c084015285811690871681611a9857611a98611df5565b0463ffffffff1660a08301525b63ffffffff841615611ae057808261016001518563ffffffff1660208110611acf57611acf611da2565b63ffffffff90921660209290920201525b60808201805163ffffffff80821660608601526004909101169052611b0361061b565b979650505050505050565b6000611b1983611bb2565b90506003841615611b2957600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b811015611ba75760208401933582821c6001168015611b775760018114611b8c57611b9d565b60008581526020839052604090209450611b9d565b600082815260208690526040902094505b5050600101611b4f565b505060805250505050565b60ff8116610380026101a4810190369061052401811015611c55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f636865636b207468617420746865726520697320656e6f7567682063616c6c6460448201527f6174610000000000000000000000000000000000000000000000000000000000606482015260840161087d565b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611cc1611cc6565b905290565b6040518061040001604052806020906020820280368337509192915050565b60008083601f840112611cf757600080fd5b50813567ffffffffffffffff811115611d0f57600080fd5b602083019150836020828501011115611d2757600080fd5b9250929050565b600080600080600060608688031215611d4657600080fd5b853567ffffffffffffffff80821115611d5e57600080fd5b611d6a89838a01611ce5565b90975095506020880135915080821115611d8357600080fd5b50611d9088828901611ce5565b96999598509660400135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008060408385031215611de457600080fd5b505080516020909101519092909150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea164736f6c634300080f000a"
var
MIPSDeployedBin
=
"0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d01461006b578063836e7b32146100af575b600080fd5b610051634000000081565b60405163ffffffff90911681526020015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610062565b6100c26100bd366004611d2e565b6100d0565b604051908152602001610062565b60006100da611c5b565b608081146100e757600080fd5b604051610600146100f757600080fd5b6084871461010457600080fd5b6101a4851461011257600080fd5b8635608052602087013560a052604087013560e090811c60c09081526044890135821c82526048890135821c61010052604c890135821c610120526050890135821c61014052605489013590911c61016052605888013560f890811c610180526059890135901c6101a052605a880135901c6101c0526102006101e0819052606288019060005b60208110156101bd57823560e01c8252600490920191602090910190600101610199565b505050806101200151156101db576101d361061b565b915050610612565b6101408101805160010167ffffffffffffffff16905260608101516000906102039082610737565b9050603f601a82901c16600281148061022257508063ffffffff166003145b156102775760006002836303ffffff1663ffffffff16901b846080015163f00000001617905061026c8263ffffffff1660021461026057601f610263565b60005b60ff16826107f3565b945050505050610612565b6101608301516000908190601f601086901c81169190601587901c16602081106102a3576102a3611da2565b602002015192508063ffffffff851615806102c457508463ffffffff16601c145b156102fb578661016001518263ffffffff16602081106102e6576102e6611da2565b6020020151925050601f600b86901c166103b7565b60208563ffffffff16101561035d578463ffffffff16600c148061032557508463ffffffff16600d145b8061033657508463ffffffff16600e145b15610347578561ffff1692506103b7565b6103568661ffff1660106108e4565b92506103b7565b60288563ffffffff1610158061037957508463ffffffff166022145b8061038a57508463ffffffff166026145b156103b7578661016001518263ffffffff16602081106103ac576103ac611da2565b602002015192508190505b60048563ffffffff16101580156103d4575060088563ffffffff16105b806103e557508463ffffffff166001145b15610404576103f685878487610957565b975050505050505050610612565b63ffffffff6000602087831610610469576104248861ffff1660106108e4565b9095019463fffffffc861661043a816001610737565b915060288863ffffffff161015801561045a57508763ffffffff16603014155b1561046757809250600093505b505b600061047789888885610b67565b63ffffffff9081169150603f8a1690891615801561049c575060088163ffffffff1610155b80156104ae5750601c8163ffffffff16105b1561058b578063ffffffff16600814806104ce57508063ffffffff166009145b15610505576104f38163ffffffff166008146104ea57856104ed565b60005b896107f3565b9b505050505050505050505050610612565b8063ffffffff16600a03610525576104f3858963ffffffff8a16156112f7565b8063ffffffff16600b03610546576104f3858963ffffffff8a1615156112f7565b8063ffffffff16600c0361055d576104f38d6113dd565b60108163ffffffff161015801561057a5750601c8163ffffffff16105b1561058b576104f381898988611914565b8863ffffffff1660381480156105a6575063ffffffff861615155b156105db5760018b61016001518763ffffffff16602081106105ca576105ca611da2565b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146105f8576105f884600184611b0e565b610604858360016112f7565b9b5050505050505050505050505b95945050505050565b60408051608051815260a051602082015260dc519181019190915260fc51604482015261011c51604882015261013c51604c82015261015c51605082015261017c5160548201526101805161019f5160588301526101a0516101bf5160598401526101d851605a840152600092610200929091606283019190855b60208110156106ba57601c8601518452602090950194600490930192600101610696565b506000835283830384a06000945080600181146106da5760039550610702565b8280156106f257600181146106fb5760029650610700565b60009650610700565b600196505b505b50505081900390207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660f89190911b17919050565b60008061074383611bb2565b9050600384161561075357600080fd5b6020810190358460051c8160005b601b8110156107b95760208501943583821c6001168015610789576001811461079e576107af565b600084815260208390526040902093506107af565b600082815260208590526040902093505b5050600101610761565b5060805191508181146107d457630badf00d60005260206000fd5b5050601f94909416601c0360031b9390931c63ffffffff169392505050565b60006107fd611c5b565b60809050806060015160040163ffffffff16816080015163ffffffff1614610886576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6a756d7020696e2064656c617920736c6f74000000000000000000000000000060448201526064015b60405180910390fd5b60608101805160808301805163ffffffff9081169093528583169052908516156108dc57806008018261016001518663ffffffff16602081106108cb576108cb611da2565b63ffffffff90921660209290920201525b61061261061b565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b0182610941576000610943565b815b90861663ffffffff16179250505092915050565b6000610961611c5b565b608090506000816060015160040163ffffffff16826080015163ffffffff16146109e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6272616e636820696e2064656c617920736c6f74000000000000000000000000604482015260640161087d565b8663ffffffff1660041480610a0257508663ffffffff166005145b15610a7e5760008261016001518663ffffffff1660208110610a2657610a26611da2565b602002015190508063ffffffff168563ffffffff16148015610a4e57508763ffffffff166004145b80610a7657508063ffffffff168563ffffffff1614158015610a7657508763ffffffff166005145b915050610afb565b8663ffffffff16600603610a9b5760008460030b13159050610afb565b8663ffffffff16600703610ab75760008460030b139050610afb565b8663ffffffff16600103610afb57601f601087901c166000819003610ae05760008560030b1291505b8063ffffffff16600103610af95760008560030b121591505b505b606082018051608084015163ffffffff169091528115610b41576002610b268861ffff1660106108e4565b63ffffffff90811690911b8201600401166080840152610b53565b60808301805160040163ffffffff1690525b610b5b61061b565b98975050505050505050565b6000603f601a86901c16801580610b96575060088163ffffffff1610158015610b965750600f8163ffffffff16105b15610fec57603f86168160088114610bdd5760098114610be657600a8114610bef57600b8114610bf857600c8114610c0157600d8114610c0a57600e8114610c1357610c18565b60209150610c18565b60219150610c18565b602a9150610c18565b602b9150610c18565b60249150610c18565b60259150610c18565b602691505b508063ffffffff16600003610c3f5750505063ffffffff8216601f600686901c161b6112ef565b8063ffffffff16600203610c655750505063ffffffff8216601f600686901c161c6112ef565b8063ffffffff16600303610c9b57601f600688901c16610c9163ffffffff8716821c60208390036108e4565b93505050506112ef565b8063ffffffff16600403610cbd5750505063ffffffff8216601f84161b6112ef565b8063ffffffff16600603610cdf5750505063ffffffff8216601f84161c6112ef565b8063ffffffff16600703610d1257610d098663ffffffff168663ffffffff16901c876020036108e4565b925050506112ef565b8063ffffffff16600803610d2a5785925050506112ef565b8063ffffffff16600903610d425785925050506112ef565b8063ffffffff16600a03610d5a5785925050506112ef565b8063ffffffff16600b03610d725785925050506112ef565b8063ffffffff16600c03610d8a5785925050506112ef565b8063ffffffff16600f03610da25785925050506112ef565b8063ffffffff16601003610dba5785925050506112ef565b8063ffffffff16601103610dd25785925050506112ef565b8063ffffffff16601203610dea5785925050506112ef565b8063ffffffff16601303610e025785925050506112ef565b8063ffffffff16601803610e1a5785925050506112ef565b8063ffffffff16601903610e325785925050506112ef565b8063ffffffff16601a03610e4a5785925050506112ef565b8063ffffffff16601b03610e625785925050506112ef565b8063ffffffff16602003610e7b575050508282016112ef565b8063ffffffff16602103610e94575050508282016112ef565b8063ffffffff16602203610ead575050508183036112ef565b8063ffffffff16602303610ec6575050508183036112ef565b8063ffffffff16602403610edf575050508282166112ef565b8063ffffffff16602503610ef8575050508282176112ef565b8063ffffffff16602603610f11575050508282186112ef565b8063ffffffff16602703610f2b57505050828217196112ef565b8063ffffffff16602a03610f5c578460030b8660030b12610f4d576000610f50565b60015b60ff16925050506112ef565b8063ffffffff16602b03610f84578463ffffffff168663ffffffff1610610f4d576000610f50565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e00000000000000000000000000604482015260640161087d565b50610f84565b8063ffffffff16601c0361107057603f86166002819003611012575050508282026112ef565b8063ffffffff166020148061102d57508063ffffffff166021145b15610fe6578063ffffffff16602003611044579419945b60005b6380000000871615611066576401fffffffe600197881b169601611047565b92506112ef915050565b8063ffffffff16600f0361109257505065ffffffff0000601083901b166112ef565b8063ffffffff166020036110ce576110c68560031660080260180363ffffffff168463ffffffff16901c60ff1660086108e4565b9150506112ef565b8063ffffffff16602103611103576110c68560021660080260100363ffffffff168463ffffffff16901c61ffff1660106108e4565b8063ffffffff1660220361113257505063ffffffff60086003851602811681811b198416918316901b176112ef565b8063ffffffff1660230361114957829150506112ef565b8063ffffffff1660240361117b578460031660080260180363ffffffff168363ffffffff16901c60ff169150506112ef565b8063ffffffff166025036111ae578460021660080260100363ffffffff168363ffffffff16901c61ffff169150506112ef565b8063ffffffff166026036111e057505063ffffffff60086003851602601803811681811c198416918316901c176112ef565b8063ffffffff1660280361121657505060ff63ffffffff60086003861602601803811682811b9091188316918416901b176112ef565b8063ffffffff1660290361124d57505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b176112ef565b8063ffffffff16602a0361127c57505063ffffffff60086003851602811681811c198316918416901c176112ef565b8063ffffffff16602b0361129357839150506112ef565b8063ffffffff16602e036112c557505063ffffffff60086003851602601803811681811b198316918416901b176112ef565b8063ffffffff166030036112dc57829150506112ef565b8063ffffffff16603803610f8457839150505b949350505050565b6000611301611c5b565b506080602063ffffffff861610611374576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c6964207265676973746572000000000000000000000000000000000000604482015260640161087d565b63ffffffff8516158015906113865750825b156113ba57838161016001518663ffffffff16602081106113a9576113a9611da2565b63ffffffff90921660209290920201525b60808101805163ffffffff8082166060850152600490910116905261061261061b565b60006113e7611c5b565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa036114615781610fff81161561143057610fff811661100003015b8363ffffffff166000036114575760e08801805163ffffffff83820116909152955061145b565b8395505b506118d3565b8563ffffffff16610fcd0361147c57634000000094506118d3565b8563ffffffff166110180361149457600194506118d3565b8563ffffffff16611096036114ca57600161012088015260ff83166101008801526114bd61061b565b9998505050505050505050565b8563ffffffff16610fa3036117365763ffffffff8316156118d3577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb63ffffffff8416016116f05760006115258363fffffffc166001610737565b60208901519091508060001a60010361159457604080516000838152336020528d83526060902091527effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790505b6040808a015190517fe03110e10000000000000000000000000000000000000000000000000000000081526004810183905263ffffffff9091166024820152600090819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063e03110e1906044016040805180830381865afa158015611635573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116599190611dd1565b91509150600386168060040382811015611671578092505b508186101561167e578591505b8260088302610100031c9250826008828460040303021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119871617955050506116d58663fffffffc16600186611b0e565b60408b018051820163ffffffff169052975061173192505050565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd63ffffffff841601611725578094506118d3565b63ffffffff9450600993505b6118d3565b8563ffffffff16610fa4036118275763ffffffff831660011480611760575063ffffffff83166002145b80611771575063ffffffff83166004145b1561177e578094506118d3565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa63ffffffff8416016117255760006117be8363fffffffc166001610737565b602089015190915060038416600403838110156117d9578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b176020880152600060408801529350836118d3565b8563ffffffff16610fd7036118d3578163ffffffff166003036118c75763ffffffff8316158061185d575063ffffffff83166005145b8061186e575063ffffffff83166003145b1561187c57600094506118d3565b63ffffffff831660011480611897575063ffffffff83166002145b806118a8575063ffffffff83166006145b806118b9575063ffffffff83166004145b1561172557600194506118d3565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b015260040190911690526114bd61061b565b600061191e611c5b565b506080600063ffffffff871660100361193c575060c0810151611aa5565b8663ffffffff1660110361195b5763ffffffff861660c0830152611aa5565b8663ffffffff16601203611974575060a0810151611aa5565b8663ffffffff166013036119935763ffffffff861660a0830152611aa5565b8663ffffffff166018036119c75763ffffffff600387810b9087900b02602081901c821660c08501521660a0830152611aa5565b8663ffffffff166019036119f85763ffffffff86811681871602602081901c821660c08501521660a0830152611aa5565b8663ffffffff16601a03611a4e578460030b8660030b81611a1b57611a1b611df5565b0763ffffffff1660c0830152600385810b9087900b81611a3d57611a3d611df5565b0563ffffffff1660a0830152611aa5565b8663ffffffff16601b03611aa5578463ffffffff168663ffffffff1681611a7757611a77611df5565b0663ffffffff90811660c084015285811690871681611a9857611a98611df5565b0463ffffffff1660a08301525b63ffffffff841615611ae057808261016001518563ffffffff1660208110611acf57611acf611da2565b63ffffffff90921660209290920201525b60808201805163ffffffff80821660608601526004909101169052611b0361061b565b979650505050505050565b6000611b1983611bb2565b90506003841615611b2957600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b811015611ba75760208401933582821c6001168015611b775760018114611b8c57611b9d565b60008581526020839052604090209450611b9d565b600082815260208690526040902094505b5050600101611b4f565b505060805250505050565b60ff8116610380026101a4810190369061052401811015611c55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f636865636b207468617420746865726520697320656e6f7567682063616c6c6460448201527f6174610000000000000000000000000000000000000000000000000000000000606482015260840161087d565b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611cc1611cc6565b905290565b6040518061040001604052806020906020820280368337509192915050565b60008083601f840112611cf757600080fd5b50813567ffffffffffffffff811115611d0f57600080fd5b602083019150836020828501011115611d2757600080fd5b9250929050565b600080600080600060608688031215611d4657600080fd5b853567ffffffffffffffff80821115611d5e57600080fd5b611d6a89838a01611ce5565b90975095506020880135915080821115611d8357600080fd5b50611d9088828901611ce5565b96999598509660400135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008060408385031215611de457600080fd5b505080516020909101519092909150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea164736f6c634300080f000a"
var
MIPSDeployedSourceMap
=
"1131:40054:1
26:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1710:45;;1745:10;1710:45;;;;;188:10:285;176:23;;;158:42;;146:2;131:18;1710:45:126;;;;;;;;2448:99;;;412:42:285;2534:6:126;400:55:285;382:74;;370:2;355:18;2448:99:126;211:251:285;26025:6379:126;;;;;;:::i;:::-;;:::i;:::-;;;1755:25:285;;;1743:2;1728:18;26025:6379:126;1609:177:285;26025:6379:126;26128:7;26171:18;;:::i;:::-;26318:4;26311:5;26308:15;26298:134;;26412:1;26409;26402:12;26298:134;26468:4;26462:11;26475:10;26459:27;26449:136;;26565:1;26562;26555:12;26449:136;26634:3;26615:17;26612:26;26602:151;;26733:1;26730;26723:12;26602:151;26798:3;26783:13;26780:22;26770:146;;26896:1;26893;26886:12;26770:146;27176:24;;27521:4;27222:20;27579:2;27280:21;;27176:24;27338:18;27222:20;27280:21;;;27176:24;27153:21;27149:52;;;27338:18;27222:20;;;27280:21;;;27176:24;27149:52;;27222:20;;27280:21;;;27176:24;27149:52;;27338:18;27222:20;27280:21;;;27176:24;27149:52;;27338:18;27222:20;27280:21;;;27176:24;27149:52;;27338:18;27222:20;27280:21;;;27176:24;27149:52;;;27338:18;27222:20;27280:21;;;27176:24;27153:21;27149:52;;;27338:18;27222:20;27280:21;;;27176:24;27149:52;;27338:18;27222:20;27280:21;;;27176:24;27149:52;;27338:18;27222:20;28197:10;27338:18;28187:21;;;27280;;;;28295:1;28280:77;28305:2;28302:1;28299:9;28280:77;;;27176:24;;27153:21;27149:52;27222:20;;28353:1;27280:21;;;;27164:2;27338:18;;;;28323:1;28316:9;28280:77;;;28284:14;;;28435:5;:12;;;28431:71;;;28474:13;:11;:13::i;:::-;28467:20;;;;;28431:71;28516:10;;;:15;;28530:1;28516:15;;;;;28601:8;;;;-1:-1:-1;;28593:20:126;;-1:-1:-1;28593:7:126;:20::i;:::-;28579:34;-1:-1:-1;28643:10:126;28651:2;28643:10;;;;28720:1;28710:11;;;:26;;;28725:6;:11;;28735:1;28725:11;28710:26;28706:310;;;28866:13;28935:1;28913:4;28920:10;28913:17;28912:24;;;;28883:5;:12;;;28898:10;28883:25;28882:54;28866:70;;28961:40;28972:6;:11;;28982:1;28972:11;:20;;28990:2;28972:20;;;28986:1;28972:20;28961:40;;28994:6;28961:10;:40::i;:::-;28954:47;;;;;;;;28706:310;29265:15;;;;29060:9;;;;29197:4;29191:2;29183:10;;;29182:19;;;29265:15;29290:2;29282:10;;;29281:19;29265:36;;;;;;;:::i;:::-;;;;;;-1:-1:-1;29330:5:126;29354:11;;;;;:29;;;29369:6;:14;;29379:4;29369:14;29354:29;29350:832;;;29446:5;:15;;;29462:5;29446:22;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;29509:4:126;29503:2;29495:10;;;29494:19;29350:832;;;29547:4;29538:6;:13;;;29534:648;;;29668:6;:13;;29678:3;29668:13;:30;;;;29685:6;:13;;29695:3;29685:13;29668:30;:47;;;;29702:6;:13;;29712:3;29702:13;29668:47;29664:253;;;29778:4;29785:6;29778:13;29773:18;;29534:648;;29664:253;29877:21;29880:4;29887:6;29880:13;29895:2;29877;:21::i;:::-;29872:26;;29534:648;;;29951:4;29941:6;:14;;;;:32;;;;29959:6;:14;;29969:4;29959:14;29941:32;:50;;;;29977:6;:14;;29987:4;29977:14;29941:50;29937:245;;;30061:5;:15;;;30077:5;30061:22;;;;;;;;;:::i;:::-;;;;;30056:27;;30162:5;30154:13;;29937:245;30211:1;30201:6;:11;;;;:25;;;;;30225:1;30216:6;:10;;;30201:25;30200:42;;;;30231:6;:11;;30241:1;30231:11;30200:42;30196:125;;;30269:37;30282:6;30290:4;30296:5;30303:2;30269:12;:37::i;:::-;30262:44;;;;;;;;;;;30196:125;30354:13;30335:16;30506:4;30496:14;;;;30492:446;;30575:21;30578:4;30585:6;30578:13;30593:2;30575;:21::i;:::-;30569:27;;;;30633:10;30628:15;;30667:16;30628:15;30681:1;30667:7;:16::i;:::-;30661:22;;30715:4;30705:6;:14;;;;:32;;;;;30723:6;:14;;30733:4;30723:14;;30705:32;30701:223;;;30802:4;30790:16;;30904:1;30896:9;;30701:223;30512:426;30492:446;30971:10;30984:26;30992:4;30998:2;31002;31006:3;30984:7;:26::i;:::-;31013:10;30984:39;;;;-1:-1:-1;31109:4:126;31102:11;;;31141;;;:24;;;;;31164:1;31156:4;:9;;;;31141:24;:39;;;;;31176:4;31169;:11;;;31141:39;31137:860;;;31204:4;:9;;31212:1;31204:9;:22;;;;31217:4;:9;;31225:1;31217:9;31204:22;31200:144;;;31288:37;31299:4;:9;;31307:1;31299:9;:21;;31315:5;31299:21;;;31311:1;31299:21;31322:2;31288:10;:37::i;:::-;31281:44;;;;;;;;;;;;;;;31200:144;31366:4;:11;;31374:3;31366:11;31362:121;;31436:28;31445:5;31452:2;31456:7;;;;31436:8;:28::i;31362:121::-;31504:4;:11;;31512:3;31504:11;31500:121;;31574:28;31583:5;31590:2;31594:7;;;;;31574:8;:28::i;31500:121::-;31691:4;:11;;31699:3;31691:11;31687:93;;31733:28;31747:13;31733;:28::i;31687:93::-;31883:4;31875;:12;;;;:27;;;;;31898:4;31891;:11;;;31875:27;31871:112;;;31933:31;31944:4;31950:2;31954;31958:5;31933:10;:31::i;31871:112::-;32057:6;:14;;32067:4;32057:14;:28;;;;-1:-1:-1;32075:10:126;;;;;32057:28;32053:93;;;32130:1;32105:5;:15;;;32121:5;32105:22;;;;;;;;;:::i;:::-;:26;;;;:22;;;;;;:26;32053:93;32192:9;:26;;32205:13;32192:26;32188:92;;32238:27;32247:9;32258:1;32261:3;32238:8;:27::i;:::-;32361:26;32370:5;32377:3;32382:4;32361:8;:26::i;:::-;32354:33;;;;;;;;;;;;;26025:6379;;;;;;;;:::o;3087:2334::-;3634:4;3628:11;;3550:4;3353:31;3342:43;;3413:13;3353:31;3752:2;3452:13;;3342:43;3359:24;3353:31;3452:13;;;3342:43;;;;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3413:13;4180:11;3359:24;3353:31;3452:13;;;3342:43;3413:13;4275:11;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3128:12;;4415:13;;3628:11;;3452:13;;;;4180:11;3128:12;4495:84;4520:2;4517:1;4514:9;4495:84;;;3369:13;3359:24;;3353:31;3342:43;;3373:2;3413:13;;;;4575:1;3452:13;;;;4538:1;4531:9;4495:84;;;4499:14;4642:1;4638:2;4631:13;4737:5;4733:2;4729:14;4722:5;4717:27;4811:1;4797:15;;4832:6;4856:1;4851:273;;;;5191:1;5181:11;;4825:369;;4851:273;4883:8;4941:22;;;;5020:1;5015:22;;;;5107:1;5097:11;;4876:234;;4941:22;4960:1;4950:11;;4941:22;;5015;5034:1;5024:11;;4876:234;;4825:369;-1:-1:-1;;;5317:14:126;;;5300:32;;5360:19;5356:30;5392:3;5388:16;;;;5353:52;;3087:2334;-1:-1:-1;3087:2334:126:o;21746:1831::-;21819:11;21930:14;21947:24;21959:11;21947;:24::i;:::-;21930:41;;22079:1;22072:5;22068:13;22065:33;;;22094:1;22091;22084:12;22065:33;22227:2;22215:15;;;22168:20;22657:5;22654:1;22650:13;22692:4;22728:1;22713:343;22738:2;22735:1;22732:9;22713:343;;;22861:2;22849:15;;;22798:20;22896:12;;;22910:1;22892:20;22933:42;;;;23001:1;22996:42;;;;22885:153;;22933:42;22391:1;22384:12;;;22424:2;22417:13;;;22469:2;22456:16;;22942:31;;22933:42;;22996;22391:1;22384:12;;;22424:2;22417:13;;;22469:2;22456:16;;23005:31;;22885:153;-1:-1:-1;;22756:1:126;22749:9;22713:343;;;22717:14;23166:4;23160:11;23145:26;;23252:7;23246:4;23243:17;23233:124;;23294:10;23291:1;23284:21;23336:2;23333:1;23326:13;23233:124;-1:-1:-1;;23484:2:126;23473:14;;;;23461:10;23457:31;23454:1;23450:39;23518:16;;;;23536:10;23514:33;;21746:1831;-1:-1:-1;;;21746:1831:126:o;18856:823::-;18925:12;19012:18;;:::i;:::-;19080:4;19071:13;;19132:5;:8;;;19143:1;19132:12;19116:28;;:5;:12;;;:28;;;19112:95;;19164:28;;;;;2182:2:285;19164:28:126;;;2164:21:285;2221:2;2201:18;;;2194:30;2260:20;2240:18;;;2233:48;2298:18;;19164:28:126;;;;;;;;19112:95;19296:8;;;;;19329:12;;;;;19318:23;;;;;;;19355:20;;;;;19296:8;19487:13;;;19483:90;;19548:6;19557:1;19548:10;19520:5;:15;;;19536:8;19520:25;;;;;;;;;:::i;:::-;:38;;;;:25;;;;;;:38;19483:90;19649:13;:11;:13::i;2645:339::-;2706:11;2770:18;;;;2779:8;;;;2770:18;;;;;;2769:25;;;;;2786:1;2833:2;:9;;;2827:16;;;;;2826:22;;2825:32;;;;;;;2887:9;;2886:15;2769:25;2944:21;;2964:1;2944:21;;;2955:6;2944:21;2929:11;;;;;:37;;-1:-1:-1;;;2645:339:126;;;;:::o;13732:2026::-;13829:12;13915:18;;:::i;:::-;13983:4;13974:13;;14015:17;14075:5;:8;;;14086:1;14075:12;14059:28;;:5;:12;;;:28;;;14055:97;;14107:30;;;;;2529:2:285;14107:30:126;;;2511:21:285;2568:2;2548:18;;;2541:30;2607:22;2587:18;;;2580:50;2647:18;;14107:30:126;2327:344:285;14055:97:126;14222:7;:12;;14233:1;14222:12;:28;;;;14238:7;:12;;14249:1;14238:12;14222:28;14218:947;;;14270:9;14282:5;:15;;;14298:6;14282:23;;;;;;;;;:::i;:::-;;;;;14270:35;;14346:2;14339:9;;:3;:9;;;:25;;;;;14352:7;:12;;14363:1;14352:12;14339:25;14338:58;;;;14377:2;14370:9;;:3;:9;;;;:25;;;;;14383:7;:12;;14394:1;14383:12;14370:25;14323:73;;14252:159;14218:947;;;14508:7;:12;;14519:1;14508:12;14504:661;;14569:1;14561:3;14555:15;;;;14540:30;;14504:661;;;14673:7;:12;;14684:1;14673:12;14669:496;;14733:1;14726:3;14720:14;;;14705:29;;14669:496;;;14854:7;:12;;14865:1;14854:12;14850:315;;14942:4;14936:2;14927:11;;;14926:20;14912:10;14969:8;;;14965:84;;15029:1;15022:3;15016:14;;;15001:29;;14965:84;15070:3;:8;;15077:1;15070:8;15066:85;;15131:1;15123:3;15117:15;;;;15102:30;;15066:85;14868:297;14850:315;15241:8;;;;;15319:12;;;;15308:23;;;;;15475:178;;;;15566:1;15540:22;15543:5;15551:6;15543:14;15559:2;15540;:22::i;:::-;:27;;;;;;;15526:42;;15535:1;15526:42;15511:57;:12;;;:57;15475:178;;;15622:12;;;;;15637:1;15622:16;15607:31;;;;15475:178;15728:13;:11;:13::i;:::-;15721:20;13732:2026;-1:-1:-1;;;;;;;;13732:2026:126:o;32450:8733::-;32537:10;32599;32607:2;32599:10;;;;32638:11;;;:44;;;32664:1;32654:6;:11;;;;:27;;;;;32678:3;32669:6;:12;;;32654:27;32634:8490;;;32723:4;32716:11;;32847:6;32907:3;32902:25;;;;32982:3;32977:25;;;;33056:3;33051:25;;;;33131:3;33126:25;;;;33205:3;33200:25;;;;33278:3;33273:25;;;;33352:3;33347:25;;;;32840:532;;32902:25;32921:4;32913:12;;32902:25;;32977;32996:4;32988:12;;32977:25;;33051;33070:4;33062:12;;33051:25;;33126;33145:4;33137:12;;33126:25;;33200;33219:4;33211:12;;33200:25;;33273;33292:4;33284:12;;33273:25;;33347;33366:4;33358:12;;32840:532;;33435:4;:12;;33443:4;33435:12;33431:4023;;-1:-1:-1;;;33486:9:126;33478:26;;33499:4;33494:1;33486:9;;;33485:18;33478:26;33471:33;;33431:4023;33572:4;:12;;33580:4;33572:12;33568:3886;;-1:-1:-1;;;33623:9:126;33615:26;;33636:4;33631:1;33623:9;;;33622:18;33615:26;33608:33;;33568:3886;33709:4;:12;;33717:4;33709:12;33705:3749;;33774:4;33769:1;33761:9;;;33760:18;33807:27;33761:9;33810:11;;;;33823:2;:10;;;33807:2;:27::i;:::-;33800:34;;;;;;;33705:3749;33903:4;:12;;33911:4;33903:12;33899:3555;;-1:-1:-1;;;33946:17:126;;;33958:4;33953:9;;33946:17;33939:24;;33899:3555;34032:4;:11;;34040:3;34032:11;34028:3426;;-1:-1:-1;;;34074:17:126;;;34086:4;34081:9;;34074:17;34067:24;;34028:3426;34160:4;:12;;34168:4;34160:12;34156:3298;;34203:21;34212:2;34206:8;;:2;:8;;;;34221:2;34216;:7;34203:2;:21::i;:::-;34196:28;;;;;;34156:3298;34473:4;:12;;34481:4;34473:12;34469:2985;;34516:2;34509:9;;;;;;34469:2985;34587:4;:12;;34595:4;34587:12;34583:2871;;34630:2;34623:9;;;;;;34583:2871;34701:4;:12;;34709:4;34701:12;34697:2757;;34744:2;34737:9;;;;;;34697:2757;34815:4;:12;;34823:4;34815:12;34811:2643;;34858:2;34851:9;;;;;;34811:2643;34932:4;:12;;34940:4;34932:12;34928:2526;;34975:2;34968:9;;;;;;34928:2526;35092:4;:12;;35100:4;35092:12;35088:2366;;35135:2;35128:9;;;;;;35088:2366;35206:4;:12;;35214:4;35206:12;35202:2252;;35249:2;35242:9;;;;;;35202:2252;35320:4;:12;;35328:4;35320:12;35316:2138;;35363:2;35356:9;;;;;;35316:2138;35434:4;:12;;35442:4;35434:12;35430:2024;;35477:2;35470:9;;;;;;35430:2024;35548:4;:12;;35556:4;35548:12;35544:1910;;35591:2;35584:9;;;;;;35544:1910;35662:4;:12;;35670:4;35662:12;35658:1796;;35705:2;35698:9;;;;;;35658:1796;35777:4;:12;;35785:4;35777:12;35773:1681;;35820:2;35813:9;;;;;;35773:1681;35890:4;:12;;35898:4;35890:12;35886:1568;;35933:2;35926:9;;;;;;35886:1568;36004:4;:12;;36012:4;36004:12;36000:1454;;36047:2;36040:9;;;;;;36000:1454;36196:4;:12;;36204:4;36196:12;36192:1262;;-1:-1:-1;;;36240:7:126;;;36232:16;;36192:1262;36317:4;:12;;36325:4;36317:12;36313:1141;;-1:-1:-1;;;36361:7:126;;;36353:16;;36313:1141;36437:4;:12;;36445:4;36437:12;36433:1021;;-1:-1:-1;;;36481:7:126;;;36473:16;;36433:1021;36558:4;:12;;36566:4;36558:12;36554:900;;-1:-1:-1;;;36602:7:126;;;36594:16;;36554:900;36678:4;:12;;36686:4;36678:12;36674:780;;-1:-1:-1;;;36722:7:126;;;36714:16;;36674:780;36797:4;:12;;36805:4;36797:12;36793:661;;-1:-1:-1;;;36841:7:126;;;36833:16;;36793:661;36917:4;:12;;36925:4;36917:12;36913:541;;-1:-1:-1;;;36961:7:126;;;36953:16;;36913:541;37037:4;:12;;37045:4;37037:12;37033:421;;-1:-1:-1;;;37082:7:126;;;37080:10;37073:17;;37033:421;37159:4;:12;;37167:4;37159:12;37155:299;;37220:2;37202:21;;37208:2;37202:21;;;:29;;37230:1;37202:29;;;37226:1;37202:29;37195:36;;;;;;;;37155:299;37301:4;:12;;37309:4;37301:12;37297:157;;37349:2;37344:7;;:2;:7;;;:15;;37358:1;37344:15;;37297:157;37406:29;;;;;2878:2:285;37406:29:126;;;2860:21:285;2917:2;2897:18;;;2890:30;2956:21;2936:18;;;2929:49;2995:18;;37406:29:126;2676:343:285;37297:157:126;32684:4784;32634:8490;;;37524:6;:14;;37534:4;37524:14;37520:3590;;37583:4;37576:11;;37658:3;37650:11;;;37646:549;;-1:-1:-1;;;37703:21:126;;;37689:36;;37646:549;37810:4;:12;;37818:4;37810:12;:28;;;;37826:4;:12;;37834:4;37826:12;37810:28;37806:389;;;37870:4;:12;;37878:4;37870:12;37866:83;;37919:3;;;37866:83;37974:8;38012:127;38024:10;38019:15;;:20;38012:127;;38104:8;38071:3;38104:8;;;;;38071:3;38012:127;;;38171:1;-1:-1:-1;38164:8:126;;-1:-1:-1;;38164:8:126;37520:3590;38262:6;:14;;38272:4;38262:14;38258:2852;;-1:-1:-1;;38307:8:126;38313:2;38307:8;;;;38300:15;;38258:2852;38382:6;:14;;38392:4;38382:14;38378:2732;;38427:42;38445:2;38450:1;38445:6;38455:1;38444:12;38439:2;:17;38431:26;;:3;:26;;;;38461:4;38430:35;38467:1;38427:2;:42::i;:::-;38420:49;;;;;38378:2732;38536:6;:14;;38546:4;38536:14;38532:2578;;38581:45;38599:2;38604:1;38599:6;38609:1;38598:12;38593:2;:17;38585:26;;:3;:26;;;;38615:6;38584:37;38623:2;38581;:45::i;38532:2578::-;38694:6;:14;;38704:4;38694:14;38690:2420;;-1:-1:-1;;38745:21:126;38764:1;38759;38754:6;;38753:12;38745:21;;38802:36;;;38873:5;38868:10;;38745:21;;;;;38867:18;38860:25;;38690:2420;38952:6;:14;;38962:4;38952:14;38948:2162;;38997:3;38990:10;;;;;38948:2162;39068:6;:14;;39078:4;39068:14;39064:2046;;39128:2;39133:1;39128:6;39138:1;39127:12;39122:2;:17;39114:26;;:3;:26;;;;39144:4;39113:35;39106:42;;;;;39064:2046;39217:6;:14;;39227:4;39217:14;39213:1897;;39277:2;39282:1;39277:6;39287:1;39276:12;39271:2;:17;39263:26;;:3;:26;;;;39293:6;39262:37;39255:44;;;;;39213:1897;39368:6;:14;;39378:4;39368:14;39364:1746;;-1:-1:-1;;39419:26:126;39443:1;39438;39433:6;;39432:12;39427:2;:17;39419:26;;39481:41;;;39557:5;39552:10;;39419:26;;;;;39551:18;39544:25;;39364:1746;39637:6;:14;;39647:4;39637:14;39633:1477;;-1:-1:-1;;39694:4:126;39688:34;39720:1;39715;39710:6;;39709:12;39704:2;:17;39688:34;;39778:27;;;39758:48;;;39836:10;;39689:9;;;39688:34;;39835:18;39828:25;;39633:1477;39921:6;:14;;39931:4;39921:14;39917:1193;;-1:-1:-1;;39978:6:126;39972:36;40006:1;40001;39996:6;;39995:12;39990:2;:17;39972:36;;40064:29;;;40044:50;;;40124:10;;39973:11;;;39972:36;;40123:18;40116:25;;39917:1193;40210:6;:14;;40220:4;40210:14;40206:904;;-1:-1:-1;;40261:20:126;40279:1;40274;40269:6;;40268:12;40261:20;;40317:36;;;40389:5;40383:11;;40261:20;;;;;40382:19;40375:26;;40206:904;40469:6;:14;;40479:4;40469:14;40465:645;;40514:2;40507:9;;;;;40465:645;40585:6;:14;;40595:4;40585:14;40581:529;;-1:-1:-1;;40636:25:126;40659:1;40654;40649:6;;40648:12;40643:2;:17;40636:25;;40697:41;;;40774:5;40768:11;;40636:25;;;;;40767:19;40760:26;;40581:529;40853:6;:14;;40863:4;40853:14;40849:261;;40898:3;40891:10;;;;;40849:261;40968:6;:14;;40978:4;40968:14;40964:146;;41013:2;41006:9;;;32450:8733;;;;;;;:::o;19960:782::-;20046:12;20133:18;;:::i;:::-;-1:-1:-1;20201:4:126;20308:2;20296:14;;;;20288:41;;;;;;;3226:2:285;20288:41:126;;;3208:21:285;3265:2;3245:18;;;3238:30;3304:16;3284:18;;;3277:44;3338:18;;20288:41:126;3024:338:285;20288:41:126;20425:14;;;;;;;:30;;;20443:12;20425:30;20421:102;;;20504:4;20475:5;:15;;;20491:9;20475:26;;;;;;;;;:::i;:::-;:33;;;;:26;;;;;;:33;20421:102;20578:12;;;;;20567:23;;;;:8;;;:23;20634:1;20619:16;;;20604:31;;;20712:13;:11;:13::i;5582:7764::-;5646:12;5732:18;;:::i;:::-;-1:-1:-1;5910:15:126;;:18;;;;5800:4;6070:18;;;;6114;;;;6158;;;;;5800:4;;5890:17;;;;6070:18;6114;6248;;;6262:4;6248:18;6244:6792;;6298:2;6327:4;6322:9;;:14;6318:144;;6438:4;6433:9;;6425:4;:18;6419:24;6318:144;6483:2;:7;;6489:1;6483:7;6479:161;;6519:10;;;;;6551:16;;;;;;;;6519:10;-1:-1:-1;6479:161:126;;;6619:2;6614:7;;6479:161;6268:386;6244:6792;;;6756:10;:18;;6770:4;6756:18;6752:6284;;1745:10;6794:14;;6752:6284;;;6892:10;:18;;6906:4;6892:18;6888:6148;;6935:1;6930:6;;6888:6148;;;7060:10;:18;;7074:4;7060:18;7056:5980;;7113:4;7098:12;;;:19;7135:26;;;:14;;;:26;7186:13;:11;:13::i;:::-;7179:20;5582:7764;-1:-1:-1;;;;;;;;;5582:7764:126:o;7056:5980::-;7325:10;:18;;7339:4;7325:18;7321:5715;;7476:14;;;7472:2723;7321:5715;7472:2723;7646:22;;;;;7642:2553;;7771:10;7784:27;7792:2;7797:10;7792:15;7809:1;7784:7;:27::i;:::-;7895:17;;;;7771:40;;-1:-1:-1;7895:17:126;7873:19;8045:14;8064:1;8039:26;8035:146;;1676:4:127;1670:11;;1533:21;1787:15;;;1828:8;1822:4;1815:22;1850:27;;;1996:4;1983:18;;2098:17;;2003:19;1979:44;2025:11;1976:61;8093:65:126;;8035:146;8267:20;;;;;8234:54;;;;;;;;3540:25:285;;;8234:54:126;3601:23:285;;;3581:18;;;3574:51;8203:11:126;;;;8234:19;:6;:19;;;;3513:18:285;;8234:54:126;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8202:86;;;;8515:1;8511:2;8507:10;8612:9;8609:1;8605:17;8694:6;8687:5;8684:17;8681:40;;;8714:5;8704:15;;8681:40;;8797:6;8793:2;8790:14;8787:34;;;8817:2;8807:12;;8787:34;8923:3;8918:1;8910:6;8906:14;8901:3;8897:24;8893:34;8886:41;;9023:3;9019:1;9007:9;8998:6;8995:1;8991:14;8987:30;8983:38;8979:48;8972:55;;9178:1;9174;9170;9158:9;9155:1;9151:17;9147:25;9143:33;9139:41;9305:1;9301;9297;9288:6;9276:9;9273:1;9269:17;9265:30;9261:38;9257:46;9253:54;9235:72;;9436:10;9432:15;9426:4;9422:26;9414:34;;9552:3;9544:4;9540:9;9535:3;9531:19;9528:28;9521:35;;;;9698:33;9707:2;9712:10;9707:15;9724:1;9727:3;9698:8;:33::i;:::-;9753:20;;;:38;;;;;;;;;-1:-1:-1;7642:2553:126;;-1:-1:-1;;;7642:2553:126;;9910:18;;;;;9906:289;;10080:2;10075:7;;7321:5715;;9906:289;10134:10;10129:15;;2053:3;10166:10;;9906:289;7321:5715;;;10324:10;:18;;10338:4;10324:18;10320:2716;;10478:15;;;1824:1;10478:15;;:34;;-1:-1:-1;10497:15:126;;;1859:1;10497:15;10478:34;:57;;;-1:-1:-1;10516:19:126;;;1936:1;10516:19;10478:57;10474:1593;;;10564:2;10559:7;;10320:2716;;10474:1593;10690:23;;;;;10686:1381;;10737:10;10750:27;10758:2;10763:10;10758:15;10775:1;10750:7;:27::i;:::-;10853:17;;;;10737:40;;-1:-1:-1;11096:1:126;11088:10;;11190:1;11186:17;11265:13;;;11262:32;;;11287:5;11281:11;;11262:32;11573:14;;;11379:1;11569:22;;;11565:32;;;;11462:26;11486:1;11371:10;;;11466:18;;;11462:26;11561:43;11367:20;;11669:12;11797:17;;;:23;11865:1;11842:20;;;:24;11375:2;-1:-1:-1;11375:2:126;7321:5715;;10320:2716;12269:10;:18;;12283:4;12269:18;12265:771;;12379:2;:7;;12385:1;12379:7;12375:647;;12472:14;;;;;:40;;-1:-1:-1;12490:22:126;;;1978:1;12490:22;12472:40;:62;;;-1:-1:-1;12516:18:126;;;1897:1;12516:18;12472:62;12468:404;;;12567:1;12562:6;;12375:647;;12468:404;12613:15;;;1824:1;12613:15;;:34;;-1:-1:-1;12632:15:126;;;1859:1;12632:15;12613:34;:61;;;-1:-1:-1;12651:23:126;;;2021:1;12651:23;12613:61;:84;;;-1:-1:-1;12678:19:126;;;1936:1;12678:19;12613:84;12609:263;;;12730:1;12725:6;;7321:5715;;12375:647;12923:10;12918:15;;2087:4;12955:11;;12375:647;13111:15;;;;;:23;;;;:18;;;;:23;;;;13148:15;;:23;;;:18;;;;:23;-1:-1:-1;13237:12:126;;;;13226:23;;;:8;;;:23;13293:1;13278:16;13263:31;;;;;13316:13;:11;:13::i;16084:2480::-;16178:12;16264:18;;:::i;:::-;-1:-1:-1;16332:4:126;16364:10;16472:13;;;16481:4;16472:13;16468:1705;;-1:-1:-1;16511:8:126;;;;16468:1705;;;16630:5;:13;;16639:4;16630:13;16626:1547;;16663:14;;;:8;;;:14;16626:1547;;;16793:5;:13;;16802:4;16793:13;16789:1384;;-1:-1:-1;16832:8:126;;;;16789:1384;;;16951:5;:13;;16960:4;16951:13;16947:1226;;16984:14;;;:8;;;:14;16947:1226;;;17125:5;:13;;17134:4;17125:13;17121:1052;;17252:9;17198:17;17178;;;17198;;;;17178:37;17259:2;17252:9;;;;;17234:8;;;:28;17280:22;:8;;;:22;17121:1052;;;17439:5;:13;;17448:4;17439:13;17435:738;;17506:11;17492;;;17506;;;17492:25;17561:2;17554:9;;;;;17536:8;;;:28;17582:22;:8;;;:22;17435:738;;;17763:5;:13;;17772:4;17763:13;17759:414;;17833:3;17814:23;;17820:3;17814:23;;;;;;;:::i;:::-;;17796:42;;:8;;;:42;17874:23;;;;;;;;;;;;;:::i;:::-;;17856:42;;:8;;;:42;17759:414;;;18067:5;:13;;18076:4;18067:13;18063:110;;18117:3;18111:9;;:3;:9;;;;;;;:::i;:::-;;18100:20;;;;:8;;;:20;18149:9;;;;;;;;;;;:::i;:::-;;18138:20;;:8;;;:20;18063:110;18266:14;;;;18262:85;;18329:3;18300:5;:15;;;18316:9;18300:26;;;;;;;;;:::i;:::-;:32;;;;:26;;;;;;:32;18262:85;18401:12;;;;;18390:23;;;;:8;;;:23;18457:1;18442:16;;;18427:31;;;18534:13;:11;:13::i;:::-;18527:20;16084:2480;-1:-1:-1;;;;;;;16084:2480:126:o;23913:1654::-;24089:14;24106:24;24118:11;24106;:24::i;:::-;24089:41;;24238:1;24231:5;24227:13;24224:33;;;24253:1;24250;24243:12;24224:33;24392:2;24586:15;;;24411:2;24400:14;;24388:10;24384:31;24381:1;24377:39;24542:16;;;24327:20;;24527:10;24516:22;;;24512:27;24502:38;24499:60;25028:5;25025:1;25021:13;25099:1;25084:343;25109:2;25106:1;25103:9;25084:343;;;25232:2;25220:15;;;25169:20;25267:12;;;25281:1;25263:20;25304:42;;;;25372:1;25367:42;;;;25256:153;;25304:42;22391:1;22384:12;;;22424:2;22417:13;;;22469:2;22456:16;;25313:31;;25304:42;;25367;22391:1;22384:12;;;22424:2;22417:13;;;22469:2;22456:16;;25376:31;;25256:153;-1:-1:-1;;25127:1:126;25120:9;25084:343;;;-1:-1:-1;;25526:4:126;25519:18;-1:-1:-1;;;;23913:1654:126:o;20946:586::-;21268:20;;;21292:7;21268:32;21261:3;:40;;;21374:14;;21429:17;;21423:24;;;21415:72;;;;;;;4277:2:285;21415:72:126;;;4259:21:285;4316:2;4296:18;;;4289:30;4355:34;4335:18;;;4328:62;4426:5;4406:18;;;4399:33;4449:19;;21415:72:126;4075:399:285;21415:72:126;21501:14;20946:586;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;467:347:285:-;518:8;528:6;582:3;575:4;567:6;563:17;559:27;549:55;;600:1;597;590:12;549:55;-1:-1:-1;623:20:285;;666:18;655:30;;652:50;;;698:1;695;688:12;652:50;735:4;727:6;723:17;711:29;;787:3;780:4;771:6;763;759:19;755:30;752:39;749:59;;;804:1;801;794:12;749:59;467:347;;;;;:::o;819:785::-;918:6;926;934;942;950;1003:2;991:9;982:7;978:23;974:32;971:52;;;1019:1;1016;1009:12;971:52;1059:9;1046:23;1088:18;1129:2;1121:6;1118:14;1115:34;;;1145:1;1142;1135:12;1115:34;1184:58;1234:7;1225:6;1214:9;1210:22;1184:58;:::i;:::-;1261:8;;-1:-1:-1;1158:84:285;-1:-1:-1;1349:2:285;1334:18;;1321:32;;-1:-1:-1;1365:16:285;;;1362:36;;;1394:1;1391;1384:12;1362:36;;1433:60;1485:7;1474:8;1463:9;1459:24;1433:60;:::i;:::-;819:785;;;;-1:-1:-1;1512:8:285;1594:2;1579:18;1566:32;;819:785;-1:-1:-1;;;;819:785:285:o;1791:184::-;1843:77;1840:1;1833:88;1940:4;1937:1;1930:15;1964:4;1961:1;1954:15;3636:245;3715:6;3723;3776:2;3764:9;3755:7;3751:23;3747:32;3744:52;;;3792:1;3789;3782:12;3744:52;-1:-1:-1;;3815:16:285;;3871:2;3856:18;;;3850:25;3815:16;;3850:25;;-1:-1:-1;3636:245:285
:o;3886:184::-;3938:77;3935:1;3928:88;4035:4;4032:1;4025:15;4059:4;4056:1;4049:15"
var
MIPSDeployedSourceMap
=
"1131:40054:1
35:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1710:45;;1745:10;1710:45;;;;;188:10:299;176:23;;;158:42;;146:2;131:18;1710:45:135;;;;;;;;2448:99;;;412:42:299;2534:6:135;400:55:299;382:74;;370:2;355:18;2448:99:135;211:251:299;26025:6379:135;;;;;;:::i;:::-;;:::i;:::-;;;1755:25:299;;;1743:2;1728:18;26025:6379:135;1609:177:299;26025:6379:135;26128:7;26171:18;;:::i;:::-;26318:4;26311:5;26308:15;26298:134;;26412:1;26409;26402:12;26298:134;26468:4;26462:11;26475:10;26459:27;26449:136;;26565:1;26562;26555:12;26449:136;26634:3;26615:17;26612:26;26602:151;;26733:1;26730;26723:12;26602:151;26798:3;26783:13;26780:22;26770:146;;26896:1;26893;26886:12;26770:146;27176:24;;27521:4;27222:20;27579:2;27280:21;;27176:24;27338:18;27222:20;27280:21;;;27176:24;27153:21;27149:52;;;27338:18;27222:20;;;27280:21;;;27176:24;27149:52;;27222:20;;27280:21;;;27176:24;27149:52;;27338:18;27222:20;27280:21;;;27176:24;27149:52;;27338:18;27222:20;27280:21;;;27176:24;27149:52;;27338:18;27222:20;27280:21;;;27176:24;27149:52;;;27338:18;27222:20;27280:21;;;27176:24;27153:21;27149:52;;;27338:18;27222:20;27280:21;;;27176:24;27149:52;;27338:18;27222:20;27280:21;;;27176:24;27149:52;;27338:18;27222:20;28197:10;27338:18;28187:21;;;27280;;;;28295:1;28280:77;28305:2;28302:1;28299:9;28280:77;;;27176:24;;27153:21;27149:52;27222:20;;28353:1;27280:21;;;;27164:2;27338:18;;;;28323:1;28316:9;28280:77;;;28284:14;;;28435:5;:12;;;28431:71;;;28474:13;:11;:13::i;:::-;28467:20;;;;;28431:71;28516:10;;;:15;;28530:1;28516:15;;;;;28601:8;;;;-1:-1:-1;;28593:20:135;;-1:-1:-1;28593:7:135;:20::i;:::-;28579:34;-1:-1:-1;28643:10:135;28651:2;28643:10;;;;28720:1;28710:11;;;:26;;;28725:6;:11;;28735:1;28725:11;28710:26;28706:310;;;28866:13;28935:1;28913:4;28920:10;28913:17;28912:24;;;;28883:5;:12;;;28898:10;28883:25;28882:54;28866:70;;28961:40;28972:6;:11;;28982:1;28972:11;:20;;28990:2;28972:20;;;28986:1;28972:20;28961:40;;28994:6;28961:10;:40::i;:::-;28954:47;;;;;;;;28706:310;29265:15;;;;29060:9;;;;29197:4;29191:2;29183:10;;;29182:19;;;29265:15;29290:2;29282:10;;;29281:19;29265:36;;;;;;;:::i;:::-;;;;;;-1:-1:-1;29330:5:135;29354:11;;;;;:29;;;29369:6;:14;;29379:4;29369:14;29354:29;29350:832;;;29446:5;:15;;;29462:5;29446:22;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;29509:4:135;29503:2;29495:10;;;29494:19;29350:832;;;29547:4;29538:6;:13;;;29534:648;;;29668:6;:13;;29678:3;29668:13;:30;;;;29685:6;:13;;29695:3;29685:13;29668:30;:47;;;;29702:6;:13;;29712:3;29702:13;29668:47;29664:253;;;29778:4;29785:6;29778:13;29773:18;;29534:648;;29664:253;29877:21;29880:4;29887:6;29880:13;29895:2;29877;:21::i;:::-;29872:26;;29534:648;;;29951:4;29941:6;:14;;;;:32;;;;29959:6;:14;;29969:4;29959:14;29941:32;:50;;;;29977:6;:14;;29987:4;29977:14;29941:50;29937:245;;;30061:5;:15;;;30077:5;30061:22;;;;;;;;;:::i;:::-;;;;;30056:27;;30162:5;30154:13;;29937:245;30211:1;30201:6;:11;;;;:25;;;;;30225:1;30216:6;:10;;;30201:25;30200:42;;;;30231:6;:11;;30241:1;30231:11;30200:42;30196:125;;;30269:37;30282:6;30290:4;30296:5;30303:2;30269:12;:37::i;:::-;30262:44;;;;;;;;;;;30196:125;30354:13;30335:16;30506:4;30496:14;;;;30492:446;;30575:21;30578:4;30585:6;30578:13;30593:2;30575;:21::i;:::-;30569:27;;;;30633:10;30628:15;;30667:16;30628:15;30681:1;30667:7;:16::i;:::-;30661:22;;30715:4;30705:6;:14;;;;:32;;;;;30723:6;:14;;30733:4;30723:14;;30705:32;30701:223;;;30802:4;30790:16;;30904:1;30896:9;;30701:223;30512:426;30492:446;30971:10;30984:26;30992:4;30998:2;31002;31006:3;30984:7;:26::i;:::-;31013:10;30984:39;;;;-1:-1:-1;31109:4:135;31102:11;;;31141;;;:24;;;;;31164:1;31156:4;:9;;;;31141:24;:39;;;;;31176:4;31169;:11;;;31141:39;31137:860;;;31204:4;:9;;31212:1;31204:9;:22;;;;31217:4;:9;;31225:1;31217:9;31204:22;31200:144;;;31288:37;31299:4;:9;;31307:1;31299:9;:21;;31315:5;31299:21;;;31311:1;31299:21;31322:2;31288:10;:37::i;:::-;31281:44;;;;;;;;;;;;;;;31200:144;31366:4;:11;;31374:3;31366:11;31362:121;;31436:28;31445:5;31452:2;31456:7;;;;31436:8;:28::i;31362:121::-;31504:4;:11;;31512:3;31504:11;31500:121;;31574:28;31583:5;31590:2;31594:7;;;;;31574:8;:28::i;31500:121::-;31691:4;:11;;31699:3;31691:11;31687:93;;31733:28;31747:13;31733;:28::i;31687:93::-;31883:4;31875;:12;;;;:27;;;;;31898:4;31891;:11;;;31875:27;31871:112;;;31933:31;31944:4;31950:2;31954;31958:5;31933:10;:31::i;31871:112::-;32057:6;:14;;32067:4;32057:14;:28;;;;-1:-1:-1;32075:10:135;;;;;32057:28;32053:93;;;32130:1;32105:5;:15;;;32121:5;32105:22;;;;;;;;;:::i;:::-;:26;;;;:22;;;;;;:26;32053:93;32192:9;:26;;32205:13;32192:26;32188:92;;32238:27;32247:9;32258:1;32261:3;32238:8;:27::i;:::-;32361:26;32370:5;32377:3;32382:4;32361:8;:26::i;:::-;32354:33;;;;;;;;;;;;;26025:6379;;;;;;;;:::o;3087:2334::-;3634:4;3628:11;;3550:4;3353:31;3342:43;;3413:13;3353:31;3752:2;3452:13;;3342:43;3359:24;3353:31;3452:13;;;3342:43;;;;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3413:13;4180:11;3359:24;3353:31;3452:13;;;3342:43;3413:13;4275:11;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3128:12;;4415:13;;3628:11;;3452:13;;;;4180:11;3128:12;4495:84;4520:2;4517:1;4514:9;4495:84;;;3369:13;3359:24;;3353:31;3342:43;;3373:2;3413:13;;;;4575:1;3452:13;;;;4538:1;4531:9;4495:84;;;4499:14;4642:1;4638:2;4631:13;4737:5;4733:2;4729:14;4722:5;4717:27;4811:1;4797:15;;4832:6;4856:1;4851:273;;;;5191:1;5181:11;;4825:369;;4851:273;4883:8;4941:22;;;;5020:1;5015:22;;;;5107:1;5097:11;;4876:234;;4941:22;4960:1;4950:11;;4941:22;;5015;5034:1;5024:11;;4876:234;;4825:369;-1:-1:-1;;;5317:14:135;;;5300:32;;5360:19;5356:30;5392:3;5388:16;;;;5353:52;;3087:2334;-1:-1:-1;3087:2334:135:o;21746:1831::-;21819:11;21930:14;21947:24;21959:11;21947;:24::i;:::-;21930:41;;22079:1;22072:5;22068:13;22065:33;;;22094:1;22091;22084:12;22065:33;22227:2;22215:15;;;22168:20;22657:5;22654:1;22650:13;22692:4;22728:1;22713:343;22738:2;22735:1;22732:9;22713:343;;;22861:2;22849:15;;;22798:20;22896:12;;;22910:1;22892:20;22933:42;;;;23001:1;22996:42;;;;22885:153;;22933:42;22391:1;22384:12;;;22424:2;22417:13;;;22469:2;22456:16;;22942:31;;22933:42;;22996;22391:1;22384:12;;;22424:2;22417:13;;;22469:2;22456:16;;23005:31;;22885:153;-1:-1:-1;;22756:1:135;22749:9;22713:343;;;22717:14;23166:4;23160:11;23145:26;;23252:7;23246:4;23243:17;23233:124;;23294:10;23291:1;23284:21;23336:2;23333:1;23326:13;23233:124;-1:-1:-1;;23484:2:135;23473:14;;;;23461:10;23457:31;23454:1;23450:39;23518:16;;;;23536:10;23514:33;;21746:1831;-1:-1:-1;;;21746:1831:135:o;18856:823::-;18925:12;19012:18;;:::i;:::-;19080:4;19071:13;;19132:5;:8;;;19143:1;19132:12;19116:28;;:5;:12;;;:28;;;19112:95;;19164:28;;;;;2182:2:299;19164:28:135;;;2164:21:299;2221:2;2201:18;;;2194:30;2260:20;2240:18;;;2233:48;2298:18;;19164:28:135;;;;;;;;19112:95;19296:8;;;;;19329:12;;;;;19318:23;;;;;;;19355:20;;;;;19296:8;19487:13;;;19483:90;;19548:6;19557:1;19548:10;19520:5;:15;;;19536:8;19520:25;;;;;;;;;:::i;:::-;:38;;;;:25;;;;;;:38;19483:90;19649:13;:11;:13::i;2645:339::-;2706:11;2770:18;;;;2779:8;;;;2770:18;;;;;;2769:25;;;;;2786:1;2833:2;:9;;;2827:16;;;;;2826:22;;2825:32;;;;;;;2887:9;;2886:15;2769:25;2944:21;;2964:1;2944:21;;;2955:6;2944:21;2929:11;;;;;:37;;-1:-1:-1;;;2645:339:135;;;;:::o;13732:2026::-;13829:12;13915:18;;:::i;:::-;13983:4;13974:13;;14015:17;14075:5;:8;;;14086:1;14075:12;14059:28;;:5;:12;;;:28;;;14055:97;;14107:30;;;;;2529:2:299;14107:30:135;;;2511:21:299;2568:2;2548:18;;;2541:30;2607:22;2587:18;;;2580:50;2647:18;;14107:30:135;2327:344:299;14055:97:135;14222:7;:12;;14233:1;14222:12;:28;;;;14238:7;:12;;14249:1;14238:12;14222:28;14218:947;;;14270:9;14282:5;:15;;;14298:6;14282:23;;;;;;;;;:::i;:::-;;;;;14270:35;;14346:2;14339:9;;:3;:9;;;:25;;;;;14352:7;:12;;14363:1;14352:12;14339:25;14338:58;;;;14377:2;14370:9;;:3;:9;;;;:25;;;;;14383:7;:12;;14394:1;14383:12;14370:25;14323:73;;14252:159;14218:947;;;14508:7;:12;;14519:1;14508:12;14504:661;;14569:1;14561:3;14555:15;;;;14540:30;;14504:661;;;14673:7;:12;;14684:1;14673:12;14669:496;;14733:1;14726:3;14720:14;;;14705:29;;14669:496;;;14854:7;:12;;14865:1;14854:12;14850:315;;14942:4;14936:2;14927:11;;;14926:20;14912:10;14969:8;;;14965:84;;15029:1;15022:3;15016:14;;;15001:29;;14965:84;15070:3;:8;;15077:1;15070:8;15066:85;;15131:1;15123:3;15117:15;;;;15102:30;;15066:85;14868:297;14850:315;15241:8;;;;;15319:12;;;;15308:23;;;;;15475:178;;;;15566:1;15540:22;15543:5;15551:6;15543:14;15559:2;15540;:22::i;:::-;:27;;;;;;;15526:42;;15535:1;15526:42;15511:57;:12;;;:57;15475:178;;;15622:12;;;;;15637:1;15622:16;15607:31;;;;15475:178;15728:13;:11;:13::i;:::-;15721:20;13732:2026;-1:-1:-1;;;;;;;;13732:2026:135:o;32450:8733::-;32537:10;32599;32607:2;32599:10;;;;32638:11;;;:44;;;32664:1;32654:6;:11;;;;:27;;;;;32678:3;32669:6;:12;;;32654:27;32634:8490;;;32723:4;32716:11;;32847:6;32907:3;32902:25;;;;32982:3;32977:25;;;;33056:3;33051:25;;;;33131:3;33126:25;;;;33205:3;33200:25;;;;33278:3;33273:25;;;;33352:3;33347:25;;;;32840:532;;32902:25;32921:4;32913:12;;32902:25;;32977;32996:4;32988:12;;32977:25;;33051;33070:4;33062:12;;33051:25;;33126;33145:4;33137:12;;33126:25;;33200;33219:4;33211:12;;33200:25;;33273;33292:4;33284:12;;33273:25;;33347;33366:4;33358:12;;32840:532;;33435:4;:12;;33443:4;33435:12;33431:4023;;-1:-1:-1;;;33486:9:135;33478:26;;33499:4;33494:1;33486:9;;;33485:18;33478:26;33471:33;;33431:4023;33572:4;:12;;33580:4;33572:12;33568:3886;;-1:-1:-1;;;33623:9:135;33615:26;;33636:4;33631:1;33623:9;;;33622:18;33615:26;33608:33;;33568:3886;33709:4;:12;;33717:4;33709:12;33705:3749;;33774:4;33769:1;33761:9;;;33760:18;33807:27;33761:9;33810:11;;;;33823:2;:10;;;33807:2;:27::i;:::-;33800:34;;;;;;;33705:3749;33903:4;:12;;33911:4;33903:12;33899:3555;;-1:-1:-1;;;33946:17:135;;;33958:4;33953:9;;33946:17;33939:24;;33899:3555;34032:4;:11;;34040:3;34032:11;34028:3426;;-1:-1:-1;;;34074:17:135;;;34086:4;34081:9;;34074:17;34067:24;;34028:3426;34160:4;:12;;34168:4;34160:12;34156:3298;;34203:21;34212:2;34206:8;;:2;:8;;;;34221:2;34216;:7;34203:2;:21::i;:::-;34196:28;;;;;;34156:3298;34473:4;:12;;34481:4;34473:12;34469:2985;;34516:2;34509:9;;;;;;34469:2985;34587:4;:12;;34595:4;34587:12;34583:2871;;34630:2;34623:9;;;;;;34583:2871;34701:4;:12;;34709:4;34701:12;34697:2757;;34744:2;34737:9;;;;;;34697:2757;34815:4;:12;;34823:4;34815:12;34811:2643;;34858:2;34851:9;;;;;;34811:2643;34932:4;:12;;34940:4;34932:12;34928:2526;;34975:2;34968:9;;;;;;34928:2526;35092:4;:12;;35100:4;35092:12;35088:2366;;35135:2;35128:9;;;;;;35088:2366;35206:4;:12;;35214:4;35206:12;35202:2252;;35249:2;35242:9;;;;;;35202:2252;35320:4;:12;;35328:4;35320:12;35316:2138;;35363:2;35356:9;;;;;;35316:2138;35434:4;:12;;35442:4;35434:12;35430:2024;;35477:2;35470:9;;;;;;35430:2024;35548:4;:12;;35556:4;35548:12;35544:1910;;35591:2;35584:9;;;;;;35544:1910;35662:4;:12;;35670:4;35662:12;35658:1796;;35705:2;35698:9;;;;;;35658:1796;35777:4;:12;;35785:4;35777:12;35773:1681;;35820:2;35813:9;;;;;;35773:1681;35890:4;:12;;35898:4;35890:12;35886:1568;;35933:2;35926:9;;;;;;35886:1568;36004:4;:12;;36012:4;36004:12;36000:1454;;36047:2;36040:9;;;;;;36000:1454;36196:4;:12;;36204:4;36196:12;36192:1262;;-1:-1:-1;;;36240:7:135;;;36232:16;;36192:1262;36317:4;:12;;36325:4;36317:12;36313:1141;;-1:-1:-1;;;36361:7:135;;;36353:16;;36313:1141;36437:4;:12;;36445:4;36437:12;36433:1021;;-1:-1:-1;;;36481:7:135;;;36473:16;;36433:1021;36558:4;:12;;36566:4;36558:12;36554:900;;-1:-1:-1;;;36602:7:135;;;36594:16;;36554:900;36678:4;:12;;36686:4;36678:12;36674:780;;-1:-1:-1;;;36722:7:135;;;36714:16;;36674:780;36797:4;:12;;36805:4;36797:12;36793:661;;-1:-1:-1;;;36841:7:135;;;36833:16;;36793:661;36917:4;:12;;36925:4;36917:12;36913:541;;-1:-1:-1;;;36961:7:135;;;36953:16;;36913:541;37037:4;:12;;37045:4;37037:12;37033:421;;-1:-1:-1;;;37082:7:135;;;37080:10;37073:17;;37033:421;37159:4;:12;;37167:4;37159:12;37155:299;;37220:2;37202:21;;37208:2;37202:21;;;:29;;37230:1;37202:29;;;37226:1;37202:29;37195:36;;;;;;;;37155:299;37301:4;:12;;37309:4;37301:12;37297:157;;37349:2;37344:7;;:2;:7;;;:15;;37358:1;37344:15;;37297:157;37406:29;;;;;2878:2:299;37406:29:135;;;2860:21:299;2917:2;2897:18;;;2890:30;2956:21;2936:18;;;2929:49;2995:18;;37406:29:135;2676:343:299;37297:157:135;32684:4784;32634:8490;;;37524:6;:14;;37534:4;37524:14;37520:3590;;37583:4;37576:11;;37658:3;37650:11;;;37646:549;;-1:-1:-1;;;37703:21:135;;;37689:36;;37646:549;37810:4;:12;;37818:4;37810:12;:28;;;;37826:4;:12;;37834:4;37826:12;37810:28;37806:389;;;37870:4;:12;;37878:4;37870:12;37866:83;;37919:3;;;37866:83;37974:8;38012:127;38024:10;38019:15;;:20;38012:127;;38104:8;38071:3;38104:8;;;;;38071:3;38012:127;;;38171:1;-1:-1:-1;38164:8:135;;-1:-1:-1;;38164:8:135;37520:3590;38262:6;:14;;38272:4;38262:14;38258:2852;;-1:-1:-1;;38307:8:135;38313:2;38307:8;;;;38300:15;;38258:2852;38382:6;:14;;38392:4;38382:14;38378:2732;;38427:42;38445:2;38450:1;38445:6;38455:1;38444:12;38439:2;:17;38431:26;;:3;:26;;;;38461:4;38430:35;38467:1;38427:2;:42::i;:::-;38420:49;;;;;38378:2732;38536:6;:14;;38546:4;38536:14;38532:2578;;38581:45;38599:2;38604:1;38599:6;38609:1;38598:12;38593:2;:17;38585:26;;:3;:26;;;;38615:6;38584:37;38623:2;38581;:45::i;38532:2578::-;38694:6;:14;;38704:4;38694:14;38690:2420;;-1:-1:-1;;38745:21:135;38764:1;38759;38754:6;;38753:12;38745:21;;38802:36;;;38873:5;38868:10;;38745:21;;;;;38867:18;38860:25;;38690:2420;38952:6;:14;;38962:4;38952:14;38948:2162;;38997:3;38990:10;;;;;38948:2162;39068:6;:14;;39078:4;39068:14;39064:2046;;39128:2;39133:1;39128:6;39138:1;39127:12;39122:2;:17;39114:26;;:3;:26;;;;39144:4;39113:35;39106:42;;;;;39064:2046;39217:6;:14;;39227:4;39217:14;39213:1897;;39277:2;39282:1;39277:6;39287:1;39276:12;39271:2;:17;39263:26;;:3;:26;;;;39293:6;39262:37;39255:44;;;;;39213:1897;39368:6;:14;;39378:4;39368:14;39364:1746;;-1:-1:-1;;39419:26:135;39443:1;39438;39433:6;;39432:12;39427:2;:17;39419:26;;39481:41;;;39557:5;39552:10;;39419:26;;;;;39551:18;39544:25;;39364:1746;39637:6;:14;;39647:4;39637:14;39633:1477;;-1:-1:-1;;39694:4:135;39688:34;39720:1;39715;39710:6;;39709:12;39704:2;:17;39688:34;;39778:27;;;39758:48;;;39836:10;;39689:9;;;39688:34;;39835:18;39828:25;;39633:1477;39921:6;:14;;39931:4;39921:14;39917:1193;;-1:-1:-1;;39978:6:135;39972:36;40006:1;40001;39996:6;;39995:12;39990:2;:17;39972:36;;40064:29;;;40044:50;;;40124:10;;39973:11;;;39972:36;;40123:18;40116:25;;39917:1193;40210:6;:14;;40220:4;40210:14;40206:904;;-1:-1:-1;;40261:20:135;40279:1;40274;40269:6;;40268:12;40261:20;;40317:36;;;40389:5;40383:11;;40261:20;;;;;40382:19;40375:26;;40206:904;40469:6;:14;;40479:4;40469:14;40465:645;;40514:2;40507:9;;;;;40465:645;40585:6;:14;;40595:4;40585:14;40581:529;;-1:-1:-1;;40636:25:135;40659:1;40654;40649:6;;40648:12;40643:2;:17;40636:25;;40697:41;;;40774:5;40768:11;;40636:25;;;;;40767:19;40760:26;;40581:529;40853:6;:14;;40863:4;40853:14;40849:261;;40898:3;40891:10;;;;;40849:261;40968:6;:14;;40978:4;40968:14;40964:146;;41013:2;41006:9;;;32450:8733;;;;;;;:::o;19960:782::-;20046:12;20133:18;;:::i;:::-;-1:-1:-1;20201:4:135;20308:2;20296:14;;;;20288:41;;;;;;;3226:2:299;20288:41:135;;;3208:21:299;3265:2;3245:18;;;3238:30;3304:16;3284:18;;;3277:44;3338:18;;20288:41:135;3024:338:299;20288:41:135;20425:14;;;;;;;:30;;;20443:12;20425:30;20421:102;;;20504:4;20475:5;:15;;;20491:9;20475:26;;;;;;;;;:::i;:::-;:33;;;;:26;;;;;;:33;20421:102;20578:12;;;;;20567:23;;;;:8;;;:23;20634:1;20619:16;;;20604:31;;;20712:13;:11;:13::i;5582:7764::-;5646:12;5732:18;;:::i;:::-;-1:-1:-1;5910:15:135;;:18;;;;5800:4;6070:18;;;;6114;;;;6158;;;;;5800:4;;5890:17;;;;6070:18;6114;6248;;;6262:4;6248:18;6244:6792;;6298:2;6327:4;6322:9;;:14;6318:144;;6438:4;6433:9;;6425:4;:18;6419:24;6318:144;6483:2;:7;;6489:1;6483:7;6479:161;;6519:10;;;;;6551:16;;;;;;;;6519:10;-1:-1:-1;6479:161:135;;;6619:2;6614:7;;6479:161;6268:386;6244:6792;;;6756:10;:18;;6770:4;6756:18;6752:6284;;1745:10;6794:14;;6752:6284;;;6892:10;:18;;6906:4;6892:18;6888:6148;;6935:1;6930:6;;6888:6148;;;7060:10;:18;;7074:4;7060:18;7056:5980;;7113:4;7098:12;;;:19;7135:26;;;:14;;;:26;7186:13;:11;:13::i;:::-;7179:20;5582:7764;-1:-1:-1;;;;;;;;;5582:7764:135:o;7056:5980::-;7325:10;:18;;7339:4;7325:18;7321:5715;;7476:14;;;7472:2723;7321:5715;7472:2723;7646:22;;;;;7642:2553;;7771:10;7784:27;7792:2;7797:10;7792:15;7809:1;7784:7;:27::i;:::-;7895:17;;;;7771:40;;-1:-1:-1;7895:17:135;7873:19;8045:14;8064:1;8039:26;8035:146;;1676:4:136;1670:11;;1533:21;1787:15;;;1828:8;1822:4;1815:22;1850:27;;;1996:4;1983:18;;2098:17;;2003:19;1979:44;2025:11;1976:61;8093:65:135;;8035:146;8267:20;;;;;8234:54;;;;;;;;3540:25:299;;;8234:54:135;3601:23:299;;;3581:18;;;3574:51;8203:11:135;;;;8234:19;:6;:19;;;;3513:18:299;;8234:54:135;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8202:86;;;;8515:1;8511:2;8507:10;8612:9;8609:1;8605:17;8694:6;8687:5;8684:17;8681:40;;;8714:5;8704:15;;8681:40;;8797:6;8793:2;8790:14;8787:34;;;8817:2;8807:12;;8787:34;8923:3;8918:1;8910:6;8906:14;8901:3;8897:24;8893:34;8886:41;;9023:3;9019:1;9007:9;8998:6;8995:1;8991:14;8987:30;8983:38;8979:48;8972:55;;9178:1;9174;9170;9158:9;9155:1;9151:17;9147:25;9143:33;9139:41;9305:1;9301;9297;9288:6;9276:9;9273:1;9269:17;9265:30;9261:38;9257:46;9253:54;9235:72;;9436:10;9432:15;9426:4;9422:26;9414:34;;9552:3;9544:4;9540:9;9535:3;9531:19;9528:28;9521:35;;;;9698:33;9707:2;9712:10;9707:15;9724:1;9727:3;9698:8;:33::i;:::-;9753:20;;;:38;;;;;;;;;-1:-1:-1;7642:2553:135;;-1:-1:-1;;;7642:2553:135;;9910:18;;;;;9906:289;;10080:2;10075:7;;7321:5715;;9906:289;10134:10;10129:15;;2053:3;10166:10;;9906:289;7321:5715;;;10324:10;:18;;10338:4;10324:18;10320:2716;;10478:15;;;1824:1;10478:15;;:34;;-1:-1:-1;10497:15:135;;;1859:1;10497:15;10478:34;:57;;;-1:-1:-1;10516:19:135;;;1936:1;10516:19;10478:57;10474:1593;;;10564:2;10559:7;;10320:2716;;10474:1593;10690:23;;;;;10686:1381;;10737:10;10750:27;10758:2;10763:10;10758:15;10775:1;10750:7;:27::i;:::-;10853:17;;;;10737:40;;-1:-1:-1;11096:1:135;11088:10;;11190:1;11186:17;11265:13;;;11262:32;;;11287:5;11281:11;;11262:32;11573:14;;;11379:1;11569:22;;;11565:32;;;;11462:26;11486:1;11371:10;;;11466:18;;;11462:26;11561:43;11367:20;;11669:12;11797:17;;;:23;11865:1;11842:20;;;:24;11375:2;-1:-1:-1;11375:2:135;7321:5715;;10320:2716;12269:10;:18;;12283:4;12269:18;12265:771;;12379:2;:7;;12385:1;12379:7;12375:647;;12472:14;;;;;:40;;-1:-1:-1;12490:22:135;;;1978:1;12490:22;12472:40;:62;;;-1:-1:-1;12516:18:135;;;1897:1;12516:18;12472:62;12468:404;;;12567:1;12562:6;;12375:647;;12468:404;12613:15;;;1824:1;12613:15;;:34;;-1:-1:-1;12632:15:135;;;1859:1;12632:15;12613:34;:61;;;-1:-1:-1;12651:23:135;;;2021:1;12651:23;12613:61;:84;;;-1:-1:-1;12678:19:135;;;1936:1;12678:19;12613:84;12609:263;;;12730:1;12725:6;;7321:5715;;12375:647;12923:10;12918:15;;2087:4;12955:11;;12375:647;13111:15;;;;;:23;;;;:18;;;;:23;;;;13148:15;;:23;;;:18;;;;:23;-1:-1:-1;13237:12:135;;;;13226:23;;;:8;;;:23;13293:1;13278:16;13263:31;;;;;13316:13;:11;:13::i;16084:2480::-;16178:12;16264:18;;:::i;:::-;-1:-1:-1;16332:4:135;16364:10;16472:13;;;16481:4;16472:13;16468:1705;;-1:-1:-1;16511:8:135;;;;16468:1705;;;16630:5;:13;;16639:4;16630:13;16626:1547;;16663:14;;;:8;;;:14;16626:1547;;;16793:5;:13;;16802:4;16793:13;16789:1384;;-1:-1:-1;16832:8:135;;;;16789:1384;;;16951:5;:13;;16960:4;16951:13;16947:1226;;16984:14;;;:8;;;:14;16947:1226;;;17125:5;:13;;17134:4;17125:13;17121:1052;;17252:9;17198:17;17178;;;17198;;;;17178:37;17259:2;17252:9;;;;;17234:8;;;:28;17280:22;:8;;;:22;17121:1052;;;17439:5;:13;;17448:4;17439:13;17435:738;;17506:11;17492;;;17506;;;17492:25;17561:2;17554:9;;;;;17536:8;;;:28;17582:22;:8;;;:22;17435:738;;;17763:5;:13;;17772:4;17763:13;17759:414;;17833:3;17814:23;;17820:3;17814:23;;;;;;;:::i;:::-;;17796:42;;:8;;;:42;17874:23;;;;;;;;;;;;;:::i;:::-;;17856:42;;:8;;;:42;17759:414;;;18067:5;:13;;18076:4;18067:13;18063:110;;18117:3;18111:9;;:3;:9;;;;;;;:::i;:::-;;18100:20;;;;:8;;;:20;18149:9;;;;;;;;;;;:::i;:::-;;18138:20;;:8;;;:20;18063:110;18266:14;;;;18262:85;;18329:3;18300:5;:15;;;18316:9;18300:26;;;;;;;;;:::i;:::-;:32;;;;:26;;;;;;:32;18262:85;18401:12;;;;;18390:23;;;;:8;;;:23;18457:1;18442:16;;;18427:31;;;18534:13;:11;:13::i;:::-;18527:20;16084:2480;-1:-1:-1;;;;;;;16084:2480:135:o;23913:1654::-;24089:14;24106:24;24118:11;24106;:24::i;:::-;24089:41;;24238:1;24231:5;24227:13;24224:33;;;24253:1;24250;24243:12;24224:33;24392:2;24586:15;;;24411:2;24400:14;;24388:10;24384:31;24381:1;24377:39;24542:16;;;24327:20;;24527:10;24516:22;;;24512:27;24502:38;24499:60;25028:5;25025:1;25021:13;25099:1;25084:343;25109:2;25106:1;25103:9;25084:343;;;25232:2;25220:15;;;25169:20;25267:12;;;25281:1;25263:20;25304:42;;;;25372:1;25367:42;;;;25256:153;;25304:42;22391:1;22384:12;;;22424:2;22417:13;;;22469:2;22456:16;;25313:31;;25304:42;;25367;22391:1;22384:12;;;22424:2;22417:13;;;22469:2;22456:16;;25376:31;;25256:153;-1:-1:-1;;25127:1:135;25120:9;25084:343;;;-1:-1:-1;;25526:4:135;25519:18;-1:-1:-1;;;;23913:1654:135:o;20946:586::-;21268:20;;;21292:7;21268:32;21261:3;:40;;;21374:14;;21429:17;;21423:24;;;21415:72;;;;;;;4277:2:299;21415:72:135;;;4259:21:299;4316:2;4296:18;;;4289:30;4355:34;4335:18;;;4328:62;4426:5;4406:18;;;4399:33;4449:19;;21415:72:135;4075:399:299;21415:72:135;21501:14;20946:586;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;467:347:299:-;518:8;528:6;582:3;575:4;567:6;563:17;559:27;549:55;;600:1;597;590:12;549:55;-1:-1:-1;623:20:299;;666:18;655:30;;652:50;;;698:1;695;688:12;652:50;735:4;727:6;723:17;711:29;;787:3;780:4;771:6;763;759:19;755:30;752:39;749:59;;;804:1;801;794:12;749:59;467:347;;;;;:::o;819:785::-;918:6;926;934;942;950;1003:2;991:9;982:7;978:23;974:32;971:52;;;1019:1;1016;1009:12;971:52;1059:9;1046:23;1088:18;1129:2;1121:6;1118:14;1115:34;;;1145:1;1142;1135:12;1115:34;1184:58;1234:7;1225:6;1214:9;1210:22;1184:58;:::i;:::-;1261:8;;-1:-1:-1;1158:84:299;-1:-1:-1;1349:2:299;1334:18;;1321:32;;-1:-1:-1;1365:16:299;;;1362:36;;;1394:1;1391;1384:12;1362:36;;1433:60;1485:7;1474:8;1463:9;1459:24;1433:60;:::i;:::-;819:785;;;;-1:-1:-1;1512:8:299;1594:2;1579:18;1566:32;;819:785;-1:-1:-1;;;;819:785:299:o;1791:184::-;1843:77;1840:1;1833:88;1940:4;1937:1;1930:15;1964:4;1961:1;1954:15;3636:245;3715:6;3723;3776:2;3764:9;3755:7;3751:23;3747:32;3744:52;;;3792:1;3789;3782:12;3744:52;-1:-1:-1;;3815:16:299;;3871:2;3856:18;;;3850:25;3815:16;;3850:25;;-1:-1:-1;3636:245:299
:o;3886:184::-;3938:77;3935:1;3928:88;4035:4;4032:1;4025:15;4059:4;4056:1;4049:15"
func
init
()
{
func
init
()
{
if
err
:=
json
.
Unmarshal
([]
byte
(
MIPSStorageLayoutJSON
),
MIPSStorageLayout
);
err
!=
nil
{
if
err
:=
json
.
Unmarshal
([]
byte
(
MIPSStorageLayoutJSON
),
MIPSStorageLayout
);
err
!=
nil
{
...
...
op-bindings/bindings/preimageoracle_more.go
View file @
96a7781a
...
@@ -15,7 +15,7 @@ var PreimageOracleStorageLayout = new(solc.StorageLayout)
...
@@ -15,7 +15,7 @@ var PreimageOracleStorageLayout = new(solc.StorageLayout)
var
PreimageOracleDeployedBin
=
"0x608060405234801561001057600080fd5b50600436106100725760003560e01c8063e03110e111610050578063e03110e114610106578063e15926111461012e578063fef2b4ed1461014357600080fd5b806361238bde146100775780638542cf50146100b5578063c0c220c9146100f3575b600080fd5b6100a26100853660046104df565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6100e36100c33660046104df565b600260209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016100ac565b6100a2610101366004610501565b610163565b6101196101143660046104df565b610238565b604080519283526020830191909152016100ac565b61014161013c36600461053c565b610329565b005b6100a26101513660046105b8565b60006020819052908152604090205481565b600061016f8686610432565b905061017c836008610600565b8211806101895750602083115b156101c0576040517ffe25498700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000602081815260c085901b82526008959095528251828252600286526040808320858452875280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558484528752808320948352938652838220558181529384905292205592915050565b6000828152600260209081526040808320848452909152812054819060ff166102c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f7072652d696d616765206d757374206578697374000000000000000000000000604482015260640160405180910390fd5b50600083815260208181526040909120546102dd816008610600565b6102e8856020610600565b1061030657836102f9826008610600565b6103039190610618565b91505b506000938452600160209081526040808620948652939052919092205492909150565b604435600080600883018611156103485763fe2549876000526004601cfd5b60c083901b6080526088838682378087017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80151908490207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f02000000000000000000000000000000000000000000000000000000000000001760008181526002602090815260408083208b8452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915584845282528083209a83529981528982209390935590815290819052959095209190915550505050565b7f01000000000000000000000000000000000000000000000000000000000000007effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316176104d8818360408051600093845233602052918152606090922091527effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b9392505050565b600080604083850312156104f257600080fd5b50508035926020909101359150565b600080600080600060a0868803121561051957600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b60008060006040848603121561055157600080fd5b83359250602084013567ffffffffffffffff8082111561057057600080fd5b818601915086601f83011261058457600080fd5b81358181111561059357600080fd5b8760208285010111156105a557600080fd5b6020830194508093505050509250925092565b6000602082840312156105ca57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115610613576106136105d1565b500190565b60008282101561062a5761062a6105d1565b50039056fea164736f6c634300080f000a"
var
PreimageOracleDeployedBin
=
"0x608060405234801561001057600080fd5b50600436106100725760003560e01c8063e03110e111610050578063e03110e114610106578063e15926111461012e578063fef2b4ed1461014357600080fd5b806361238bde146100775780638542cf50146100b5578063c0c220c9146100f3575b600080fd5b6100a26100853660046104df565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6100e36100c33660046104df565b600260209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016100ac565b6100a2610101366004610501565b610163565b6101196101143660046104df565b610238565b604080519283526020830191909152016100ac565b61014161013c36600461053c565b610329565b005b6100a26101513660046105b8565b60006020819052908152604090205481565b600061016f8686610432565b905061017c836008610600565b8211806101895750602083115b156101c0576040517ffe25498700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000602081815260c085901b82526008959095528251828252600286526040808320858452875280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558484528752808320948352938652838220558181529384905292205592915050565b6000828152600260209081526040808320848452909152812054819060ff166102c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f7072652d696d616765206d757374206578697374000000000000000000000000604482015260640160405180910390fd5b50600083815260208181526040909120546102dd816008610600565b6102e8856020610600565b1061030657836102f9826008610600565b6103039190610618565b91505b506000938452600160209081526040808620948652939052919092205492909150565b604435600080600883018611156103485763fe2549876000526004601cfd5b60c083901b6080526088838682378087017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80151908490207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f02000000000000000000000000000000000000000000000000000000000000001760008181526002602090815260408083208b8452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915584845282528083209a83529981528982209390935590815290819052959095209190915550505050565b7f01000000000000000000000000000000000000000000000000000000000000007effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316176104d8818360408051600093845233602052918152606090922091527effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b9392505050565b600080604083850312156104f257600080fd5b50508035926020909101359150565b600080600080600060a0868803121561051957600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b60008060006040848603121561055157600080fd5b83359250602084013567ffffffffffffffff8082111561057057600080fd5b818601915086601f83011261058457600080fd5b81358181111561059357600080fd5b8760208285010111156105a557600080fd5b6020830194508093505050509250925092565b6000602082840312156105ca57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115610613576106136105d1565b500190565b60008282101561062a5761062a6105d1565b50039056fea164736f6c634300080f000a"
var
PreimageOracleDeployedSourceMap
=
"306:3911:1
28:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;537:68;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;413:25:285;;;401:2;386:18;537:68:128;;;;;;;;680:66;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;614:14:285;;607:22;589:41;;577:2;562:18;680:66:128;449:187:285;1367:1211:128;;;;;;:::i;:::-;;:::i;789:536::-;;;;;;:::i;:::-;;:::i;:::-;;;;1274:25:285;;;1330:2;1315:18;;1308:34;;;;1247:18;789:536:128;1100:248:285;2620:1595:128;;;;;;:::i;:::-;;:::i;:::-;;419:50;;;;;;:::i;:::-;;;;;;;;;;;;;;;1367:1211;1560:12;1665:51;1694:6;1702:13;1665:28;:51::i;:::-;1658:58;-1:-1:-1;1810:9:128;:5;1818:1;1810:9;:::i;:::-;1796:11;:23;:37;;;;1831:2;1823:5;:10;1796:37;1792:90;;;1856:15;;;;;;;;;;;;;;1792:90;1951:12;2051:4;2044:18;;;2152:3;2148:15;;;2135:29;;2184:4;2177:19;;;;2286:18;;2376:20;;;:14;:20;;;;;;:33;;;;;;;;:40;;;;2412:4;2376:40;;;;;;2426:19;;;;;;;;:32;;;;;;;;;:39;2542:21;;;;;;;;;:29;2391:4;1367:1211;-1:-1:-1;;1367:1211:128:o;789:536::-;865:12;914:20;;;:14;:20;;;;;;;;:29;;;;;;;;;865:12;;914:29;;906:62;;;;;;;2908:2:285;906:62:128;;;2890:21:285;2947:2;2927:18;;;2920:30;2986:22;2966:18;;;2959:50;3026:18;;906:62:128;;;;;;;;-1:-1:-1;1099:14:128;1116:21;;;1087:2;1116:21;;;;;;;;1167:10;1116:21;1176:1;1167:10;:::i;:::-;1151:12;:7;1161:2;1151:12;:::i;:::-;:26;1147:87;;1216:7;1203:10;:6;1212:1;1203:10;:::i;:::-;:20;;;;:::i;:::-;1193:30;;1147:87;-1:-1:-1;1290:19:128;;;;:13;:19;;;;;;;;:28;;;;;;;;;;;;789:536;;-1:-1:-1;789:536:128:o;2620:1595::-;2916:4;2903:18;2721:12;;3045:1;3035:12;;3019:29;;3016:210;;;3120:10;3117:1;3110:21;3210:1;3204:4;3197:15;3016:210;3469:3;3465:14;;;3369:4;3453:27;3500:11;3474:4;3619:16;3500:11;3601:41;3832:29;;;3836:11;3832:29;3826:36;3884:20;;;;4031:19;4024:27;4053:11;4021:44;4084:19;;;;4062:1;4084:19;;;;;;;;:32;;;;;;;;:39;;;;4119:4;4084:39;;;;;;4133:18;;;;;;;;:31;;;;;;;;;:38;;;;4181:20;;;;;;;;;;;:27;;;;-1:-1:-1;;;;2620:1595:128:o;552:449:127:-;835:11;860:19;848:32;;832:49;965:29;832:49;980:13;1676:4;1670:11;;1533:21;1787:15;;;1828:8;1822:4;1815:22;1850:27;;;1996:4;1983:18;;;2098:17;;2003:19;1979:44;2025:11;1976:61;;1455:676;965:29;958:36;552:449;-1:-1:-1;;;552:449:127:o;14:248:285:-;82:6;90;143:2;131:9;122:7;118:23;114:32;111:52;;;159:1;156;149:12;111:52;-1:-1:-1;;182:23:285;;;252:2;237:18;;;224:32;;-1:-1:-1;14:248:285:o;641:454::-;736:6;744;752;760;768;821:3;809:9;800:7;796:23;792:33;789:53;;;838:1;835;828:12;789:53;-1:-1:-1;;861:23:285;;;931:2;916:18;;903:32;;-1:-1:-1;982:2:285;967:18;;954:32;;1033:2;1018:18;;1005:32;;-1:-1:-1;1084:3:285;1069:19;1056:33;;-1:-1:-1;641:454:285;-1:-1:-1;641:454:285:o;1353:659::-;1432:6;1440;1448;1501:2;1489:9;1480:7;1476:23;1472:32;1469:52;;;1517:1;1514;1507:12;1469:52;1553:9;1540:23;1530:33;;1614:2;1603:9;1599:18;1586:32;1637:18;1678:2;1670:6;1667:14;1664:34;;;1694:1;1691;1684:12;1664:34;1732:6;1721:9;1717:22;1707:32;;1777:7;1770:4;1766:2;1762:13;1758:27;1748:55;;1799:1;1796;1789:12;1748:55;1839:2;1826:16;1865:2;1857:6;1854:14;1851:34;;;1881:1;1878;1871:12;1851:34;1926:7;1921:2;1912:6;1908:2;1904:15;1900:24;1897:37;1894:57;;;1947:1;1944;1937:12;1894:57;1978:2;1974;1970:11;1960:21;;2000:6;1990:16;;;;;1353:659;;;;;:::o;2017:180::-;2076:6;2129:2;2117:9;2108:7;2104:23;2100:32;2097:52;;;2145:1;2142;2135:12;2097:52;-1:-1:-1;2168:23:285;;2017:180;-1:-1:-1;2017:180:285:o;2384:184::-;2436:77;2433:1;2426:88;2533:4;2530:1;2523:15;2557:4;2554:1;2547:15;2573:128;2613:3;2644:1;2640:6;2637:1;2634:13;2631:39;;;2650:18;;:::i;:::-;-1:-1:-1;2686:9:285;;2573:128::o;3055:125::-;3095:4;3123:1;3120;3117:8;3114:34;;;3128:18;;:::i;:::-;-1:-1:-1;3165:9:285
;;3055:125::o"
var
PreimageOracleDeployedSourceMap
=
"306:3911:1
37:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;537:68;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;413:25:299;;;401:2;386:18;537:68:137;;;;;;;;680:66;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;614:14:299;;607:22;589:41;;577:2;562:18;680:66:137;449:187:299;1367:1211:137;;;;;;:::i;:::-;;:::i;789:536::-;;;;;;:::i;:::-;;:::i;:::-;;;;1274:25:299;;;1330:2;1315:18;;1308:34;;;;1247:18;789:536:137;1100:248:299;2620:1595:137;;;;;;:::i;:::-;;:::i;:::-;;419:50;;;;;;:::i;:::-;;;;;;;;;;;;;;;1367:1211;1560:12;1665:51;1694:6;1702:13;1665:28;:51::i;:::-;1658:58;-1:-1:-1;1810:9:137;:5;1818:1;1810:9;:::i;:::-;1796:11;:23;:37;;;;1831:2;1823:5;:10;1796:37;1792:90;;;1856:15;;;;;;;;;;;;;;1792:90;1951:12;2051:4;2044:18;;;2152:3;2148:15;;;2135:29;;2184:4;2177:19;;;;2286:18;;2376:20;;;:14;:20;;;;;;:33;;;;;;;;:40;;;;2412:4;2376:40;;;;;;2426:19;;;;;;;;:32;;;;;;;;;:39;2542:21;;;;;;;;;:29;2391:4;1367:1211;-1:-1:-1;;1367:1211:137:o;789:536::-;865:12;914:20;;;:14;:20;;;;;;;;:29;;;;;;;;;865:12;;914:29;;906:62;;;;;;;2908:2:299;906:62:137;;;2890:21:299;2947:2;2927:18;;;2920:30;2986:22;2966:18;;;2959:50;3026:18;;906:62:137;;;;;;;;-1:-1:-1;1099:14:137;1116:21;;;1087:2;1116:21;;;;;;;;1167:10;1116:21;1176:1;1167:10;:::i;:::-;1151:12;:7;1161:2;1151:12;:::i;:::-;:26;1147:87;;1216:7;1203:10;:6;1212:1;1203:10;:::i;:::-;:20;;;;:::i;:::-;1193:30;;1147:87;-1:-1:-1;1290:19:137;;;;:13;:19;;;;;;;;:28;;;;;;;;;;;;789:536;;-1:-1:-1;789:536:137:o;2620:1595::-;2916:4;2903:18;2721:12;;3045:1;3035:12;;3019:29;;3016:210;;;3120:10;3117:1;3110:21;3210:1;3204:4;3197:15;3016:210;3469:3;3465:14;;;3369:4;3453:27;3500:11;3474:4;3619:16;3500:11;3601:41;3832:29;;;3836:11;3832:29;3826:36;3884:20;;;;4031:19;4024:27;4053:11;4021:44;4084:19;;;;4062:1;4084:19;;;;;;;;:32;;;;;;;;:39;;;;4119:4;4084:39;;;;;;4133:18;;;;;;;;:31;;;;;;;;;:38;;;;4181:20;;;;;;;;;;;:27;;;;-1:-1:-1;;;;2620:1595:137:o;552:449:136:-;835:11;860:19;848:32;;832:49;965:29;832:49;980:13;1676:4;1670:11;;1533:21;1787:15;;;1828:8;1822:4;1815:22;1850:27;;;1996:4;1983:18;;;2098:17;;2003:19;1979:44;2025:11;1976:61;;1455:676;965:29;958:36;552:449;-1:-1:-1;;;552:449:136:o;14:248:299:-;82:6;90;143:2;131:9;122:7;118:23;114:32;111:52;;;159:1;156;149:12;111:52;-1:-1:-1;;182:23:299;;;252:2;237:18;;;224:32;;-1:-1:-1;14:248:299:o;641:454::-;736:6;744;752;760;768;821:3;809:9;800:7;796:23;792:33;789:53;;;838:1;835;828:12;789:53;-1:-1:-1;;861:23:299;;;931:2;916:18;;903:32;;-1:-1:-1;982:2:299;967:18;;954:32;;1033:2;1018:18;;1005:32;;-1:-1:-1;1084:3:299;1069:19;1056:33;;-1:-1:-1;641:454:299;-1:-1:-1;641:454:299:o;1353:659::-;1432:6;1440;1448;1501:2;1489:9;1480:7;1476:23;1472:32;1469:52;;;1517:1;1514;1507:12;1469:52;1553:9;1540:23;1530:33;;1614:2;1603:9;1599:18;1586:32;1637:18;1678:2;1670:6;1667:14;1664:34;;;1694:1;1691;1684:12;1664:34;1732:6;1721:9;1717:22;1707:32;;1777:7;1770:4;1766:2;1762:13;1758:27;1748:55;;1799:1;1796;1789:12;1748:55;1839:2;1826:16;1865:2;1857:6;1854:14;1851:34;;;1881:1;1878;1871:12;1851:34;1926:7;1921:2;1912:6;1908:2;1904:15;1900:24;1897:37;1894:57;;;1947:1;1944;1937:12;1894:57;1978:2;1974;1970:11;1960:21;;2000:6;1990:16;;;;;1353:659;;;;;:::o;2017:180::-;2076:6;2129:2;2117:9;2108:7;2104:23;2100:32;2097:52;;;2145:1;2142;2135:12;2097:52;-1:-1:-1;2168:23:299;;2017:180;-1:-1:-1;2017:180:299:o;2384:184::-;2436:77;2433:1;2426:88;2533:4;2530:1;2523:15;2557:4;2554:1;2547:15;2573:128;2613:3;2644:1;2640:6;2637:1;2634:13;2631:39;;;2650:18;;:::i;:::-;-1:-1:-1;2686:9:299;;2573:128::o;3055:125::-;3095:4;3123:1;3120;3117:8;3114:34;;;3128:18;;:::i;:::-;-1:-1:-1;3165:9:299
;;3055:125::o"
func
init
()
{
func
init
()
{
if
err
:=
json
.
Unmarshal
([]
byte
(
PreimageOracleStorageLayoutJSON
),
PreimageOracleStorageLayout
);
err
!=
nil
{
if
err
:=
json
.
Unmarshal
([]
byte
(
PreimageOracleStorageLayoutJSON
),
PreimageOracleStorageLayout
);
err
!=
nil
{
...
...
packages/contracts-bedrock/.gas-snapshot
View file @
96a7781a
...
@@ -305,6 +305,33 @@ LegacyERC20ETH_Test:test_transferFrom_doesNotExist_reverts() (gas: 12957)
...
@@ -305,6 +305,33 @@ LegacyERC20ETH_Test:test_transferFrom_doesNotExist_reverts() (gas: 12957)
LegacyERC20ETH_Test:test_transfer_doesNotExist_reverts() (gas: 10755)
LegacyERC20ETH_Test:test_transfer_doesNotExist_reverts() (gas: 10755)
LegacyMessagePasser_Test:test_passMessageToL1_succeeds() (gas: 34524)
LegacyMessagePasser_Test:test_passMessageToL1_succeeds() (gas: 34524)
LibPosition_Test:test_pos_correctness_succeeds() (gas: 38689)
LibPosition_Test:test_pos_correctness_succeeds() (gas: 38689)
LivenessGuard_CheckAfterExecution_TestFails:test_checkAfterExecution_callerIsNotSafe_revert() (gas: 8531)
LivenessGuard_CheckTx_Test:test_checkTransaction_succeeds() (gas: 233535)
LivenessGuard_CheckTx_TestFails:test_checkTransaction_callerIsNotSafe_revert() (gas: 10358)
LivenessGuard_Constructor_Test:test_constructor_works() (gas: 1198965)
LivenessGuard_Getters_Test:test_getters_works() (gas: 10662)
LivenessGuard_OwnerManagement_Test:test_addOwner_succeeds() (gas: 274366)
LivenessGuard_OwnerManagement_Test:test_removeOwner_succeeds() (gas: 246263)
LivenessGuard_OwnerManagement_Test:test_swapOwner_succeeds() (gas: 284880)
LivenessGuard_ShowLiveness_Test:test_showLiveness_succeeds() (gas: 28831)
LivenessGuard_ShowLiveness_TestFail:test_showLiveness_callIsNotSafeOwner_reverts() (gas: 18770)
LivenessModule_CanRemove_Test:test_canRemove_works() (gas: 33026)
LivenessModule_CanRemove_TestFail:test_canRemove_notSafeOwner_reverts() (gas: 20489)
LivenessModule_Constructor_TestFail:test_constructor_minOwnersGreaterThanOwners_reverts() (gas: 83623)
LivenessModule_Constructor_TestFail:test_constructor_wrongThreshold_reverts() (gas: 92925)
LivenessModule_Get75PercentThreshold_Test:test_get75PercentThreshold_Works() (gas: 26339)
LivenessModule_Getters_Test:test_getters_works() (gas: 14853)
LivenessModule_RemoveOwners_Test:test_removeOwners_allOwners_succeeds() (gas: 1326177)
LivenessModule_RemoveOwners_Test:test_removeOwners_oneOwner_succeeds() (gas: 133975)
LivenessModule_RemoveOwners_TestFail:test_removeOwners_belowEmptiedButNotShutDown_reverts() (gas: 1278643)
LivenessModule_RemoveOwners_TestFail:test_removeOwners_belowMinButNotEmptied_reverts() (gas: 1281685)
LivenessModule_RemoveOwners_TestFail:test_removeOwners_differentArrayLengths_reverts() (gas: 10502)
LivenessModule_RemoveOwners_TestFail:test_removeOwners_guardChanged_reverts() (gas: 2839358)
LivenessModule_RemoveOwners_TestFail:test_removeOwners_invalidThreshold_reverts() (gas: 69358)
LivenessModule_RemoveOwners_TestFail:test_removeOwners_ownerHasShownLivenessRecently_reverts() (gas: 80971)
LivenessModule_RemoveOwners_TestFail:test_removeOwners_ownerHasSignedRecently_reverts() (gas: 617629)
LivenessModule_RemoveOwners_TestFail:test_removeOwners_swapToFallbackOwner_reverts() (gas: 1288036)
LivenessModule_RemoveOwners_TestFail:test_removeOwners_wrongPreviousOwner_reverts() (gas: 73954)
MIPS_Test:test_add_succeeds() (gas: 122932)
MIPS_Test:test_add_succeeds() (gas: 122932)
MIPS_Test:test_addiSign_succeeds() (gas: 122923)
MIPS_Test:test_addiSign_succeeds() (gas: 122923)
MIPS_Test:test_addi_succeeds() (gas: 123120)
MIPS_Test:test_addi_succeeds() (gas: 123120)
...
...
packages/contracts-bedrock/semver-lock.json
View file @
96a7781a
...
@@ -18,6 +18,8 @@
...
@@ -18,6 +18,8 @@
"src/L2/L2StandardBridge.sol"
:
"0x284ebf5569c75d98f2d1920a276d1116524399355708c4a60ea5892283c56719"
,
"src/L2/L2StandardBridge.sol"
:
"0x284ebf5569c75d98f2d1920a276d1116524399355708c4a60ea5892283c56719"
,
"src/L2/L2ToL1MessagePasser.sol"
:
"0xafc710b4d320ef450586d96a61cbd58cac814cb3b0c4fdc280eace3efdcdf321"
,
"src/L2/L2ToL1MessagePasser.sol"
:
"0xafc710b4d320ef450586d96a61cbd58cac814cb3b0c4fdc280eace3efdcdf321"
,
"src/L2/SequencerFeeVault.sol"
:
"0x883e434a69b4789997a4a9a32060dbbd2e12db6f1970927f1310820336119575"
,
"src/L2/SequencerFeeVault.sol"
:
"0x883e434a69b4789997a4a9a32060dbbd2e12db6f1970927f1310820336119575"
,
"src/Safe/LivenessGuard.sol"
:
"0xa08460138c22a337f8f5d3a17e02beffe8136c4dba58935cc5c9c2d7ffe1222c"
,
"src/Safe/LivenessModule.sol"
:
"0x45621d74ea464c75064f9194261d29d47552cf4a9c4f4b3a733f5df5803fc0dd"
,
"src/dispute/BlockOracle.sol"
:
"0x7e724b1ee0116dfd744f556e6237af449c2f40c6426d6f1462ae2a47589283bb"
,
"src/dispute/BlockOracle.sol"
:
"0x7e724b1ee0116dfd744f556e6237af449c2f40c6426d6f1462ae2a47589283bb"
,
"src/dispute/DisputeGameFactory.sol"
:
"0xfdfa141408d7f8de7e230ff4bef088e30d0e4d569ca743d60d292abdd21ff270"
,
"src/dispute/DisputeGameFactory.sol"
:
"0xfdfa141408d7f8de7e230ff4bef088e30d0e4d569ca743d60d292abdd21ff270"
,
"src/dispute/FaultDisputeGame.sol"
:
"0x0766707ab32338a6586c2340ddfbfd4e9023eeb9dfa3ef87e4b404fb0260479f"
,
"src/dispute/FaultDisputeGame.sol"
:
"0x0766707ab32338a6586c2340ddfbfd4e9023eeb9dfa3ef87e4b404fb0260479f"
,
...
...
packages/contracts-bedrock/src/Safe/LivenessGuard.sol
0 → 100644
View file @
96a7781a
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Safe } from "safe-contracts/Safe.sol";
import { BaseGuard, GuardManager } from "safe-contracts/base/GuardManager.sol";
import { ModuleManager } from "safe-contracts/base/ModuleManager.sol";
import { SafeSigners } from "src/Safe/SafeSigners.sol";
import { Enum } from "safe-contracts/common/Enum.sol";
import { ISemver } from "src/universal/ISemver.sol";
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
/// @title LivenessGuard
/// @notice This Guard contract is used to track the liveness of Safe owners.
/// @dev It keeps track of the last time each owner participated in signing a transaction.
/// If an owner does not participate in a transaction for a certain period of time, they are considered inactive.
/// This Guard is intended to be used in conjunction with the LivenessModule contract, but does
/// not depend on it.
/// Note: Both `checkTransaction` and `checkAfterExecution` are called once each by the Safe contract
/// before and after the execution of a transaction. It is critical that neither function revert,
/// otherwise the Safe contract will be unable to execute a transaction.
contract LivenessGuard is ISemver, BaseGuard {
using EnumerableSet for EnumerableSet.AddressSet;
/// @notice Emitted when an owner is recorded.
/// @param owner The owner's address.
event OwnerRecorded(address owner);
/// @notice Semantic version.
/// @custom:semver 1.0.0
string public constant version = "1.0.0";
/// @notice The safe account for which this contract will be the guard.
Safe internal immutable SAFE;
/// @notice A mapping of the timestamp at which an owner last participated in signing a
/// an executed transaction, or called showLiveness.
mapping(address => uint256) public lastLive;
/// @notice An enumerable set of addresses used to store the list of owners before execution,
/// and then to update the lastLive mapping according to changes in the set observed
/// after execution.
EnumerableSet.AddressSet internal ownersBefore;
/// @notice Constructor.
/// @param _safe The safe account for which this contract will be the guard.
constructor(Safe _safe) {
SAFE = _safe;
address[] memory owners = _safe.getOwners();
for (uint256 i = 0; i < owners.length; i++) {
address owner = owners[i];
lastLive[owner] = block.timestamp;
emit OwnerRecorded(owner);
}
}
/// @notice Getter function for the Safe contract instance
/// @return safe_ The Safe contract instance
function safe() public view returns (Safe safe_) {
safe_ = SAFE;
}
/// @notice Internal function to ensure that only the Safe can call certain functions.
function _requireOnlySafe() internal view {
require(msg.sender == address(SAFE), "LivenessGuard: only Safe can call this function");
}
/// @notice Records the most recent time which any owner has signed a transaction.
/// @dev Called by the Safe contract before execution of a transaction.
function checkTransaction(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver,
bytes memory signatures,
address msgSender
)
external
{
msgSender; // silence unused variable warning
_requireOnlySafe();
// Cache the set of owners prior to execution.
// This will be used in the checkAfterExecution method.
address[] memory owners = SAFE.getOwners();
for (uint256 i = 0; i < owners.length; i++) {
ownersBefore.add(owners[i]);
}
// This call will reenter to the Safe which is calling it. This is OK because it is only reading the
// nonce, and using the getTransactionHash() method.
bytes32 txHash = SAFE.getTransactionHash({
to: to,
value: value,
data: data,
operation: operation,
safeTxGas: safeTxGas,
baseGas: baseGas,
gasPrice: gasPrice,
gasToken: gasToken,
refundReceiver: refundReceiver,
_nonce: SAFE.nonce() - 1
});
uint256 threshold = SAFE.getThreshold();
address[] memory signers =
SafeSigners.getNSigners({ dataHash: txHash, signatures: signatures, requiredSignatures: threshold });
for (uint256 i = 0; i < signers.length; i++) {
lastLive[signers[i]] = block.timestamp;
emit OwnerRecorded(signers[i]);
}
}
/// @notice Update the lastLive mapping according to the set of owners before and after execution.
/// @dev Called by the Safe contract after the execution of a transaction.
/// We use this post execution hook to compare the set of owners before and after.
/// If the set of owners has changed then we:
/// 1. Add new owners to the lastLive mapping
/// 2. Delete removed owners from the lastLive mapping
function checkAfterExecution(bytes32, bool) external {
_requireOnlySafe();
// Get the current set of owners
address[] memory ownersAfter = SAFE.getOwners();
// Iterate over the current owners, and remove one at a time from the ownersBefore set.
for (uint256 i = 0; i < ownersAfter.length; i++) {
// If the value was present, remove() returns true.
address ownerAfter = ownersAfter[i];
if (ownersBefore.remove(ownerAfter) == false) {
// This address was not already an owner, add it to the lastLive mapping
lastLive[ownerAfter] = block.timestamp;
}
}
// Now iterate over the remaining ownersBefore entries. Any remaining addresses are no longer an owner, so we
// delete them from the lastLive mapping.
// We cache the ownersBefore set before iterating over it, because the remove() method mutates the set.
address[] memory ownersBeforeCache = ownersBefore.values();
for (uint256 i = 0; i < ownersBeforeCache.length; i++) {
address ownerBefore = ownersBeforeCache[i];
delete lastLive[ownerBefore];
ownersBefore.remove(ownerBefore);
}
}
/// @notice Enables an owner to demonstrate liveness by calling this method directly.
/// This is useful for owners who have not recently signed a transaction via the Safe.
function showLiveness() external {
require(SAFE.isOwner(msg.sender), "LivenessGuard: only Safe owners may demonstrate liveness");
lastLive[msg.sender] = block.timestamp;
emit OwnerRecorded(msg.sender);
}
}
packages/contracts-bedrock/src/Safe/LivenessModule.sol
0 → 100644
View file @
96a7781a
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Safe, OwnerManager } from "safe-contracts/Safe.sol";
import { Enum } from "safe-contracts/common/Enum.sol";
import { OwnerManager } from "safe-contracts/base/OwnerManager.sol";
import { LivenessGuard } from "src/Safe/LivenessGuard.sol";
import { ISemver } from "src/universal/ISemver.sol";
/// @title LivenessModule
/// @notice This module is intended to be used in conjunction with the LivenessGuard. In the event
/// that an owner of the safe is not recorded by the guard during the liveness interval,
/// the owner will be considered inactive and will be removed from the list of owners.
/// If the number of owners falls below the minimum number of owners, the ownership of the
/// safe will be transferred to the fallback owner.
contract LivenessModule is ISemver {
/// @notice The Safe contract instance
Safe internal immutable SAFE;
/// @notice The LivenessGuard contract instance
/// This can be updated by replacing with a new module and switching out the guard.
LivenessGuard internal immutable LIVENESS_GUARD;
/// @notice The interval, in seconds, during which an owner must have demonstrated liveness
/// This can be updated by replacing with a new module.
uint256 internal immutable LIVENESS_INTERVAL;
/// @notice The minimum number of owners before ownership of the safe is transferred to the fallback owner.
/// This can be updated by replacing with a new module.
uint256 internal immutable MIN_OWNERS;
/// @notice The fallback owner of the Safe
/// This can be updated by replacing with a new module.
address internal immutable FALLBACK_OWNER;
/// @notice The storage slot used in the safe to store the guard address
/// keccak256("guard_manager.guard.address")
uint256 internal constant GUARD_STORAGE_SLOT = 0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8;
/// @notice Semantic version.
/// @custom:semver 1.0.0
string public constant version = "1.0.0";
// Constructor to initialize the Safe and baseModule instances
constructor(
Safe _safe,
LivenessGuard _livenessGuard,
uint256 _livenessInterval,
uint256 _minOwners,
address _fallbackOwner
) {
SAFE = _safe;
LIVENESS_GUARD = _livenessGuard;
LIVENESS_INTERVAL = _livenessInterval;
FALLBACK_OWNER = _fallbackOwner;
MIN_OWNERS = _minOwners;
address[] memory owners = _safe.getOwners();
require(_minOwners <= owners.length, "LivenessModule: minOwners must be less than the number of owners");
require(
_safe.getThreshold() >= get75PercentThreshold(owners.length),
"LivenessModule: Safe must have a threshold of at least 75% of the number of owners"
);
}
/// @notice For a given number of owners, return the lowest threshold which is greater than 75.
/// Note: this function returns 1 for numOwners == 1.
function get75PercentThreshold(uint256 _numOwners) public pure returns (uint256 threshold_) {
threshold_ = (_numOwners * 75 + 99) / 100;
}
/// @notice Getter function for the Safe contract instance
/// @return safe_ The Safe contract instance
function safe() public view returns (Safe safe_) {
safe_ = SAFE;
}
/// @notice Getter function for the LivenessGuard contract instance
/// @return livenessGuard_ The LivenessGuard contract instance
function livenessGuard() public view returns (LivenessGuard livenessGuard_) {
livenessGuard_ = LIVENESS_GUARD;
}
/// @notice Getter function for the liveness interval
/// @return livenessInterval_ The liveness interval, in seconds
function livenessInterval() public view returns (uint256 livenessInterval_) {
livenessInterval_ = LIVENESS_INTERVAL;
}
/// @notice Getter function for the minimum number of owners
/// @return minOwners_ The minimum number of owners
function minOwners() public view returns (uint256 minOwners_) {
minOwners_ = MIN_OWNERS;
}
/// @notice Getter function for the fallback owner
/// @return fallbackOwner_ The fallback owner of the Safe
function fallbackOwner() public view returns (address fallbackOwner_) {
fallbackOwner_ = FALLBACK_OWNER;
}
/// @notice Checks if the owner can be removed
/// @param _owner The owner to be removed
/// @return canRemove_ bool indicating if the owner can be removed
function canRemove(address _owner) public view returns (bool canRemove_) {
require(SAFE.isOwner(_owner), "LivenessModule: the owner to remove must be an owner of the Safe");
canRemove_ = LIVENESS_GUARD.lastLive(_owner) + LIVENESS_INTERVAL < block.timestamp;
}
/// @notice This function can be called by anyone to remove a set of owners that have not signed a transaction
/// during the liveness interval. If the number of owners drops below the minimum, then all owners
/// must be removed.
/// @param _previousOwners The previous owners in the linked list of owners
/// @param _ownersToRemove The owners to remove
function removeOwners(address[] memory _previousOwners, address[] memory _ownersToRemove) external {
require(_previousOwners.length == _ownersToRemove.length, "LivenessModule: arrays must be the same length");
// Initialize the ownersCount count to the current number of owners, so that we can track the number of
// owners in the Safe after each removal. The Safe will revert if an owner cannot be removed, so it is safe
// keep a local count of the number of owners this way.
uint256 ownersCount = SAFE.getOwners().length;
for (uint256 i = 0; i < _previousOwners.length; i++) {
// Validate that the owner can be removed, which means that either:
// 1. the ownersCount is now less than MIN_OWNERS, in which case all owners should be removed regardless
// of liveness,
// 2. the owner has not signed a transaction during the liveness interval.
if (ownersCount >= MIN_OWNERS) {
require(canRemove(_ownersToRemove[i]), "LivenessModule: the owner to remove has signed recently");
}
// Pre-emptively update our local count of the number of owners.
// This is safe because _removeOwner will bubble up any revert from the Safe if the owner cannot be removed.
ownersCount--;
// We now attempt remove the owner from the safe.
_removeOwner({
_prevOwner: _previousOwners[i],
_ownerToRemove: _ownersToRemove[i],
_newOwnersCount: ownersCount
});
// when all owners are removed and the sole owner is the fallback owner, the
// ownersCount variable will be incorrectly set to zero.
// This reflects the fact that all prior owners have been removed. The loop should naturally exit at this
// point, but for safety we detect this condition and force the loop to terminate.
if (ownersCount == 0) {
break;
}
}
_verifyFinalState();
}
/// @notice Removes an owner from the Safe and updates the threshold.
/// @param _prevOwner Owner that pointed to the owner to be removed in the linked list
/// @param _ownerToRemove Owner address to be removed.
/// @param _newOwnersCount New number of owners after removal.
function _removeOwner(address _prevOwner, address _ownerToRemove, uint256 _newOwnersCount) internal {
if (_newOwnersCount > 0) {
uint256 newThreshold = get75PercentThreshold(_newOwnersCount);
// Remove the owner and update the threshold
_removeOwnerSafeCall({ _prevOwner: _prevOwner, _owner: _ownerToRemove, _threshold: newThreshold });
} else {
// There is only one owner left. The Safe will not allow a safe with no owners, so we will
// need to swap owners instead.
_swapToFallbackOwnerSafeCall({ _prevOwner: _prevOwner, _oldOwner: _ownerToRemove });
}
}
/// @notice Sets the fallback owner as the sole owner of the Safe with a threshold of 1
/// @param _prevOwner Owner that pointed to the owner to be replaced in the linked list
/// @param _oldOwner Owner address to be replaced.
function _swapToFallbackOwnerSafeCall(address _prevOwner, address _oldOwner) internal {
require(
SAFE.execTransactionFromModule({
to: address(SAFE),
value: 0,
operation: Enum.Operation.Call,
data: abi.encodeCall(OwnerManager.swapOwner, (_prevOwner, _oldOwner, FALLBACK_OWNER))
}),
"LivenessModule: failed to swap to fallback owner"
);
}
/// @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`.
/// @param _prevOwner Owner that pointed to the owner to be removed in the linked list
/// @param _owner Owner address to be removed.
/// @param _threshold New threshold.
function _removeOwnerSafeCall(address _prevOwner, address _owner, uint256 _threshold) internal {
require(
SAFE.execTransactionFromModule({
to: address(SAFE),
value: 0,
operation: Enum.Operation.Call,
data: abi.encodeCall(OwnerManager.removeOwner, (_prevOwner, _owner, _threshold))
}),
"LivenessModule: failed to remove owner"
);
}
/// @notice A FREI-PI invariant check enforcing requirements on number of owners and threshold.
function _verifyFinalState() internal view {
address[] memory owners = SAFE.getOwners();
uint256 numOwners = owners.length;
// Ensure that the safe is not being left in a safe state such that either:
// 1. there are at least the minimum number of owners, or
// 2. there is a single owner and that owner is the fallback owner.
if (numOwners == 1) {
require(owners[0] == FALLBACK_OWNER, "LivenessModule: must transfer ownership to fallback owner");
} else {
require(
numOwners >= MIN_OWNERS,
"LivenessModule: must remove all owners and transfer to fallback owner if numOwners < minOwners"
);
}
// Check that"LivenessModule: must remove all owners and transfer to fallback owner if numOwners < minOwners"
// the threshold is correct. This check is also correct when there is a single
// owner, because get75PercentThreshold(1) returns 1.
uint256 threshold = SAFE.getThreshold();
require(
threshold == get75PercentThreshold(numOwners),
"LivenessModule: Safe must have a threshold of 75% of the number of owners"
);
// Check that the guard has not been changed
require(
address(LIVENESS_GUARD) == address(uint160(uint256(bytes32(SAFE.getStorageAt(GUARD_STORAGE_SLOT, 1))))),
"LivenessModule: guard has been changed"
);
}
}
packages/contracts-bedrock/src/Safe/SafeSigners.sol
0 → 100644
View file @
96a7781a
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library SafeSigners {
/// @notice Splits signature bytes into `uint8 v, bytes32 r, bytes32 s`.
/// Copied directly from
/// https://github.com/safe-global/safe-contracts/blob/e870f514ad34cd9654c72174d6d4a839e3c6639f/contracts/common/SignatureDecoder.sol
/// @dev Make sure to perform a bounds check for @param pos, to avoid out of bounds access on @param signatures
/// The signature format is a compact form of {bytes32 r}{bytes32 s}{uint8 v}
/// Compact means uint8 is not padded to 32 bytes.
/// @param pos Which signature to read.
/// A prior bounds check of this parameter should be performed, to avoid out of bounds access.
/// @param signatures Concatenated {r, s, v} signatures.
/// @return v Recovery ID or Safe signature type.
/// @return r Output value r of the signature.
/// @return s Output value s of the signature.
function signatureSplit(
bytes memory signatures,
uint256 pos
)
internal
pure
returns (uint8 v, bytes32 r, bytes32 s)
{
// solhint-disable-next-line no-inline-assembly
assembly {
let signaturePos := mul(0x41, pos)
r := mload(add(signatures, add(signaturePos, 0x20)))
s := mload(add(signatures, add(signaturePos, 0x40)))
/**
* Here we are loading the last 32 bytes, including 31 bytes
* of 's'. There is no 'mload8' to do this.
* 'byte' is not working due to the Solidity parser, so lets
* use the second best option, 'and'
*/
v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff)
}
}
/// @notice Extract the signers from a set of signatures.
/// This method is based closely on the code in the Safe.checkNSignatures() method.
/// https://github.com/safe-global/safe-contracts/blob/e870f514ad34cd9654c72174d6d4a839e3c6639f/contracts/Safe.sol#L274
/// It has been modified by removing all signature _validation_ code. We trust the Safe to properly validate
/// the signatures.
/// This method therefore simply extracts the addresses from the signatures.
function getNSigners(
bytes32 dataHash,
bytes memory signatures,
uint256 requiredSignatures
)
internal
pure
returns (address[] memory _owners)
{
_owners = new address[](requiredSignatures);
address currentOwner;
uint8 v;
bytes32 r;
bytes32 s;
uint256 i;
for (i = 0; i < requiredSignatures; i++) {
(v, r, s) = signatureSplit(signatures, i);
if (v == 0) {
// If v is 0 then it is a contract signature
// When handling contract signatures the address of the contract is encoded into r
currentOwner = address(uint160(uint256(r)));
} else if (v == 1) {
// If v is 1 then it is an approved hash
// When handling approved hashes the address of the approver is encoded into r
currentOwner = address(uint160(uint256(r)));
} else if (v > 30) {
// If v > 30 then default va (27,28) has been adjusted for eth_sign flow
// To support eth_sign and similar we adjust v and hash the messageHash with the Ethereum message prefix
// before applying ecrecover
currentOwner =
ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash)), v - 4, r, s);
} else {
// Default is the ecrecover flow with the provided data hash
// Use ecrecover with the messageHash for EOA signatures
currentOwner = ecrecover(dataHash, v, r, s);
}
_owners[i] = currentOwner;
}
}
}
packages/contracts-bedrock/test/LivenessGuard.t.sol
0 → 100644
View file @
96a7781a
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
import { StdUtils } from "forge-std/StdUtils.sol";
import { StdCheats } from "forge-std/StdCheats.sol";
import { Safe, OwnerManager } from "safe-contracts/Safe.sol";
import { SafeProxyFactory } from "safe-contracts/proxies/SafeProxyFactory.sol";
import { ModuleManager } from "safe-contracts/base/ModuleManager.sol";
import { Enum } from "safe-contracts/common/Enum.sol";
import "test/safe-tools/SafeTestTools.sol";
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import { LivenessGuard } from "src/Safe/LivenessGuard.sol";
/// @dev A wrapper contract exposing the length of the ownersBefore set in the LivenessGuard.
contract WrappedGuard is LivenessGuard {
using EnumerableSet for EnumerableSet.AddressSet;
constructor(Safe safe) LivenessGuard(safe) { }
function ownersBeforeLength() public view returns (uint256) {
return ownersBefore.length();
}
}
contract LivenessGuard_TestInit is Test, SafeTestTools {
using SafeTestLib for SafeInstance;
event OwnerRecorded(address owner);
uint256 initTime = 10;
WrappedGuard livenessGuard;
SafeInstance safeInstance;
/// @dev Sets up the test environment
function setUp() public {
vm.warp(initTime);
safeInstance = _setupSafe();
livenessGuard = new WrappedGuard(safeInstance.safe);
safeInstance.setGuard(address(livenessGuard));
}
}
contract LivenessGuard_Constructor_Test is LivenessGuard_TestInit {
/// @dev Tests that the constructor correctly sets the current time as the lastLive time for each owner
function test_constructor_works() external {
address[] memory owners = safeInstance.owners;
livenessGuard = new WrappedGuard(safeInstance.safe);
for (uint256 i = 0; i < owners.length; i++) {
assertEq(livenessGuard.lastLive(owners[i]), initTime);
}
}
}
contract LivenessGuard_Getters_Test is LivenessGuard_TestInit {
/// @dev Tests that the getters return the correct values
function test_getters_works() external {
assertEq(address(livenessGuard.safe()), address(safeInstance.safe));
assertEq(livenessGuard.lastLive(address(0)), 0);
}
}
contract LivenessGuard_CheckTx_TestFails is LivenessGuard_TestInit {
/// @dev Tests that the checkTransaction function reverts if the caller is not the Safe
function test_checkTransaction_callerIsNotSafe_revert() external {
vm.expectRevert("LivenessGuard: only Safe can call this function");
livenessGuard.checkTransaction({
to: address(0),
value: 0,
data: hex"00",
operation: Enum.Operation.Call,
safeTxGas: 0,
baseGas: 0,
gasPrice: 0,
gasToken: address(0),
refundReceiver: payable(address(0)),
signatures: hex"00",
msgSender: address(0)
});
}
}
contract LivenessGuard_CheckTx_Test is LivenessGuard_TestInit {
using SafeTestLib for SafeInstance;
/// @dev Tests that the checkTransaction function succeeds
function test_checkTransaction_succeeds() external {
// Create an array of the addresses who will sign the transaction. SafeTestTools
// will generate these signatures up to the threshold by iterating over the owners array.
address[] memory signers = new address[](safeInstance.threshold);
signers[0] = safeInstance.owners[0];
signers[1] = safeInstance.owners[1];
// Record the timestamps before the transaction
uint256[] memory beforeTimestamps = new uint256[](safeInstance.owners.length);
// Jump ahead
uint256 newTimestamp = block.timestamp + 100;
vm.warp(newTimestamp);
for (uint256 i; i < signers.length; i++) {
vm.expectEmit(address(livenessGuard));
emit OwnerRecorded(signers[i]);
}
vm.expectCall(address(safeInstance.safe), abi.encodeWithSignature("nonce()"));
vm.expectCall(address(safeInstance.safe), abi.encodeCall(OwnerManager.getThreshold, ()));
safeInstance.execTransaction({ to: address(1111), value: 0, data: hex"abba" });
for (uint256 i; i < safeInstance.threshold; i++) {
uint256 lastLive = livenessGuard.lastLive(safeInstance.owners[i]);
assertGe(lastLive, beforeTimestamps[i]);
assertEq(lastLive, newTimestamp);
}
}
}
contract LivenessGuard_CheckAfterExecution_TestFails is LivenessGuard_TestInit {
/// @dev Tests that the checkAfterExecution function reverts if the caller is not the Safe
function test_checkAfterExecution_callerIsNotSafe_revert() external {
vm.expectRevert("LivenessGuard: only Safe can call this function");
livenessGuard.checkAfterExecution(bytes32(0), false);
}
}
contract LivenessGuard_ShowLiveness_TestFail is LivenessGuard_TestInit {
/// @dev Tests that the showLiveness function reverts if the caller is not an owner
function test_showLiveness_callIsNotSafeOwner_reverts() external {
vm.expectRevert("LivenessGuard: only Safe owners may demonstrate liveness");
livenessGuard.showLiveness();
}
}
contract LivenessGuard_ShowLiveness_Test is LivenessGuard_TestInit {
/// @dev Tests that the showLiveness function succeeds
function test_showLiveness_succeeds() external {
// Cache the caller
address caller = safeInstance.owners[0];
vm.expectEmit(address(livenessGuard));
emit OwnerRecorded(caller);
vm.prank(caller);
livenessGuard.showLiveness();
assertEq(livenessGuard.lastLive(caller), block.timestamp);
}
}
contract LivenessGuard_OwnerManagement_Test is LivenessGuard_TestInit {
using SafeTestLib for SafeInstance;
/// @dev Tests that the guard correctly deletes the owner from the lastLive mapping when it is removed
function test_removeOwner_succeeds() external {
address ownerToRemove = safeInstance.owners[0];
assertGe(livenessGuard.lastLive(ownerToRemove), 0);
assertTrue(safeInstance.safe.isOwner(ownerToRemove));
assertEq(livenessGuard.ownersBeforeLength(), 0);
safeInstance.removeOwner({ prevOwner: address(0), owner: ownerToRemove, threshold: 1 });
assertEq(livenessGuard.ownersBeforeLength(), 0);
assertFalse(safeInstance.safe.isOwner(ownerToRemove));
assertEq(livenessGuard.lastLive(ownerToRemove), 0);
}
/// @dev Tests that the guard correctly adds an owner to the lastLive mapping when it is added
function test_addOwner_succeeds() external {
address ownerToAdd = makeAddr("new owner");
assertEq(livenessGuard.lastLive(ownerToAdd), 0);
assertFalse(safeInstance.safe.isOwner(ownerToAdd));
assertEq(livenessGuard.ownersBeforeLength(), 0);
safeInstance.addOwnerWithThreshold({ owner: ownerToAdd, threshold: 1 });
assertEq(livenessGuard.ownersBeforeLength(), 0);
assertTrue(safeInstance.safe.isOwner(ownerToAdd));
assertEq(livenessGuard.lastLive(ownerToAdd), block.timestamp);
}
/// @dev Tests that the guard correctly adds an owner to the lastLive mapping when it is added
function test_swapOwner_succeeds() external {
address ownerToRemove = safeInstance.owners[0];
assertGe(livenessGuard.lastLive(ownerToRemove), 0);
assertTrue(safeInstance.safe.isOwner(ownerToRemove));
address ownerToAdd = makeAddr("new owner");
assertEq(livenessGuard.lastLive(ownerToAdd), 0);
assertFalse(safeInstance.safe.isOwner(ownerToAdd));
assertEq(livenessGuard.ownersBeforeLength(), 0);
safeInstance.swapOwner({ prevOwner: address(0), oldOwner: ownerToRemove, newOwner: ownerToAdd });
assertEq(livenessGuard.ownersBeforeLength(), 0);
assertFalse(safeInstance.safe.isOwner(ownerToRemove));
assertEq(livenessGuard.lastLive(ownerToRemove), 0);
assertTrue(safeInstance.safe.isOwner(ownerToAdd));
assertEq(livenessGuard.lastLive(ownerToAdd), block.timestamp);
}
}
contract LivenessGuard_FuzzOwnerManagement_Test is StdCheats, StdUtils, LivenessGuard_TestInit {
using SafeTestLib for SafeInstance;
/// @dev Enumerates the possible owner management operations
enum OwnerOp {
Add,
Remove,
Swap
}
/// @dev Describes a change to be made to the safe
struct OwnerChange {
uint8 timeDelta; // used to warp the vm
uint8 operation; // used to choose an OwnerOp
uint256 ownerIndex; // used to choose the owner to remove or swap out
uint256 newThreshold;
}
/// @dev Maps addresses to private keys
mapping(address => uint256) privateKeys;
/// @dev Tests that the guard correctly manages the lastLive mapping when owners are added, removed, or swapped
function testFuzz_OwnerManagement_works(
uint256 initialOwners,
uint256 threshold,
OwnerChange[] memory changes
)
external
{
vm.assume(changes.length < 20);
// Initialize the safe with more owners than changes, to ensure we don't try to remove them all
initialOwners = bound(initialOwners, changes.length, 2 * changes.length);
// We need at least one owner
initialOwners = initialOwners < 1 ? 1 : initialOwners;
// Limit the threshold to the number of owners
threshold = bound(threshold, 1, initialOwners);
// Generate the initial owners and keys and setup the safe
(address[] memory ownerAddrs, uint256[] memory ownerkeys) =
SafeTestLib.makeAddrsAndKeys("safeTest", initialOwners);
// record the private keys for later use
for (uint256 i = 0; i < ownerAddrs.length; i++) {
privateKeys[ownerAddrs[i]] = ownerkeys[i];
}
// Create the new safe and register the guard.
SafeInstance memory safeInstance = _setupSafe(ownerkeys, threshold);
livenessGuard = new WrappedGuard(safeInstance.safe);
safeInstance.setGuard(address(livenessGuard));
for (uint256 i = 0; i < changes.length; i++) {
vm.warp(block.timestamp + changes[i].timeDelta);
OwnerChange memory change = changes[i];
address[] memory currentOwners = safeInstance.safe.getOwners();
// Create a new owner address to add and store the key
(address newOwner, uint256 newKey) = makeAddrAndKey(string.concat("new owner", vm.toString(i)));
privateKeys[newOwner] = newKey;
OwnerOp op = OwnerOp(bound(change.operation, 0, uint256(type(OwnerOp).max)));
assertEq(livenessGuard.ownersBeforeLength(), 0);
if (op == OwnerOp.Add) {
assertEq(livenessGuard.lastLive(newOwner), 0);
assertFalse(safeInstance.safe.isOwner(newOwner));
change.newThreshold = bound(change.newThreshold, 1, currentOwners.length + 1);
safeInstance.addOwnerWithThreshold(newOwner, change.newThreshold);
assertTrue(safeInstance.safe.isOwner(newOwner));
assertEq(livenessGuard.lastLive(newOwner), block.timestamp);
} else {
// Ensure we're removing an owner at an index within bounds
uint256 ownerIndexToRemove = bound(change.ownerIndex, 0, currentOwners.length - 1);
address ownerToRemove = currentOwners[ownerIndexToRemove];
address prevOwner = safeInstance.getPrevOwner(ownerToRemove);
if (op == OwnerOp.Remove) {
if (currentOwners.length == 1) continue;
assertGe(livenessGuard.lastLive(ownerToRemove), 0);
assertTrue(safeInstance.safe.isOwner(ownerToRemove));
change.newThreshold = bound(change.newThreshold, 1, currentOwners.length - 1);
safeInstance.removeOwner(prevOwner, ownerToRemove, change.newThreshold);
assertFalse(safeInstance.safe.isOwner(ownerToRemove));
assertEq(livenessGuard.lastLive(ownerToRemove), 0);
} else if (op == OwnerOp.Swap) {
assertGe(livenessGuard.lastLive(ownerToRemove), 0);
assertTrue(safeInstance.safe.isOwner(ownerToRemove));
safeInstance.swapOwner(prevOwner, ownerToRemove, newOwner);
assertTrue(safeInstance.safe.isOwner(newOwner));
assertFalse(safeInstance.safe.isOwner(ownerToRemove));
assertEq(livenessGuard.lastLive(ownerToRemove), 0);
assertEq(livenessGuard.lastLive(newOwner), block.timestamp);
}
}
assertEq(livenessGuard.ownersBeforeLength(), 0);
_refreshOwners(safeInstance);
}
}
/// @dev Refreshes the owners and ownerPKs arrays in the SafeInstance
function _refreshOwners(SafeInstance memory instance) internal view {
// Get the current owners
instance.owners = instance.safe.getOwners();
// Looks up the private key for each owner
uint256[] memory unsortedOwnerPKs = new uint256[](instance.owners.length);
for (uint256 j = 0; j < instance.owners.length; j++) {
unsortedOwnerPKs[j] = privateKeys[instance.owners[j]];
}
// Sort the keys by address and store them in the SafeInstance
instance.ownerPKs = SafeTestLib.sortPKsByComputedAddress(unsortedOwnerPKs);
// Overwrite the SafeInstances owners array with the computed addresses from the ownerPKs array
for (uint256 k; k < instance.owners.length; k++) {
instance.owners[k] = SafeTestLib.getAddr(instance.ownerPKs[k]);
}
}
}
packages/contracts-bedrock/test/LivenessModule.t.sol
0 → 100644
View file @
96a7781a
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test, StdUtils } from "forge-std/Test.sol";
import { Safe } from "safe-contracts/Safe.sol";
import { SafeProxyFactory } from "safe-contracts/proxies/SafeProxyFactory.sol";
import { ModuleManager } from "safe-contracts/base/ModuleManager.sol";
import { OwnerManager } from "safe-contracts/base/OwnerManager.sol";
import { Enum } from "safe-contracts/common/Enum.sol";
import "test/safe-tools/SafeTestTools.sol";
import { LivenessModule } from "src/Safe/LivenessModule.sol";
import { LivenessGuard } from "src/Safe/LivenessGuard.sol";
contract LivenessModule_TestInit is Test, SafeTestTools {
using SafeTestLib for SafeInstance;
event SignersRecorded(bytes32 indexed txHash, address[] signers);
uint256 initTime = 10;
uint256 livenessInterval = 30 days;
uint256 minOwners = 6;
LivenessModule livenessModule;
LivenessGuard livenessGuard;
SafeInstance safeInstance;
address fallbackOwner;
/// @dev Removes an owner from the safe
function _removeAnOwner(address _ownerToRemove, address[] memory _owners) internal {
address[] memory prevOwners = new address[](1);
address[] memory ownersToRemove = new address[](1);
ownersToRemove[0] = _ownerToRemove;
prevOwners[0] = SafeTestLib.getPrevOwnerFromList(_ownerToRemove, _owners);
livenessModule.removeOwners(prevOwners, ownersToRemove);
}
/// @dev Set the current time to after the liveness interval
function _warpPastLivenessInterval() internal {
vm.warp(initTime + livenessInterval + 1);
}
/// @dev Sets up the test environment
function setUp() public virtual {
// Set the block timestamp to the initTime, so that signatures recorded in the first block
// are non-zero.
vm.warp(initTime);
// Create a Safe with 10 owners
(, uint256[] memory keys) = SafeTestLib.makeAddrsAndKeys("moduleTest", 10);
safeInstance = _setupSafe(keys, 8);
livenessGuard = new LivenessGuard(safeInstance.safe);
fallbackOwner = makeAddr("fallbackOwner");
livenessModule = new LivenessModule({
_safe: safeInstance.safe,
_livenessGuard: livenessGuard,
_livenessInterval: livenessInterval,
_minOwners: minOwners,
_fallbackOwner: fallbackOwner
});
safeInstance.setGuard(address(livenessGuard));
safeInstance.enableModule(address(livenessModule));
}
}
contract LivenessModule_Constructor_TestFail is LivenessModule_TestInit {
/// @dev Tests that the constructor fails if the minOwners is greater than the number of owners
function test_constructor_minOwnersGreaterThanOwners_reverts() external {
vm.expectRevert("LivenessModule: minOwners must be less than the number of owners");
new LivenessModule({
_safe: safeInstance.safe,
_livenessGuard: livenessGuard,
_livenessInterval: livenessInterval,
_minOwners: 11,
_fallbackOwner: address(0)
});
}
/// @dev Tests that the constructor fails if the minOwners is greater than the number of owners
function test_constructor_wrongThreshold_reverts() external {
uint256 wrongThreshold = livenessModule.get75PercentThreshold(safeInstance.owners.length) - 1;
vm.mockCall(
address(safeInstance.safe), abi.encodeCall(OwnerManager.getThreshold, ()), abi.encode(wrongThreshold)
);
vm.expectRevert("LivenessModule: Safe must have a threshold of at least 75% of the number of owners");
new LivenessModule({
_safe: safeInstance.safe,
_livenessGuard: livenessGuard,
_livenessInterval: livenessInterval,
_minOwners: minOwners,
_fallbackOwner: address(0)
});
}
}
contract LivenessModule_Getters_Test is LivenessModule_TestInit {
/// @dev Tests if the getters work correctly
function test_getters_works() external {
assertEq(address(livenessModule.safe()), address(safeInstance.safe));
assertEq(address(livenessModule.livenessGuard()), address(livenessGuard));
assertEq(livenessModule.livenessInterval(), 30 days);
assertEq(livenessModule.minOwners(), 6);
assertEq(livenessModule.fallbackOwner(), fallbackOwner);
}
}
contract LivenessModule_CanRemove_TestFail is LivenessModule_TestInit {
/// @dev Tests if canRemove work correctly
function test_canRemove_notSafeOwner_reverts() external {
address nonOwner = makeAddr("nonOwner");
vm.expectRevert("LivenessModule: the owner to remove must be an owner of the Safe");
livenessModule.canRemove(nonOwner);
}
}
contract LivenessModule_CanRemove_Test is LivenessModule_TestInit {
/// @dev Tests if canRemove work correctly
function test_canRemove_works() external {
_warpPastLivenessInterval();
bool canRemove = livenessModule.canRemove(safeInstance.owners[0]);
assertTrue(canRemove);
}
}
contract LivenessModule_Get75PercentThreshold_Test is LivenessModule_TestInit {
/// @dev check the return values of the get75PercentThreshold function against manually
/// calculated values.
function test_get75PercentThreshold_Works() external {
assertEq(livenessModule.get75PercentThreshold(20), 15);
assertEq(livenessModule.get75PercentThreshold(19), 15);
assertEq(livenessModule.get75PercentThreshold(18), 14);
assertEq(livenessModule.get75PercentThreshold(17), 13);
assertEq(livenessModule.get75PercentThreshold(16), 12);
assertEq(livenessModule.get75PercentThreshold(15), 12);
assertEq(livenessModule.get75PercentThreshold(14), 11);
assertEq(livenessModule.get75PercentThreshold(13), 10);
assertEq(livenessModule.get75PercentThreshold(12), 9);
assertEq(livenessModule.get75PercentThreshold(11), 9);
assertEq(livenessModule.get75PercentThreshold(10), 8);
assertEq(livenessModule.get75PercentThreshold(9), 7);
assertEq(livenessModule.get75PercentThreshold(8), 6);
assertEq(livenessModule.get75PercentThreshold(7), 6);
assertEq(livenessModule.get75PercentThreshold(6), 5);
assertEq(livenessModule.get75PercentThreshold(5), 4);
assertEq(livenessModule.get75PercentThreshold(4), 3);
assertEq(livenessModule.get75PercentThreshold(3), 3);
assertEq(livenessModule.get75PercentThreshold(2), 2);
assertEq(livenessModule.get75PercentThreshold(1), 1);
}
}
contract LivenessModule_RemoveOwners_TestFail is LivenessModule_TestInit {
using SafeTestLib for SafeInstance;
/// @dev Tests with different length owner arrays
function test_removeOwners_differentArrayLengths_reverts() external {
address[] memory ownersToRemove = new address[](1);
address[] memory prevOwners = new address[](2);
vm.expectRevert("LivenessModule: arrays must be the same length");
livenessModule.removeOwners(prevOwners, ownersToRemove);
}
/// @dev Test removing an owner which has recently signed a transaction
function test_removeOwners_ownerHasSignedRecently_reverts() external {
/// Will sign a transaction with the first M owners in the owners list
safeInstance.execTransaction({ to: address(1111), value: 0, data: hex"abba" });
address[] memory owners = safeInstance.safe.getOwners();
vm.expectRevert("LivenessModule: the owner to remove has signed recently");
_removeAnOwner(safeInstance.owners[0], owners);
}
/// @dev Test removing an owner which has recently called showLiveness
function test_removeOwners_ownerHasShownLivenessRecently_reverts() external {
/// Will sign a transaction with the first M owners in the owners list
vm.prank(safeInstance.owners[0]);
livenessGuard.showLiveness();
address[] memory owners = safeInstance.safe.getOwners();
vm.expectRevert("LivenessModule: the owner to remove has signed recently");
_removeAnOwner(safeInstance.owners[0], owners);
}
/// @dev Test removing an owner with an incorrect previous owner
function test_removeOwners_wrongPreviousOwner_reverts() external {
address[] memory prevOwners = new address[](1);
address[] memory ownersToRemove = new address[](1);
ownersToRemove[0] = safeInstance.owners[0];
prevOwners[0] = ownersToRemove[0]; // incorrect.
_warpPastLivenessInterval();
vm.expectRevert("LivenessModule: failed to remove owner");
livenessModule.removeOwners(prevOwners, ownersToRemove);
}
/// @dev Tests if removing all owners works correctly
function test_removeOwners_swapToFallbackOwner_reverts() external {
uint256 numOwners = safeInstance.owners.length;
address[] memory ownersToRemove = new address[](numOwners);
for (uint256 i = 0; i < numOwners; i++) {
ownersToRemove[i] = safeInstance.owners[i];
}
address[] memory prevOwners = safeInstance.getPrevOwners(ownersToRemove);
// Incorrectly set the final owner to address(0)
ownersToRemove[ownersToRemove.length - 1] = address(0);
_warpPastLivenessInterval();
vm.expectRevert("LivenessModule: failed to swap to fallback owner");
livenessModule.removeOwners(prevOwners, ownersToRemove);
}
/// @dev Tests if remove owners reverts if it removes too many owners without removing all of them
function test_removeOwners_belowMinButNotEmptied_reverts() external {
// Remove all but one owner
uint256 numOwners = safeInstance.owners.length - 2;
address[] memory ownersToRemove = new address[](numOwners);
for (uint256 i = 0; i < numOwners; i++) {
ownersToRemove[i] = safeInstance.owners[i];
}
address[] memory prevOwners = safeInstance.getPrevOwners(ownersToRemove);
_warpPastLivenessInterval();
vm.expectRevert(
"LivenessModule: must remove all owners and transfer to fallback owner if numOwners < minOwners"
);
livenessModule.removeOwners(prevOwners, ownersToRemove);
}
/// @dev Tests if remove owners reverts if it removes too many owners transferring to the shutDown owner
function test_removeOwners_belowEmptiedButNotShutDown_reverts() external {
// Remove all but one owner
uint256 numOwners = safeInstance.owners.length - 1;
address[] memory ownersToRemove = new address[](numOwners);
for (uint256 i = 0; i < numOwners; i++) {
ownersToRemove[i] = safeInstance.owners[i];
}
address[] memory prevOwners = safeInstance.getPrevOwners(ownersToRemove);
_warpPastLivenessInterval();
vm.expectRevert("LivenessModule: must transfer ownership to fallback owner");
livenessModule.removeOwners(prevOwners, ownersToRemove);
}
/// @dev Tests if remove owners reverts if the current Safe.guard does note match the expected
/// livenessGuard address.
function test_removeOwners_guardChanged_reverts() external {
address[] memory ownersToRemove = new address[](1);
ownersToRemove[0] = safeInstance.owners[0];
address[] memory prevOwners = safeInstance.getPrevOwners(ownersToRemove);
// Change the guard
livenessGuard = new LivenessGuard(safeInstance.safe);
safeInstance.setGuard(address(livenessGuard));
_warpPastLivenessInterval();
vm.expectRevert("LivenessModule: guard has been changed");
livenessModule.removeOwners(prevOwners, ownersToRemove);
}
function test_removeOwners_invalidThreshold_reverts() external {
address[] memory ownersToRemove = new address[](0);
address[] memory prevOwners = new address[](0);
uint256 wrongThreshold = safeInstance.safe.getThreshold() + 1;
vm.mockCall(
address(safeInstance.safe), abi.encodeCall(OwnerManager.getThreshold, ()), abi.encode(wrongThreshold)
);
_warpPastLivenessInterval();
vm.expectRevert("LivenessModule: Safe must have a threshold of 75% of the number of owners");
livenessModule.removeOwners(prevOwners, ownersToRemove);
}
}
contract LivenessModule_RemoveOwners_Test is LivenessModule_TestInit {
using SafeTestLib for SafeInstance;
/// @dev Tests if removing one owner works correctly
function test_removeOwners_oneOwner_succeeds() external {
uint256 ownersBefore = safeInstance.owners.length;
address ownerToRemove = safeInstance.owners[0];
_warpPastLivenessInterval();
_removeAnOwner(ownerToRemove, safeInstance.owners);
assertFalse(safeInstance.safe.isOwner(ownerToRemove));
assertEq(safeInstance.safe.getOwners().length, ownersBefore - 1);
}
/// @dev Tests if removing all owners works correctly
function test_removeOwners_allOwners_succeeds() external {
uint256 numOwners = safeInstance.owners.length;
address[] memory ownersToRemove = new address[](numOwners);
for (uint256 i = 0; i < numOwners; i++) {
ownersToRemove[i] = safeInstance.owners[i];
}
address[] memory prevOwners = safeInstance.getPrevOwners(ownersToRemove);
_warpPastLivenessInterval();
livenessModule.removeOwners(prevOwners, ownersToRemove);
assertEq(safeInstance.safe.getOwners().length, 1);
assertEq(safeInstance.safe.getOwners()[0], fallbackOwner);
assertEq(safeInstance.safe.getThreshold(), 1);
}
}
/// @dev A copy of LivenessModule.get75PercentThreshold as a free function to use below.
function get75PercentThreshold(uint256 _numOwners) pure returns (uint256 threshold_) {
threshold_ = (_numOwners * 75 + 99) / 100;
}
contract LivenessModule_RemoveOwnersFuzz_Test is LivenessModule_TestInit {
using SafeTestLib for SafeInstance;
/// @dev We put this array in storage so that we can more easily populate it using push in the tests below.
address[] ownersToRemove;
/// @dev Options for handling the event that the number of owners remaining is less than minOwners
enum ShutDownBehavior {
Correct, // Correctly removes the owners and transfers to the shutDown owner
DoesNotTransferToFallbackOwner, // Removes all but one owner, and does not transfer to the shutDown owner
DoesNotRemoveAllOwners // Leaves more than one owner when below minOwners
}
/// @dev This contract inherits the storage layout from the LivenessModule_TestInit contract, but we
/// override the base setUp function, to avoid instantiating an unnecessary Safe and liveness checking system.
function setUp() public override {
vm.warp(initTime);
fallbackOwner = makeAddr("fallbackOwner");
}
/// @dev Extracts the setup of the test environment into a separate function.
function _prepare(
uint256 _numOwners,
uint256 _minOwners,
uint256 _numLiveOwners
)
internal
returns (uint256 numOwners_, uint256 minOwners_, uint256 numLiveOwners_)
{
// First we modify the test parameters to ensure that they describe a plausible starting point.
//
// _numOwners must be at least 4, so that _minOwners can be set to at least 3 by the following bound() call.
// Limiting the owner set to 20 helps to keep the runtime of the test reasonable.
console.log("bounding numOwners");
numOwners_ = bound(_numOwners, 4, 20);
// _minOwners must be at least 3, otherwise we don't have any range below _minOwners in which to test all of the
// ShutDownBehavior options.
console.log("bounding minOwners");
minOwners_ = bound(_minOwners, 3, numOwners_ - 1);
// Ensure that _numLiveOwners is less than _numOwners so that we can remove at least one owner.
console.log("bounding numLiveOwners");
numLiveOwners_ = bound(_numLiveOwners, 0, numOwners_ - 1);
// The above bounds are a bit tricky, so we assert that the resulting parameters enable us to test all possible
// success and revert cases in the removeOwners function.
// This is also necessary to avoid underflows or out of bounds accesses in the test.
assertTrue(
numOwners_ > minOwners_ // We need to be able to remove at least one owner
&& numOwners_ >= numLiveOwners_ // We can have more live owners than there are owners
&& minOwners_ >= 3 // Allows us to test all of the ShutDownBehavior options when removing an owner
);
// Create a Safe with _numOwners owners
(, uint256[] memory keys) = SafeTestLib.makeAddrsAndKeys("rmOwnersTest", numOwners_);
uint256 threshold = get75PercentThreshold(numOwners_);
safeInstance = _setupSafe(keys, threshold);
livenessGuard = new LivenessGuard(safeInstance.safe);
livenessModule = new LivenessModule({
_safe: safeInstance.safe,
_livenessGuard: livenessGuard,
_livenessInterval: livenessInterval,
_minOwners: minOwners_,
_fallbackOwner: fallbackOwner
});
safeInstance.setGuard(address(livenessGuard));
safeInstance.enableModule(address(livenessModule));
// Warp ahead so that all owners non-live
_warpPastLivenessInterval();
}
/// @dev Tests if removing owners works correctly for various safe configurations and numbeers of live owners
function testFuzz_removeOwners(
uint256 _numOwners,
uint256 _minOwners,
uint256 _numLiveOwners,
uint256 _shutDownBehavior,
uint256 _numOwnersToRemoveinShutDown
)
external
{
// Prepare the test env and test params
(uint256 numOwners, uint256 minOwners, uint256 numLiveOwners) = _prepare(_numOwners, _minOwners, _numLiveOwners);
// Create an array of live owners, and call showLiveness for each of them
address[] memory liveOwners = new address[](numLiveOwners);
for (uint256 i = 0; i < numLiveOwners; i++) {
liveOwners[i] = safeInstance.owners[i];
vm.prank(safeInstance.owners[i]);
livenessGuard.showLiveness();
}
address[] memory nonLiveOwners = new address[](numOwners - numLiveOwners);
for (uint256 i = 0; i < numOwners - numLiveOwners; i++) {
nonLiveOwners[i] = safeInstance.owners[i + numLiveOwners];
}
address[] memory prevOwners;
if (numLiveOwners >= minOwners) {
console.log("No shutdown");
// The safe will remain above the minimum number of owners, so we can remove only those owners which are not
// live.
prevOwners = safeInstance.getPrevOwners(nonLiveOwners);
livenessModule.removeOwners(prevOwners, nonLiveOwners);
// Validate the resulting state of the Safe
assertEq(safeInstance.safe.getOwners().length, numLiveOwners);
assertEq(safeInstance.safe.getThreshold(), get75PercentThreshold(numLiveOwners));
for (uint256 i = 0; i < numLiveOwners; i++) {
assertTrue(safeInstance.safe.isOwner(liveOwners[i]));
}
for (uint256 i = 0; i < nonLiveOwners.length; i++) {
assertFalse(safeInstance.safe.isOwner(nonLiveOwners[i]));
}
} else {
// The number of non-live owners will push the safe below the minimum number of owners.
// We need to test all of the possible ShutDownBehavior options, so we'll create a ShutDownBehavior enum
// from the _shutDownBehavior input.
ShutDownBehavior shutDownBehavior =
ShutDownBehavior(bound(_shutDownBehavior, 0, uint256(type(ShutDownBehavior).max)));
// The safe is below the minimum number of owners.
// The ShutDownBehavior enum determines how we handle this case.
if (shutDownBehavior == ShutDownBehavior.Correct) {
console.log("Correct Shutdown");
// We remove all owners, and transfer ownership to the shutDown owner.
// but we need to do remove the non-live owners first, so we reverse the owners array, since
// the first owners in the array were the ones to call showLiveness.
// ownersToRemove = new address[](numOwners);
for (uint256 i = 0; i < numOwners; i++) {
// ownersToRemove[numOwners - i - 1] = safeInstance.owners[i];
// ownersToRemove[i] = safeInstance.owners[numOwners - i - 1];
ownersToRemove.push(safeInstance.owners[numOwners - i - 1]);
}
prevOwners = safeInstance.getPrevOwners(ownersToRemove);
livenessModule.removeOwners(prevOwners, ownersToRemove);
// Validate the resulting state of the Safe
assertEq(safeInstance.safe.getOwners().length, 1);
assertEq(safeInstance.safe.getOwners()[0], fallbackOwner);
assertEq(safeInstance.safe.getThreshold(), 1);
} else {
// For both of the incorrect behaviors, we need to calculate the number of owners to remove to
// trigger that behavior. We initialize that value here then set it in the if statements below.
uint256 numOwnersToRemoveinShutDown;
if (shutDownBehavior == ShutDownBehavior.DoesNotRemoveAllOwners) {
console.log("Shutdown DoesNotRemoveAllOwners");
// In the DoesNotRemoveAllOwners case, we should have more than 1 of the pre-existing owners
// remaining
console.log("bounding numOwnersToRemoveinShutDown");
numOwnersToRemoveinShutDown =
bound(_numOwnersToRemoveinShutDown, numOwners - minOwners + 1, numOwners - 2);
uint256 i = 0;
for (i; i < numOwnersToRemoveinShutDown; i++) {
// Add non-live owners to remove first
if (i < nonLiveOwners.length) {
ownersToRemove.push(nonLiveOwners[i]);
} else {
// Then add live owners to remove
ownersToRemove.push(liveOwners[i - nonLiveOwners.length]);
}
}
prevOwners = safeInstance.getPrevOwners(ownersToRemove);
vm.expectRevert(
"LivenessModule: must remove all owners and transfer to fallback owner if numOwners < minOwners"
);
livenessModule.removeOwners(prevOwners, ownersToRemove);
} else if (shutDownBehavior == ShutDownBehavior.DoesNotTransferToFallbackOwner) {
console.log("Shutdown DoesNotTransferToFallbackOwner");
// In the DoesNotRemoveAllOwners case, we should have exactly 1 pre-existing owners remaining
numOwnersToRemoveinShutDown = numOwners - 1;
uint256 i = 0;
for (i; i < numOwnersToRemoveinShutDown; i++) {
// Add non-live owners to remove first
if (i < nonLiveOwners.length) {
ownersToRemove.push(nonLiveOwners[i]);
} else {
// Then add live owners to remove
ownersToRemove.push(liveOwners[i - nonLiveOwners.length]);
}
}
prevOwners = safeInstance.getPrevOwners(ownersToRemove);
vm.expectRevert("LivenessModule: must transfer ownership to fallback owner");
livenessModule.removeOwners(prevOwners, ownersToRemove);
}
// For both of the incorrect behaviors, verify no change to the Safe state
assertEq(safeInstance.safe.getOwners().length, numOwners);
assertEq(safeInstance.safe.getThreshold(), get75PercentThreshold(numOwners));
for (uint256 j = 0; j < numOwners; j++) {
assertTrue(safeInstance.safe.isOwner(safeInstance.owners[j]));
}
}
}
}
}
packages/contracts-bedrock/test/SafeSigners.t.sol
0 → 100644
View file @
96a7781a
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
import { Safe } from "safe-contracts/Safe.sol";
import { SafeSigners } from "src/Safe/SafeSigners.sol";
import "test/safe-tools/SafeTestTools.sol";
import { SignatureDecoder } from "safe-contracts/common/SignatureDecoder.sol";
contract SafeSigners_Test is Test, SafeTestTools {
bytes4 internal constant EIP1271_MAGIC_VALUE = 0x20c13b0b;
enum SigTypes {
Eoa,
EthSign,
ApprovedHash,
Contract
}
/// @dev Maps every key to one of the 4 signatures types.
/// This is used in the tests below as a pseudorandom mechanism for determining which
/// signature type to use for each key.
/// @param _key The key to map to a signature type.
function sigType(uint256 _key) internal pure returns (SigTypes sigType_) {
uint256 t = _key % 4;
sigType_ = SigTypes(t);
}
/// @dev Test that for a given set of signatures:
/// 1. safe.checkNSignatures() succeeds
/// 2. the getSigners() method returns the expected signers
/// 3. the expected signers are all owners of the safe.
/// Demonstrating these three properties is sufficient to prove that the getSigners() method
/// returns the same signatures as those recovered by safe.checkNSignatures().
function testDiff_getSignaturesVsCheckSignatures_succeeds(bytes memory _data, uint256 _numSigs) external {
bytes32 digest = keccak256(_data);
// Limit the number of signatures to 25
uint256 numSigs = bound(_numSigs, 1, 25);
(, uint256[] memory keys) = SafeTestLib.makeAddrsAndKeys("getSigsTest", numSigs);
for (uint256 i = 0; i < keys.length; i++) {
if (sigType(keys[i]) == SigTypes.Contract) {
keys[i] =
SafeTestLib.encodeSmartContractWalletAsPK(SafeTestLib.decodeSmartContractWalletAsAddress(keys[i]));
}
}
// Create a new safeInstance with M=N, so that it requires a signature from each key.
SafeInstance memory safeInstance = SafeTestTools._setupSafe(keys, numSigs, 0);
// Next we will generate signatures by iterating over the keys, and choosing the signature type
// based on the key.
uint8 v;
bytes32 r;
bytes32 s;
uint256 contractSigs;
bytes memory signatures;
uint256[] memory pks = safeInstance.ownerPKs;
for (uint256 i; i < pks.length; i++) {
if (sigType(pks[i]) == SigTypes.Eoa) {
(v, r, s) = vm.sign(pks[i], digest);
signatures = bytes.concat(signatures, abi.encodePacked(r, s, v));
} else if (sigType(pks[i]) == SigTypes.EthSign) {
(v, r, s) = vm.sign(pks[i], keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest)));
v += 4;
signatures = bytes.concat(signatures, abi.encodePacked(r, s, v));
} else if (sigType(pks[i]) == SigTypes.ApprovedHash) {
vm.prank(SafeTestLib.getAddr(pks[i]));
safeInstance.safe.approveHash(digest);
v = 1;
// s is not checked on approved hash signatures, so we can leave it as zero.
r = bytes32(uint256(uint160(SafeTestLib.getAddr(pks[i]))));
signatures = bytes.concat(signatures, abi.encodePacked(r, s, v));
} else if (sigType(pks[i]) == SigTypes.Contract) {
contractSigs++;
address addr = SafeTestLib.decodeSmartContractWalletAsAddress(pks[i]);
r = bytes32(uint256(uint160(addr)));
vm.mockCall(
addr, abi.encodeWithSignature("isValidSignature(bytes,bytes)"), abi.encode(EIP1271_MAGIC_VALUE)
);
v = 0;
// s needs to point to data that comes after the signatures
s = bytes32(numSigs * 65);
signatures = bytes.concat(signatures, abi.encodePacked(r, s, v));
}
}
// For each contract sig, add 64 bytes to the signature data. This is necessary to satisfy
// the validation checks that the Safe contract performs on the value of s on contract
// signatures. The Safe contract checks that s correctly points to additional data appended
// after the signatures, and that the length of the data is within bounds.
for (uint256 i = 0; i < contractSigs; i++) {
signatures = bytes.concat(signatures, abi.encode(32, 1));
}
// Signature checking on the Safe should succeed.
safeInstance.safe.checkNSignatures(digest, _data, signatures, numSigs);
// Recover the signatures using the _getNSigners() method.
address[] memory gotSigners =
SafeSigners.getNSigners({ dataHash: digest, signatures: signatures, requiredSignatures: numSigs });
// Compare the list of recovered signers to the expected signers.
assertEq(gotSigners.length, numSigs);
assertEq(gotSigners.length, safeInstance.owners.length);
for (uint256 i; i < numSigs; i++) {
assertEq(safeInstance.owners[i], gotSigners[i]);
}
}
}
packages/contracts-bedrock/test/safe-tools/CompatibilityFallbackHandler_1_3_0.sol
0 → 100644
View file @
96a7781a
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import "safe-contracts/interfaces/ERC1155TokenReceiver.sol";
import "safe-contracts/interfaces/ERC721TokenReceiver.sol";
import "safe-contracts/interfaces/ERC777TokensRecipient.sol";
import "safe-contracts/interfaces/IERC165.sol";
import "safe-contracts/interfaces/ISignatureValidator.sol";
import { Safe as GnosisSafe } from "safe-contracts/Safe.sol";
/// author: Colin Nielsen
/// https://github.com/colinnielsen/safe-tools/blob/ce6c654a76d91b619ab7778c77d1a76b3ced6666/src/CompatibilityFallbackHandler_1_3_0.sol
contract DefaultCallbackHandler is ERC1155TokenReceiver, ERC777TokensRecipient, ERC721TokenReceiver, IERC165 {
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes calldata
)
external
pure
override
returns (bytes4)
{
return 0xf23a6e61;
}
function onERC1155BatchReceived(
address,
address,
uint256[] calldata,
uint256[] calldata,
bytes calldata
)
external
pure
override
returns (bytes4)
{
return 0xbc197c81;
}
function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) {
return 0x150b7a02;
}
function tokensReceived(
address,
address,
address,
uint256,
bytes calldata,
bytes calldata
)
external
pure
override
{
// We implement this for completeness, doesn't really have any value
}
function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) {
return interfaceId == type(ERC1155TokenReceiver).interfaceId
|| interfaceId == type(ERC721TokenReceiver).interfaceId || interfaceId == type(IERC165).interfaceId;
}
}
address constant SENTINEL_MODULES = address(0x1);
/// @title Compatibility Fallback Handler - fallback handler to provider compatibility between pre 1.3.0 and 1.3.0+ Safe
/// contracts
/// @author Richard Meissner - <richard@gnosis.pm>
contract CompatibilityFallbackHandler is DefaultCallbackHandler, ISignatureValidator {
//keccak256(
// "SafeMessage(bytes message)"
//);
bytes32 private constant SAFE_MSG_TYPEHASH = 0x60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca;
bytes4 internal constant SIMULATE_SELECTOR = bytes4(keccak256("simulate(address,bytes)"));
bytes4 internal constant UPDATED_MAGIC_VALUE = 0x1626ba7e;
/**
* Implementation of ISignatureValidator (see `interfaces/ISignatureValidator.sol`)
* @dev Should return whether the signature provided is valid for the provided data.
* @param _data Arbitrary length data signed on the behalf of address(msg.sender)
* @param _signature Signature byte array associated with _data
* @return a bool upon valid or invalid signature with corresponding _data
*/
function isValidSignature(bytes memory _data, bytes memory _signature) public view override returns (bytes4) {
// Caller should be a Safe
GnosisSafe safe = GnosisSafe(payable(msg.sender));
bytes32 messageHash = getMessageHashForSafe(safe, _data);
if (_signature.length == 0) {
require(safe.signedMessages(messageHash) != 0, "Hash not approved");
} else {
safe.checkSignatures(messageHash, _data, _signature);
}
return EIP1271_MAGIC_VALUE;
}
/// @dev Returns hash of a message that can be signed by owners.
/// @param message Message that should be hashed
/// @return Message hash.
function getMessageHash(bytes memory message) public view returns (bytes32) {
return getMessageHashForSafe(GnosisSafe(payable(msg.sender)), message);
}
/// @dev Returns hash of a message that can be signed by owners.
/// @param safe Safe to which the message is targeted
/// @param message Message that should be hashed
/// @return Message hash.
function getMessageHashForSafe(GnosisSafe safe, bytes memory message) public view returns (bytes32) {
bytes32 safeMessageHash = keccak256(abi.encode(SAFE_MSG_TYPEHASH, keccak256(message)));
return keccak256(abi.encodePacked(bytes1(0x19), bytes1(0x01), safe.domainSeparator(), safeMessageHash));
}
/**
* Implementation of updated EIP-1271
* @dev Should return whether the signature provided is valid for the provided data.
* The save does not implement the interface since `checkSignatures` is not a view method.
* The method will not perform any state changes (see parameters of `checkSignatures`)
* @param _dataHash Hash of the data signed on the behalf of address(msg.sender)
* @param _signature Signature byte array associated with _dataHash
* @return a bool upon valid or invalid signature with corresponding _dataHash
* @notice See
* https://github.com/gnosis/util-contracts/blob/bb5fe5fb5df6d8400998094fb1b32a178a47c3a1/contracts/StorageAccessible.sol
*/
function isValidSignature(bytes32 _dataHash, bytes calldata _signature) external view returns (bytes4) {
ISignatureValidator validator = ISignatureValidator(msg.sender);
bytes4 value = validator.isValidSignature(abi.encode(_dataHash), _signature);
return (value == EIP1271_MAGIC_VALUE) ? UPDATED_MAGIC_VALUE : bytes4(0);
}
/// @dev Returns array of first 10 modules.
/// @return Array of modules.
function getModules() external view returns (address[] memory) {
// Caller should be a Safe
GnosisSafe safe = GnosisSafe(payable(msg.sender));
(address[] memory array,) = safe.getModulesPaginated(SENTINEL_MODULES, 10);
return array;
}
/**
* @dev Performs a delegetecall on a targetContract in the context of self.
* Internally reverts execution to avoid side effects (making it static). Catches revert and returns encoded result
* as bytes.
* @param targetContract Address of the contract containing the code to execute.
* @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
*/
function simulate(
address targetContract,
bytes calldata calldataPayload
)
external
returns (bytes memory response)
{
// Suppress compiler warnings about not using parameters, while allowing
// parameters to keep names for documentation purposes. This does not
// generate code.
targetContract;
calldataPayload;
// solhint-disable-next-line no-inline-assembly
assembly {
let internalCalldata := mload(0x40)
// Store `simulateAndRevert.selector`.
// String representation is used to force right padding
mstore(internalCalldata, "\xb4\xfa\xba\x09")
// Abuse the fact that both this and the internal methods have the
// same signature, and differ only in symbol name (and therefore,
// selector) and copy calldata directly. This saves us approximately
// 250 bytes of code and 300 gas at runtime over the
// `abi.encodeWithSelector` builtin.
calldatacopy(add(internalCalldata, 0x04), 0x04, sub(calldatasize(), 0x04))
// `pop` is required here by the compiler, as top level expressions
// can't have return values in inline assembly. `call` typically
// returns a 0 or 1 value indicated whether or not it reverted, but
// since we know it will always revert, we can safely ignore it.
pop(
call(
gas(),
// address() has been changed to caller() to use the implementation of the Safe
caller(),
0,
internalCalldata,
calldatasize(),
// The `simulateAndRevert` call always reverts, and
// instead encodes whether or not it was successful in the return
// data. The first 32-byte word of the return data contains the
// `success` value, so write it to memory address 0x00 (which is
// reserved Solidity scratch space and OK to use).
0x00,
0x20
)
)
// Allocate and copy the response bytes, making sure to increment
// the free memory pointer accordingly (in case this method is
// called as an internal function). The remaining `returndata[0x20:]`
// contains the ABI encoded response bytes, so we can just write it
// as is to memory.
let responseSize := sub(returndatasize(), 0x20)
response := mload(0x40)
mstore(0x40, add(response, responseSize))
returndatacopy(response, 0x20, responseSize)
if iszero(mload(0x00)) { revert(add(response, 0x20), mload(response)) }
}
}
}
packages/contracts-bedrock/test/safe-tools/SafeTestTools.sol
0 → 100644
View file @
96a7781a
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
import "forge-std/Test.sol";
import "scripts/libraries/LibSort.sol";
import { Safe as GnosisSafe, OwnerManager, ModuleManager, GuardManager } from "safe-contracts/Safe.sol";
import { SafeProxyFactory as GnosisSafeProxyFactory } from "safe-contracts/proxies/SafeProxyFactory.sol";
import { Enum } from "safe-contracts/common/Enum.sol";
import { SignMessageLib } from "safe-contracts/libraries/SignMessageLib.sol";
import "./CompatibilityFallbackHandler_1_3_0.sol";
// Tools to simplify testing Safe contracts
// Author: Colin Nielsen (https://github.com/colinnielsen/safe-tools)
// With expanded and improved functionality by OP Labs
/// @dev A minimal wrapper around the OwnerManager contract. This contract is meant to be initialized with
/// the same owners as a Safe instance, and then used to simulate the resulting owners list
/// after an owner is removed.
contract OwnerSimulator is OwnerManager {
constructor(address[] memory _owners, uint256 _threshold) {
setupOwners(_owners, _threshold);
}
/// @dev Exposes the OwnerManager's removeOwner function so that anyone may call without needing auth
function removeOwnerWrapped(address prevOwner, address owner, uint256 _threshold) public {
OwnerManager(address(this)).removeOwner(prevOwner, owner, _threshold);
}
}
/// @dev collapsed interface that includes comapatibilityfallback handler calls
abstract contract DeployedSafe is GnosisSafe, CompatibilityFallbackHandler { }
struct AdvancedSafeInitParams {
bool includeFallbackHandler;
uint256 saltNonce;
address setupModulesCall_to;
bytes setupModulesCall_data;
uint256 refundAmount;
address refundToken;
address payable refundReceiver;
bytes initData;
}
struct SafeInstance {
uint256 instanceId;
uint256[] ownerPKs;
address[] owners;
uint256 threshold;
DeployedSafe safe;
}
library Sort {
/// @dev Sorts an array of addresses in place
function sort(address[] memory arr) public pure returns (address[] memory) {
LibSort.sort(arr);
return arr;
}
}
library SafeTestLib {
/// @dev The address of foundry's VM contract
address constant VM_ADDR = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D;
/// @dev The address of the first owner in the linked list of owners
address constant SENTINEL_OWNERS = address(0x1);
/// @dev Get the address from a private key
function getAddr(uint256 pk) internal pure returns (address) {
return Vm(VM_ADDR).addr(pk);
}
/// @dev Get arrays of addresses and private keys. The arrays are sorted by address, and the addresses are labelled
function makeAddrsAndKeys(
string memory prefix,
uint256 num
)
internal
returns (address[] memory addrs, uint256[] memory keys)
{
keys = new uint256[](num);
addrs = new address[](num);
for (uint256 i; i < num; i++) {
uint256 key = uint256(keccak256(abi.encodePacked(i)));
keys[i] = key;
}
for (uint256 i; i < num; i++) {
addrs[i] = Vm(VM_ADDR).addr(keys[i]);
Vm(VM_ADDR).label(getAddr(keys[i]), string.concat(prefix, Vm(VM_ADDR).toString(i)));
}
}
bytes12 constant ADDR_MASK = 0xffffffffffffffffffffffff;
/// @dev Encode a smart contract wallet as a private key
function encodeSmartContractWalletAsPK(address addr) internal pure returns (uint256 encodedPK) {
assembly {
let addr_b32 := addr
encodedPK := or(addr, ADDR_MASK)
}
}
/// @dev Decode a smart contract wallet as an address from a private key
function decodeSmartContractWalletAsAddress(uint256 pk) internal pure returns (address decodedAddr) {
assembly {
let addr := shl(96, pk)
decodedAddr := shr(96, addr)
}
}
/// @dev Checks if a private key is an encoded smart contract address
function isSmartContractPK(uint256 pk) internal pure returns (bool isEncoded) {
assembly {
isEncoded := eq(shr(160, pk), shr(160, ADDR_MASK))
}
}
/// @dev Sorts an array of private keys by the computed address
/// If the private key is a smart contract wallet, it will be decoded and sorted by the address
function sortPKsByComputedAddress(uint256[] memory _pks) internal pure returns (uint256[] memory) {
uint256[] memory sortedPKs = new uint256[](_pks.length);
address[] memory addresses = new address[](_pks.length);
bytes32[2][] memory accounts = new bytes32[2][](_pks.length);
for (uint256 i; i < _pks.length; i++) {
uint256 pk = _pks[i];
address signer = SafeTestLib.getAddr(pk);
if (isSmartContractPK(pk)) {
signer = decodeSmartContractWalletAsAddress(pk);
}
addresses[i] = signer;
accounts[i][0] = bytes32(abi.encode(signer));
accounts[i][1] = bytes32(pk);
}
addresses = Sort.sort(addresses);
uint256 found;
for (uint256 j; j < addresses.length; j++) {
address signer = addresses[j];
uint256 pk;
for (uint256 k; k < accounts.length; k++) {
if (address(uint160(uint256(accounts[k][0]))) == signer) {
pk = uint256(accounts[k][1]);
found++;
}
}
sortedPKs[j] = pk;
}
if (found < _pks.length) {
revert("SAFETESTTOOLS: issue with private key sorting, please open a ticket on github");
}
return sortedPKs;
}
/// @dev Sign a transaction as a safe owner with a private key.
function signTransaction(
SafeInstance memory instance,
uint256 pk,
address to,
uint256 value,
bytes memory data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver
)
internal
view
returns (uint8 v, bytes32 r, bytes32 s)
{
bytes32 txDataHash;
{
uint256 _nonce = instance.safe.nonce();
txDataHash = instance.safe.getTransactionHash({
to: to,
value: value,
data: data,
operation: operation,
safeTxGas: safeTxGas,
baseGas: baseGas,
gasPrice: gasPrice,
gasToken: gasToken,
refundReceiver: refundReceiver,
_nonce: _nonce
});
}
(v, r, s) = Vm(VM_ADDR).sign(pk, txDataHash);
}
/// @dev Get the previous owner in the linked list of owners.
/// This version of getPrevOwner will call to the Safe contract to get the current list of owners.
/// Note that this will break vm.expectRevert() tests by making a call which does not revert..
/// @param _owner The owner whose previous owner we want to find
function getPrevOwner(SafeInstance memory instance, address _owner) internal view returns (address prevOwner_) {
address[] memory owners = instance.safe.getOwners();
prevOwner_ = getPrevOwnerFromList(_owner, owners);
}
/// @dev Get the previous owner in the provided list of owners.
/// This version of getPrevOwner accepts a list of owners, and will return the previous owner.
/// It is useful when testing for a revert, as it avoids the need to call to the Safe contract.
/// @param _owner The owner whose previous owner we want to find
/// @param _ownersList The list of owners to search in
function getPrevOwnerFromList(
address _owner,
address[] memory _ownersList
)
internal
view
returns (
// pure
address prevOwner_
)
{
// console.log("getPrevOwnerFromList");
for (uint256 i = 0; i < _ownersList.length; i++) {
// console.log(i);
// console.log(_owner);
// console.log("_ownersList[i]:", _ownersList[i]);
if (_ownersList[i] != _owner) continue;
if (i == 0) {
prevOwner_ = SENTINEL_OWNERS;
break;
}
prevOwner_ = _ownersList[i - 1];
}
console.log("prevOwner_:", prevOwner_);
}
/// @dev Given an array of owners to remove, this function will return an array of the previous owners
/// in the order that they must be provided to the LivenessMoules's removeOwners() function.
/// Because owners are removed one at a time, and not necessarily in order, we need to simulate
/// the owners list after each removal, in order to identify the correct previous owner.
/// @param _ownersToRemove The owners to remove
/// @return prevOwners_ The previous owners in the linked list
function getPrevOwners(
SafeInstance memory instance,
address[] memory _ownersToRemove
)
internal
returns (address[] memory prevOwners_)
{
OwnerSimulator ownerSimulator = new OwnerSimulator(instance.owners, 1);
prevOwners_ = new address[](_ownersToRemove.length);
address[] memory currentOwners;
for (uint256 i = 0; i < _ownersToRemove.length; i++) {
currentOwners = ownerSimulator.getOwners();
prevOwners_[i] = SafeTestLib.getPrevOwnerFromList(_ownersToRemove[i], currentOwners);
// Don't try to remove the last owner
if (currentOwners.length == 1) break;
ownerSimulator.removeOwnerWrapped(prevOwners_[i], _ownersToRemove[i], 1);
}
}
/// @dev Enables a module on the Safe.
function enableModule(SafeInstance memory instance, address module) internal {
execTransaction(
instance,
address(instance.safe),
0,
abi.encodeWithSelector(ModuleManager.enableModule.selector, module),
Enum.Operation.Call,
0,
0,
0,
address(0),
address(0),
""
);
}
/// @dev Disables a module on the Safe.
function disableModule(SafeInstance memory instance, address module) internal {
(address[] memory modules,) = instance.safe.getModulesPaginated(SENTINEL_MODULES, 1000);
address prevModule = SENTINEL_MODULES;
bool moduleFound;
for (uint256 i; i < modules.length; i++) {
if (modules[i] == module) {
moduleFound = true;
break;
}
prevModule = modules[i];
}
if (!moduleFound) revert("SAFETESTTOOLS: cannot disable module that is not enabled");
execTransaction(
instance,
address(instance.safe),
0,
abi.encodeWithSelector(ModuleManager.disableModule.selector, prevModule, module),
Enum.Operation.Call,
0,
0,
0,
address(0),
address(0),
""
);
}
/// @dev Sets the guard address on the Safe. Unlike modules there can only be one guard, so
/// this method will remove the previous guard. If the guard is set to the 0 address, the
/// guard will be disabled.
function setGuard(SafeInstance memory instance, address guard) internal {
execTransaction(
instance,
address(instance.safe),
0,
abi.encodeWithSelector(GuardManager.setGuard.selector, guard),
Enum.Operation.Call,
0,
0,
0,
address(0),
address(0),
""
);
}
/// @dev Signs message data using EIP1271: Standard Signature Validation Method for Contracts
function EIP1271Sign(SafeInstance memory instance, bytes memory data) internal {
address signMessageLib = address(new SignMessageLib());
execTransaction({
instance: instance,
to: signMessageLib,
value: 0,
data: abi.encodeWithSelector(SignMessageLib.signMessage.selector, data),
operation: Enum.Operation.DelegateCall,
safeTxGas: 0,
baseGas: 0,
gasPrice: 0,
gasToken: address(0),
refundReceiver: payable(address(0)),
signatures: ""
});
}
/// @dev Signs a data hash using EIP1271: Standard Signature Validation Method for Contracts
function EIP1271Sign(SafeInstance memory instance, bytes32 digest) internal {
EIP1271Sign(instance, abi.encodePacked(digest));
}
/// @dev Increments the nonce of the Safe by sending an empty transaction.
function incrementNonce(SafeInstance memory instance) internal returns (uint256 newNonce) {
execTransaction(instance, address(0), 0, "", Enum.Operation.Call, 0, 0, 0, address(0), address(0), "");
return instance.safe.nonce();
}
/// @dev Adds a new owner to the safe
function changeThreshold(SafeInstance memory instance, uint256 threshold) internal {
execTransaction(
instance,
address(instance.safe),
0,
abi.encodeWithSelector(OwnerManager.changeThreshold.selector, threshold)
);
}
/// @dev Adds a new owner to the safe
function addOwnerWithThreshold(SafeInstance memory instance, address owner, uint256 threshold) internal {
execTransaction(
instance,
address(instance.safe),
0,
abi.encodeWithSelector(OwnerManager.addOwnerWithThreshold.selector, owner, threshold)
);
}
/// @dev Removes an owner from the safe. If not provided explictly, the identification of the prevOwner is handled
/// automatically.
function removeOwner(SafeInstance memory instance, address prevOwner, address owner, uint256 threshold) internal {
prevOwner = prevOwner > address(0) ? prevOwner : SafeTestLib.getPrevOwner(instance, owner);
execTransaction(
instance,
address(instance.safe),
0,
abi.encodeWithSelector(OwnerManager.removeOwner.selector, prevOwner, owner, threshold)
);
}
/// @dev Replaces an old owner with a new owner. If not provided explictly, the identification of the prevOwner is
/// handled automatically.
function swapOwner(SafeInstance memory instance, address prevOwner, address oldOwner, address newOwner) internal {
prevOwner = prevOwner > address(0) ? prevOwner : SafeTestLib.getPrevOwner(instance, oldOwner);
execTransaction(
instance,
address(instance.safe),
0,
abi.encodeWithSelector(OwnerManager.swapOwner.selector, prevOwner, oldOwner, newOwner)
);
}
/// @dev A wrapper for the full execTransaction method, if no signatures are provided it will
/// generate them for all owners.
function execTransaction(
SafeInstance memory instance,
address to,
uint256 value,
bytes memory data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
bytes memory signatures
)
internal
returns (bool)
{
if (instance.owners.length == 0) {
revert("SAFETEST: Instance not initialized. Call _setupSafe() to initialize a test safe");
}
bytes32 safeTxHash;
{
uint256 _nonce = instance.safe.nonce();
safeTxHash = instance.safe.getTransactionHash({
to: to,
value: value,
data: data,
operation: operation,
safeTxGas: safeTxGas,
baseGas: baseGas,
gasPrice: gasPrice,
gasToken: gasToken,
refundReceiver: refundReceiver,
_nonce: _nonce
});
}
if (signatures.length == 0) {
for (uint256 i; i < instance.ownerPKs.length; ++i) {
uint256 pk = instance.ownerPKs[i];
(uint8 v, bytes32 r, bytes32 s) = Vm(VM_ADDR).sign(pk, safeTxHash);
if (isSmartContractPK(pk)) {
v = 0;
address addr = decodeSmartContractWalletAsAddress(pk);
assembly {
r := addr
}
console.logBytes32(r);
}
signatures = bytes.concat(signatures, abi.encodePacked(r, s, v));
}
}
return instance.safe.execTransaction({
to: to,
value: value,
data: data,
operation: operation,
safeTxGas: safeTxGas,
baseGas: baseGas,
gasPrice: gasPrice,
gasToken: gasToken,
refundReceiver: payable(refundReceiver),
signatures: signatures
});
}
/// @dev Executes either a CALL or DELEGATECALL transaction.
function execTransaction(
SafeInstance memory instance,
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
)
internal
returns (bool)
{
return execTransaction(instance, to, value, data, operation, 0, 0, 0, address(0), address(0), "");
}
/// @dev Executes a CALL transaction.
function execTransaction(
SafeInstance memory instance,
address to,
uint256 value,
bytes memory data
)
internal
returns (bool)
{
return execTransaction(instance, to, value, data, Enum.Operation.Call, 0, 0, 0, address(0), address(0), "");
}
}
/// @dev SafeTestTools implements a set of helper functions for testing Safe contracts.
contract SafeTestTools {
using SafeTestLib for SafeInstance;
GnosisSafe internal singleton = new GnosisSafe();
GnosisSafeProxyFactory internal proxyFactory = new GnosisSafeProxyFactory();
CompatibilityFallbackHandler internal handler = new CompatibilityFallbackHandler();
SafeInstance[] internal instances;
/// @dev can be called to reinitialize the singleton, proxyFactory and handler. Useful for forking.
function _initializeSafeTools() internal {
singleton = new GnosisSafe();
proxyFactory = new GnosisSafeProxyFactory();
handler = new CompatibilityFallbackHandler();
}
function _setupSafe(
uint256[] memory ownerPKs,
uint256 threshold,
uint256 initialBalance,
AdvancedSafeInitParams memory advancedParams
)
public
returns (SafeInstance memory)
{
uint256[] memory sortedPKs = SafeTestLib.sortPKsByComputedAddress(ownerPKs);
address[] memory owners = new address[](sortedPKs.length);
for (uint256 i; i < sortedPKs.length; i++) {
if (SafeTestLib.isSmartContractPK(sortedPKs[i])) {
owners[i] = SafeTestLib.decodeSmartContractWalletAsAddress(sortedPKs[i]);
} else {
owners[i] = SafeTestLib.getAddr(sortedPKs[i]);
}
}
// store the initialization parameters
bytes memory initData = advancedParams.initData.length > 0
? advancedParams.initData
: abi.encodeWithSelector(
GnosisSafe.setup.selector,
owners,
threshold,
advancedParams.setupModulesCall_to,
advancedParams.setupModulesCall_data,
advancedParams.includeFallbackHandler ? address(handler) : address(0),
advancedParams.refundToken,
advancedParams.refundAmount,
advancedParams.refundReceiver
);
DeployedSafe safe0 = DeployedSafe(
payable(proxyFactory.createProxyWithNonce(address(singleton), initData, advancedParams.saltNonce))
);
SafeInstance memory instance0 = SafeInstance({
instanceId: instances.length,
ownerPKs: sortedPKs,
owners: owners,
threshold: threshold,
// setup safe ecosystem, singleton, proxy factory, fallback handler, and create a new safe
safe: safe0
});
instances.push(instance0);
Vm(SafeTestLib.VM_ADDR).deal(address(safe0), initialBalance);
return instance0;
}
function _setupSafe(
uint256[] memory ownerPKs,
uint256 threshold,
uint256 initialBalance
)
public
returns (SafeInstance memory)
{
return _setupSafe(
ownerPKs,
threshold,
initialBalance,
AdvancedSafeInitParams({
includeFallbackHandler: true,
initData: "",
saltNonce: 0,
setupModulesCall_to: address(0),
setupModulesCall_data: "",
refundAmount: 0,
refundToken: address(0),
refundReceiver: payable(address(0))
})
);
}
function _setupSafe(uint256[] memory ownerPKs, uint256 threshold) public returns (SafeInstance memory) {
return _setupSafe(
ownerPKs,
threshold,
10000 ether,
AdvancedSafeInitParams({
includeFallbackHandler: true,
initData: "",
saltNonce: 0,
setupModulesCall_to: address(0),
setupModulesCall_data: "",
refundAmount: 0,
refundToken: address(0),
refundReceiver: payable(address(0))
})
);
}
function _setupSafe() public returns (SafeInstance memory) {
(, uint256[] memory defaultPKs) = SafeTestLib.makeAddrsAndKeys("default", 3);
return _setupSafe(
defaultPKs,
2,
10000 ether,
AdvancedSafeInitParams({
includeFallbackHandler: true,
initData: "",
saltNonce: uint256(keccak256(bytes("SAFE TEST"))),
setupModulesCall_to: address(0),
setupModulesCall_data: "",
refundAmount: 0,
refundToken: address(0),
refundReceiver: payable(address(0))
})
);
}
function getSafe() public view returns (SafeInstance memory) {
if (instances.length == 0) {
revert("SAFETESTTOOLS: Test Safe has not been deployed, use _setupSafe() calling safe()");
}
return instances[0];
}
function getSafe(address _safe) public view returns (SafeInstance memory) {
for (uint256 i; i < instances.length; ++i) {
if (address(instances[i].safe) == _safe) return instances[i];
}
revert("SAFETESTTOOLS: Safe instance not found");
}
}
specs/safe-liveness-checking.md
0 → 100644
View file @
96a7781a
# Safe Liveness Checking
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**
-
[
Liveness checking Mechanism
](
#liveness-checking-mechanism
)
-
[
Liveness checking methodology
](
#liveness-checking-methodology
)
-
[
The liveness guard
](
#the-liveness-guard
)
-
[
The liveness module
](
#the-liveness-module
)
-
[
Owner removal call flow
](
#owner-removal-call-flow
)
-
[
Shutdown
](
#shutdown
)
-
[
Security Properties
](
#security-properties
)
-
[
Interdependency between the guard and module
](
#interdependency-between-the-guard-and-module
)
-
[
Deploying the liveness checking system
](
#deploying-the-liveness-checking-system
)
-
[
Modify the liveness checking system
](
#modify-the-liveness-checking-system
)
-
[
Replacing the module
](
#replacing-the-module
)
-
[
Replacing the guard
](
#replacing-the-guard
)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Liveness checking Mechanism
The Security Security Council uses a specially extended Safe multisig contract to ensure that
any loss of access to a signer's keys is identified and addressed within a predictable period of
time.
This mechanism is intended only to be used to remove signers who have lost access to their keys, or
are otherwise inactive. It is not intended to be used to remove signers who are acting in bad faith,
or any other subjective criteria, such cases should be addressed by governance, and the removal
handled via the standard Safe ownership management functionality.
## Liveness checking methodology
This is achieved using two types of contracts which the Safe contract has built-in support for:
1.
**Guard contracts:**
can execute pre- and post- transaction checks.
1.
**Module contracts:**
a contract which is added to the Safe by the signers, and thenceforth is
authorized to execute transactions via the Safe. This means the module must properly implement
auth conditions internally.
### The liveness guard
For implementing liveness checks a
`LivenessGuard`
is created which receives the signatures from
each executed transaction, and tracks the latest time at which a transaction was signed by each
signer. This time is made publicly available by calling a
`lastLive(address)(Timestamp)`
method.
Signers may also call the contract's
`showLiveness()()`
method directly in order to prove liveness.
### The liveness module
A
`LivenessModule`
is also created which does the following:
1.
Has a function
`removeOwners()`
that anyone may call to specify one or more owners to be removed from the
Safe.
1.
The Module would then check the
`LivenessGuard.lastLive()`
to determine if the signer is
eligible for removal.
1.
If so, it will call the Safe's
`removeSigner()`
to remove the non-live signer, and if necessary
reduce the threshold.
1.
When a member is removed, the signing parameters are modified such that
`M/N`
is the lowest ratio
which remains greater than or equal to 75%. Using integer math, this can be expressed as
`M = (N * 75 + 99) / 100`
.
### Owner removal call flow
The following diagram illustrates the flow for removing a single owner. The
`verifyFinalState`
box indicates calls to the Safe which ensure the final state is valid.
```
mermaid
sequenceDiagram
participant User
participant LivenessModule
participant LivenessGuard
participant Safe
User->>LivenessModule: removeOwners([previousOwner], [owner])
LivenessModule->>LivenessGuard: lastLive(owner)
LivenessModule->>Safe: getOwners()
LivenessModule->>Safe: removeOwner(previousOwner, owner)
alt verifyFinalState
LivenessModule->>Safe: getOwners()
LivenessModule->>Safe: getThreshold()
LivenessModule->>Safe: getGuard()
end
```
### Shutdown
In the unlikely event that the signer set (
`N`
) is reduced below the allowed threshold, then (and only then) is a
shutdown mechanism activated which removes the existing signers, and hands control of the
multisig over to a predetermined entity.
### Security Properties
The following security properties must be upheld:
1.
Signatures are assigned to the correct signer.
1.
Non-signers are unable to create a record of having signed.
1.
A signer cannot be censored or griefed such that their signing is not recorded.
1.
Signers may demonstrate liveness either by signing a transaction or by calling directly to the
guard.
1.
The module only removes a signer if they have demonstrated liveness during the interval, or
if necessary to convert the safe to a 1 of 1.
1.
The module sets the correct 75% threshold upon removing a signer.
1.
During a shutdown the module correctly removes all signers, and converts the safe to a 1 of 1.
1.
It must be impossible for the guard's checkTransaction or checkAfterExecution to permanently
revert given any calldata and the current state.
Note: neither the module nor guard attempt to prevent a quorum of owners from removing either the liveness
module or guard. There are legitimate reasons they might wish to do so. Moreover, if such a quorum
of owners exists, there is no benefit to removing them, as they are defacto 'sufficiently live'.
### Interdependency between the guard and module
The guard has no dependency on the module, and can be used independently to track liveness of
Safe owners.
This means that the module can be removed or replaced without any affect on the guard.
The module however does have a dependency on the guard; if the guard is removed from the Safe, then
the module will no longer be functional and calls to its
`removeOwners`
function will revert.
### Deploying the liveness checking system
[
deploying
]:
#deploying-the-liveness-checking-system
The module and guard are intended to be deployed and installed on the safe in the following
sequence:
1.
Deploy the guard contract
2.
The guard's constructor will read the Safe's owners and set a timestamp
1.
Deploy the module.
1.
Set the guard on the safe.
1.
Enable the module on the safe.
This order of operations is necessary to satisfy the constructor checks in the module, and is
intended to prevent owners from being immediately removable.
Note that changes to the owners set should not be made between the time the module is deployed, and
when it is enabled on the Safe, otherwise the checks made in the module's constructor may be
invalidated. If such changes are made, a new module should be deployed.
### Modify the liveness checking system
Changes to the liveness checking system should be done in the following manner:
#### Replacing the module
The module can safely be removed without affecting the operation of the guard. A new module can then
be added.
Note: none of the module's parameters are modifiable. In order to update the security properties
enforced by the module, it must be replaced.
#### Replacing the guard
The safe can only have one guard contract at a time, and if the guard is removed the module will
cease to function. This does not affect the ability of the Safe to operate normally, however the
module should be removed as a best practice.
If a new guard is added, eg. as a means of upgrading it, then a new module will also need to be
deployed and enabled. Once both the guard and module have been removed, they can be replaced
according to the steps in the
[
Deployment
][
deploying
]
section above.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment