Repository: boundless-xyz/boundless
Pull request #526: BM-779: Refactor task retry and enable configurable policy
Author: login: austinabell
Created: 2025-04-16T16:50:25Z | Merged: 2025-04-21T19:14:51Z

Closes BM-770
Closes BM-752

PR title and:
- Lowers the error of order stream failures to recoverable (including the initial connection such that any recoverable restarts don't fault the broker on restart if order stream down)
- Re-add dev mode defaulting to local prover removed in https://github.com/boundless-xyz/boundless/pull/452
  - Not sure if anything expects this to be removed, but localnet doesn't work as is as it defaults to using bento

This implementation will warn and backoff retries for reconnecting. Applies at least a small backoff to each retry, to avoid the spinning retries that happen now, which more easily lead to rate limiting and other issues. Tested manually that this handles no order stream on startup, disconnect after startup, reconnections on localnet, and reconnections to an order stream that returns an error on connect -- all of which warn log on retries but do not fault the service.


Diff:
diff --git a/broker.toml b/broker.toml
index e29a4021a9..4248035fcc 100644
--- a/broker.toml
+++ b/broker.toml
@@ -9,6 +9,7 @@ max_stake = "5" # HP
 skip_preflight_ids = []
 max_file_size = 50_000_000
 max_concurrent_locks = 2
+max_critical_task_retries = 10
 # max_fetch_retries = 2
 # allow_client_addresses = []
 # lockin_priority_gas = 100
diff --git a/crates/boundless-market/src/contracts/bytecode.rs b/crates/boundless-market/src/contracts/bytecode.rs
index 7a9a6897b9..055d832536 100644
--- a/crates/boundless-market/src/contracts/bytecode.rs
+++ b/crates/boundless-market/src/contracts/bytecode.rs
@@ -1,7 +1,7 @@
 // Auto-generated file, do not edit manually
 
 alloy::sol! {
-    #[sol(rpc, bytecode = "610100346101d557601f615fc938819003918201601f19168301916001600160401b038311848410176101d9578084926060946040528339810103126101d5578051906001600160a01b03821682036101d5576020810151604090910151916001600160a01b03831683036101d5573060805260a05260c05260e0527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c166101c6576002600160401b03196001600160401b0382160161015d575b604051615ddb90816101ee823960805181818161184701526118da015260a0518181816122d1015281816131dd0152818161332c015281816134c301528181613861015281816139950152613a3d015260c051818181610d72015281816110dd0152818161338401526138ba015260e0518181816113060152818161144c015281816117ab01528181611c520152818161210d0152614b4d0152f35b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f6100c1565b63f92ee8a960e01b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe6080806040526004361015610012575f80fd5b5f905f3560e01c90816308c84e70146122bf575080630cdedb5a146122385780631704f60f146121b657806317e828c4146121a457806325d5971f1461206d5780632abff1f214611f625780632e1a7d4d14611f445780633336f89914611f29578063380f9c3814611ee25780633b5c226614611e9e57806341451f9414611ded57806345bc4d1014611a845780634f1ef2861461189b57806352d1902d1461183457806353182c6714611819578063553c0248146117fd5780635b07fdd8146117da5780635fbb49211461179557806360dfd4a9146116fd578063635556241461163957806370a08231146115f6578063715018a614611577578063775045cb1461155a57806379ba50971461150d5780638040fdc0146113a45780638094e614146112e057806381bf6c241461129757806384b0196e1461116f5780638da5cb5b1461113a578063956b09601461111d5780639f04f420146111005780639fe9428c146110c5578063ad3cb1cc1461107c578063ae44494514611064578063ae7330f114610fbb578063b4206dd214610f7c578063c515c15f14610ef7578063c7c9636f14610ea2578063cb09e7c014610e5c578063cb74db1114610e33578063cb82cc8f14610e15578063cdc9712314610d1f578063cfbebd8b14610a19578063cfc0106e14610a01578063d0e30db0146109ea578063d7697087146109cf578063e30c39781461099a578063efff978514610960578063f2800f1a14610909578063f2fde38b14610883578063f399e22e146102ae578063fb4ccf90146102835763ffa1ad7414610265575f80fd5b34610280578060031936011261028057602060405160018152f35b80fd5b5034610280576102aa61029e61029836612788565b91613c12565b6040519182918261243a565b0390f35b5034610280576040366003190112610280576102c8612300565b906024356001600160401b03811161087f576102e890369060040161232a565b90925f80516020615d6f833981519152549060ff8260401c1615916001600160401b03811680159081610877575b600114908161086d575b159081610864575b506108555767ffffffffffffffff1981166001175f80516020615d6f8339815191525582610829575b5061035a615991565b610362615991565b6001600160a01b038116156108155761037a90614ab2565b610382615991565b6040918251610391848261265c565b601081526f12509bdd5b991b195cdcd3585c9ad95d60821b60208201528351906103bb858361265c565b60018252603160f81b60208301526103d1615991565b6103d9615991565b8051906001600160401b038211610801576104015f80516020615caf83398151915254612b79565b601f8111610792575b50602090601f83116001146107165761043a929188918361060c575b50508160011b915f199060031b1c19161790565b5f80516020615caf833981519152555b8051906001600160401b038211610702576104725f80516020615cef83398151915254612b79565b601f8111610693575b50602090601f8311600114610617576104aa929187918361060c5750508160011b915f199060031b1c19161790565b5f80516020615cef833981519152555b835f80516020615d0f83398151915255835f80516020615d8f833981519152556001600160401b0381116105f8576104fc816104f7600254612b79565b612bb1565b83601f8211600114610589578190859661052b9495969261057e5750508160011b915f199060031b1c19161790565b6002555b610537575080f35b5f80516020615d6f833981519152805460ff60401b1916905551600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a180f35b013590505f80610426565b60028552601f198216955f80516020615c8f83398151915291865b8881106105e0575083600195969798106105c7575b505050811b0160025561052f565b01355f19600384901b60f8161c191690555f80806105b9565b909260206001819286860135815501940191016105a4565b634e487b7160e01b84526041600452602484fd5b015190505f80610426565b5f80516020615cef83398151915287528187209190601f198416885b81811061067b5750908460019594939210610663575b505050811b015f80516020615cef833981519152556104ba565b01515f1960f88460031b161c191690555f8080610649565b92936020600181928786015181550195019301610633565b5f80516020615cef83398151915287527f5f9ce34815f8e11431c7bb75a8e6886a91478f7ffc1dbb0a98dc240fddd76b75601f840160051c810191602085106106f8575b601f0160051c01905b8181106106ed575061047b565b8781556001016106e0565b90915081906106d7565b634e487b7160e01b86526041600452602486fd5b5f80516020615caf83398151915288528188209190601f198416895b81811061077a5750908460019594939210610762575b505050811b015f80516020615caf8339815191525561044a565b01515f1960f88460031b161c191690555f8080610748565b92936020600181928786015181550195019301610732565b5f80516020615caf83398151915288527f42ad5d3e1f2e6e70edcf6d991b8a3023d3fca8047a131592f9edb9fd9b89d57d601f840160051c810191602085106107f7575b601f0160051c01905b8181106107ec575061040a565b8881556001016107df565b90915081906107d6565b634e487b7160e01b87526041600452602487fd5b631e4fbdf760e01b84526004849052602484fd5b68ffffffffffffffffff191668010000000000000001175f80516020615d6f833981519152555f610351565b63f92ee8a960e01b8552600485fd5b9050155f610328565b303b159150610320565b849150610316565b5080fd5b50346102805760203660031901126102805761089d612300565b6108a56146a0565b5f80516020615daf83398151915280546001600160a01b0319166001600160a01b039283169081179091555f80516020615ccf833981519152549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b5034610280576020366003190112610280576004359061092882613559565b1561094e576040816020936001600160401b039352808452205460a01c16604051908152f35b60249163d2be005d60e01b8252600452fd5b5034610280576102aa610986610981610978366126ec565b94929093612a7e565b612e4e565b604051918291602083526020830190612416565b50346102805780600319360112610280575f80516020615daf833981519152546040516001600160a01b039091168152602090f35b5034610280576102aa61029e6109e436612788565b91613c06565b5080600319360112610280576109fe613b9e565b80f35b5034610280576109fe610a1336612788565b91613752565b5034610280576060366003190112610280576004356001600160401b03811161087f576101608160040191600319903603011261087f576024356001600160401b038111610d1b57610a6f90369060040161232a565b916044356001600160401b038111610d1757610a8f90369060040161232a565b82359391610a9c856149ca565b939096610ab1610aac36886128cf565b61401e565b91610ac383610abe615930565b6153fe565b97600160c01b1615610cd557604051630b135d3f60e11b81529160209183918291610af391908c600485016127fd565b03816001600160a01b038c165afa908115610cca578991610c9b575b506001600160e01b0319166374eca2c160e11b01610c8c575b604051610b3660608261265c565b60218152602081017f4c6f636b526571756573742850726f6f66526571756573742072657175657374815260408201602960f81b9052610b74613e0b565b90610b7d613e55565b610b85613e9a565b610b8d613f54565b8d610b96613d84565b92610b9f613fa1565b94604051978897602089019a5180918c5e880160208101918583528051926020849201905e0160200183815281516020819301825e0182815281516020819301825e0190815281516020819301825e018d815281516020819301825e018c815281516020819301825e018b815203601f1981018252610c1e908261265c565b519020906040519060208201928352604082015260408152610c4160608261265c565b519020610c4c615930565b90610c56916153fe565b913690610c6292612698565b610c6b916159bc565b610c77919392936159f6565b610c8083614497565b946109fe969194614f4b565b638baa579f60e01b8852600488fd5b610cbd915060203d602011610cc3575b610cb5818361265c565b810190614399565b5f610b0f565b503d610cab565b6040513d8b823e3d90fd5b610ce7610ced91610cf6933691612698565b886159bc565b909291926159f6565b6001600160a01b03888116911614610b2857638baa579f60e01b8852600488fd5b8480fd5b8280fd5b5034610280578060031936011261028057604051908060025490610d4282612b79565b8085529160018116908115610dee5750600114610da4575b6102aa84610d6a8186038261265c565b6040519182917f00000000000000000000000000000000000000000000000000000000000000008352604060208401526040830190612416565b600281525f80516020615c8f833981519152939250905b808210610dd457509091508101602001610d6a82610d5a565b919260018160209254838588010152019101909291610dbb565b60ff191660208087019190915292151560051b85019092019250610d6a9150839050610d5a565b5034610280576020366003190112610280576109fe60043533614b1d565b5034610280576020366003190112610280576020610e52600435613559565b6040519015158152f35b5034610280576020366003190112610280576020906001600160601b03906040906001600160a01b03610e8d612300565b16815260018452205460601c16604051908152f35b503461028057610eb136612543565b96959392919490955b818110610ecf576102aa61029e898989613c06565b80610ef1610ee06001938589612dc4565b610eeb838789612de7565b91612a7e565b01610eba565b503461028057602036600319011261028057604060e091600435815280602052208054906001600160601b0360026001830154920154916040519360018060a01b03811685526001600160401b038160a01c16602086015262ffffff81871c16604086015260f81c6060850152818116608085015260601c1660a083015260c0820152f35b5034610280576109fe610f8e36612499565b9091610fa7610f9d82356149ca565b93909485846143b9565b91610fb182614497565b9490933393614f4b565b50346102805760603660031901126102805780610fd6612300565b6044356001600160401b03811161106057610ff590369060040161232a565b6001600160a01b0390921691823b1561105b5761102e92849283604051809681958294636691f64760e01b8452602435600485016127fd565b03925af180156110505761103f5750f35b816110499161265c565b6102805780f35b6040513d84823e3d90fd5b505050fd5b5050fd5b5034610280576109fe611076366124ec565b9061314f565b5034610280578060031936011261028057506102aa60405161109f60408261265c565b60058152640352e302e360dc1b6020820152604051918291602083526020830190612416565b503461028057806003193601126102805760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610280578060031936011261028057602060405161c3508152f35b50346102805780600319360112610280576020604051611d4c8152f35b50346102805780600319360112610280575f80516020615ccf833981519152546040516001600160a01b039091168152602090f35b50346102805780600319360112610280575f80516020615d0f833981519152541580611281575b15611244576111e8906111a7613586565b906111b0613653565b9060206111f6604051936111c4838661265c565b8385525f368137604051968796600f60f81b885260e08589015260e0880190612416565b908682036040880152612416565b904660608601523060808601528260a086015284820360c08601528080855193848152019401925b82811061122d57505050500390f35b83518552869550938101939281019260010161121e565b60405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b6044820152606490fd5b505f80516020615d8f8339815191525415611196565b5034610280576020366003190112610280576112d460209160406112bc6004356149ca565b6001600160a01b039091168352600185529120614a04565b90506040519015158152f35b50346102805760a0366003190112610280576004358160443560ff811680910361087f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690813b15610d1b57829160e48392604051948593849263d505accf60e01b84523360048501523060248501528960448501526024356064850152608484015260643560a484015260843560c48401525af161138f575b506109fe8233614b1d565b816113999161265c565b61087f57815f611384565b5034610280576020366003190112610280576004356113c16146a0565b30825260016020526001600160601b03604083205460601c166001600160601b036113eb8361466f565b16116114fa576114216113fd8261466f565b30845260016020526001600160601b03604085209181835460601c16031690612b2e565b60405163a9059cbb60e01b815233600482015260248101829052602081604481866001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156114ef5783916114c0575b50156114b1576040519081527ff0ed97f7b968f9d8268bc8d104a11b3586ceeadd0e0af5f73769e2b479f9d0ae60203092a280f35b6312171d8360e31b8252600482fd5b6114e2915060203d6020116114e8575b6114da818361265c565b810190612b61565b5f61147c565b503d6114d0565b6040513d85823e3d90fd5b63112fed8b60e31b825230600452602482fd5b50346102805780600319360112610280575f80516020615daf83398151915254336001600160a01b0390911603611547576109fe33614ab2565b63118cdaa760e01b815233600452602490fd5b5034610280576102aa610986611572610978366126ec565b612cdd565b50346102805780600319360112610280576115906146a0565b5f80516020615daf83398151915280546001600160a01b03199081169091555f80516020615ccf8339815191528054918216905581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5034610280576020366003190112610280576020906001600160601b03906040906001600160a01b03611627612300565b16815260018452205416604051908152f35b5034610280576020366003190112610280576004356116566146a0565b30825260016020526001600160601b036040832054166001600160601b0361167d8361466f565b16116114fa5761168c8161466f565b30835260016020526001600160601b03806040852092818454160316166001600160601b03198254161790558180808084335af16116c8612ea2565b50156114b1576040519081527f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b6560203092a280f35b503461028057602036600319011261028057600460606040602093833581528085522060026040519161172f836125dc565b805460018060a01b03811684526001600160401b038160a01c168785015262ffffff8160e01c16604085015260f81c848401526001600160601b0360018201548181166080860152851c1660a0840152015460c082015201511615156040519015158152f35b50346102805780600319360112610280576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461028057806003193601126102805760206117f5615930565b604051908152f35b5034610280578060031936011261028057602090604051908152f35b5034610280576102aa61098661182e366124ec565b90612e4e565b50346102805780600319360112610280577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361188c5760206040515f80516020615d2f8339815191528152f35b63703e46dd60e11b8152600490fd5b506040366003190112610280576118b0612300565b906024356001600160401b03811161087f576118d09036906004016126ce565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016308114908115611a62575b50611a53576119126146a0565b6040516352d1902d60e01b8152926001600160a01b0381169190602085600481865afa80958596611a1f575b5061195757634c9c8ce360e01b84526004839052602484fd5b9091845f80516020615d2f8339815191528103611a0d5750813b156119fb575f80516020615d2f83398151915280546001600160a01b031916821790557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8480a281518390156119e157808360206119dd95519101845af46119d7612ea2565b91615c30565b5080f35b505050346119ec5780f35b63b398979f60e01b8152600490fd5b634c9c8ce360e01b8452600452602483fd5b632a87526960e21b8552600452602484fd5b9095506020813d602011611a4b575b81611a3b6020938361265c565b81010312610d175751945f61193e565b3d9150611a2e565b63703e46dd60e11b8252600482fd5b5f80516020615d2f833981519152546001600160a01b0316141590505f611905565b503461028057602036600319011261028057600435611ac5611aa5826149ca565b6001600160a01b0390911680855260016020526040852090929190614a04565b5015611dd95781835282602052604083209060405191611ae4836125dc565b805460018060a01b03811684526001600160401b038160a01c16602085015262ffffff8160e01c16604085015260f81c60608401526001810154600260808501926001600160601b03831684526001600160601b0360a087019360601c168352015460c08501526004606085015116611dc5576001606085015116611db1576001600160401b03611b74856149a8565b16421115611d885784865260208690526040862080546001600160f81b03811660f891821c60041790911b6001600160f81b031916178155869060029082600182015501556001600160601b03815116611d4c810290808204611d4c1490151715611d7457611bf96001600160601b03949392612710611bfe93049586915116612e21565b61466f565b916002606060018060a01b038751169601511615155f14611d1057505060018060a01b03831685526001602052611c4f60408620611c49836001600160601b03835460601c16612e2e565b90612b2e565b847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561087f57818091602460405180948193630852cd8d60e31b83528960048401525af1801561105057611cf7575b5050907f79ca7c80cf57b513ffdf8aa37ec70e40757f5e0d35219241860bb4b4c2fa7616926001600160601b0360609360405193845216602083015260018060a01b03166040820152a280f35b81611d049194939461265c565b610d175790845f611caa565b9093506001600160601b0330943088526001602052611d3c60408920611c498685835460601c16612e2e565b511690865260016020526001600160601b03611d5f604088209282845416612e2e565b166001600160601b0319825416179055611c4f565b634e487b7160e01b87526011600452602487fd5b6044866001600160401b0387611d9d886149a8565b9063079c66ab60e41b845260045216602452fd5b631cfdeebb60e01b86526004859052602486fd5b633231064d60e11b86526004859052602486fd5b63d2be005d60e01b83526004829052602483fd5b50346102805760203660031901126102805760043590611e0c82613559565b1561094e57604081602093611e8d935280845220600260405191611e2f836125dc565b805460018060a01b03811684526001600160401b038160a01c168685015262ffffff8160e01c16604085015260f81c60608401526001600160601b036001820154818116608086015260601c1660a0840152015460c08201526149a8565b6001600160401b0360405191168152f35b503461028057611ead36612543565b96959392919490955b818110611ecb576102aa61029e898989613c12565b80611edc610ee06001938589612dc4565b01611eb6565b50611eec36612499565b505034611f1c575b357f7fab7e8a635b9e4d20f8afff898bb2016ab093457ea8adc210f90fdbec6d8dfb8280a280f35b611f24613b9e565b611ef4565b5034610280576102aa610986611f3e366124ec565b90612cdd565b5034610280576020366003190112610280576109fe600435336146d3565b5034610280576020366003190112610280576004356001600160401b03811161087f57611f9390369060040161232a565b611f9e9291926146a0565b6001600160401b03811161205957611fbb816104f7600254612b79565b81601f8211600114611fee5781908394611fe8949261057e5750508160011b915f199060031b1c19161790565b60025580f35b60028352601f198216935f80516020615c8f83398151915291845b8681106120415750836001959610612028575b505050811b0160025580f35b01355f19600384901b60f8161c191690555f808061201c565b90926020600181928686013581550194019101612009565b634e487b7160e01b82526041600452602482fd5b50346102805760203660031901126102805760043533825260016020526001600160601b03604083205460601c166001600160601b036120ac8361466f565b1611612191576120e26120be8261466f565b33845260016020526001600160601b03604085209181835460601c16031690612b2e565b60405163a9059cbb60e01b815233600482015260248101829052602081604481866001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156114ef578391612172575b50156114b1576040519081527ff0ed97f7b968f9d8268bc8d104a11b3586ceeadd0e0af5f73769e2b479f9d0ae60203392a280f35b61218b915060203d6020116114e8576114da818361265c565b5f61213d565b63112fed8b60e31b825233600452602482fd5b5034610280576109fe610eeb36612499565b5034610280576121c536612387565b969095919490936001600160a01b039092169190823b15610d175791612206939185809460405196879586948593636691f64760e01b8552600485016127fd565b03925af1801561105057612223575b6102aa61029e868686613c06565b61222e82809261265c565b6102805780612215565b346122bb5761224636612387565b93959194909290916001600160a01b0316803b156122bb57612282965f8094604051998a9586948593636691f64760e01b8552600485016127fd565b03925af19283156122b0576102aa9461029e946122a0575b50613c12565b5f6122aa9161265c565b5f61229a565b6040513d5f823e3d90fd5b5f80fd5b346122bb575f3660031901126122bb577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b600435906001600160a01b03821682036122bb57565b35906001600160a01b03821682036122bb57565b9181601f840112156122bb578235916001600160401b0383116122bb57602083818601950101116122bb57565b9181601f840112156122bb578235916001600160401b0383116122bb576020808501948460051b0101116122bb57565b60a06003198201126122bb576004356001600160a01b03811681036122bb5791602435916044356001600160401b0381116122bb57816123c99160040161232a565b929092916064356001600160401b0381116122bb57816123eb91600401612357565b92909291608435906001600160401b0382116122bb5760809082900360031901126122bb5760040190565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b602081016020825282518091526040820191602060408360051b8301019401925f915b83831061246c57505050505090565b909192939460208061248a600193603f198682030187528951612416565b9701930193019193929061245d565b9060406003198301126122bb576004356001600160401b0381116122bb5761016081840360031901126122bb5760040191602435906001600160401b0382116122bb576124e89160040161232a565b9091565b9060406003198301126122bb576004356001600160401b0381116122bb5760a081840360031901126122bb5760040191602435906001600160401b0382116122bb5760809082900360031901126122bb5760040190565b60806003198201126122bb576004356001600160401b0381116122bb578161256d91600401612357565b929092916024356001600160401b0381116122bb578161258f91600401612357565b929092916044356001600160401b0381116122bb57816125b191600401612357565b92909291606435906001600160401b0382116122bb5760809082900360031901126122bb5760040190565b60e081019081106001600160401b038211176125f757604052565b634e487b7160e01b5f52604160045260245ffd5b60a081019081106001600160401b038211176125f757604052565b608081019081106001600160401b038211176125f757604052565b604081019081106001600160401b038211176125f757604052565b90601f801991011681019081106001600160401b038211176125f757604052565b6001600160401b0381116125f757601f01601f191660200190565b9291926126a48261267d565b916126b2604051938461265c565b8294818452818301116122bb578281602093845f960137010152565b9080601f830112156122bb578160206126e993359101612698565b90565b60806003198201126122bb576004356001600160401b0381116122bb5761016081830360031901126122bb57600401916024356001600160401b0381116122bb578261273a9160040161232a565b929092916044356001600160401b0381116122bb5760a081840360031901126122bb5760040191606435906001600160401b0382116122bb5760809082900360031901126122bb5760040190565b60406003198201126122bb576004356001600160401b0381116122bb57816127b291600401612357565b92909291602435906001600160401b0382116122bb5760809082900360031901126122bb5760040190565b908060209392818452848401375f828201840152601f01601f1916010190565b6040906126e99492815281602082015201916127dd565b35906001600160601b03821682036122bb57565b35906001600160e01b0319821682036122bb57565b359063ffffffff821682036122bb57565b91908260e09103126122bb57604051612866816125dc565b8092803582526020810135602083015260408101356001600160401b03811681036122bb5760c091829160408501526128a16060820161283d565b60608501526128b26080820161283d565b60808501526128c360a0820161283d565b60a08501520135910152565b9190610160838203126122bb57604051906128e98261260b565b81938035835260208101356001600160401b0381116122bb5781018083039060a082126122bb57604080519261291e84612626565b82358452601f1901126122bb5760405161293781612641565b61294360208301612316565b815261295160408301612814565b6020820152602083015260608101356001600160401b0381116122bb5781016040818603126122bb576040519161298783612641565b813560028110156122bb5783526020820135926001600160401b0384116122bb576129b9876129c995608095016126ce565b6020820152604085015201612828565b6060820152602084015260408101356001600160401b0381116122bb57810182601f820112156122bb5782816020612a0393359101612698565b604084015260608101356001600160401b0381116122bb578101916040838203126122bb5760405192612a3584612641565b803560028110156122bb5784526020810135926001600160401b0384116122bb57608094612a6984612a79968895016126ce565b602082015260608701520161284e565b910152565b91823590600160c01b821615612b0257602092612ad992611bf992612ac992612ab292871c6001600160a01b0316886143b9565b945b612abd81614497565b5050608036910161284e565b6001600160401b0342169061458b565b6001600160601b0360405191612aee83612641565b600183521691018190526001607f1b17905d565b5050506020612ad9611bf9612ac9612b28612b20610aac36886128cf565b610abe615930565b94612ab4565b80546bffffffffffffffffffffffff60601b191660609290921b6bffffffffffffffffffffffff60601b16919091179055565b908160209103126122bb575180151581036122bb5790565b90600182811c92168015612ba7575b6020831014612b9357565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612b88565b601f8111612bbd575050565b60025f5260205f20906020601f840160051c83019310612bf7575b601f0160051c01905b818110612bec575050565b5f8155600101612be1565b9091508190612bd8565b356001600160a01b03811681036122bb5790565b903590601e19813603018212156122bb57018035906001600160401b0382116122bb576020019160608202360383136122bb57565b359061ffff821682036122bb57565b91908260609103126122bb57604051606081018181106001600160401b038211176125f7576040526040612a79818395612c9281612c4a565b8552612ca060208201612316565b602086015201612814565b903590601e19813603018212156122bb57018035906001600160401b0382116122bb576020019181360383136122bb57565b9190612ce9818461314f565b612cfe612cf860608301612c01565b846147a5565b92803591827f4321394035f9f33b5a0c036d91d311549f949cdfc2a4fe70bd3745115b248da85f80a260208101612d358183612c15565b9050612d42575b50505050565b612d4b91612c15565b91909115612db057612da792612d646040933690612c59565b6001600160601b038460018060a01b036020840151169201511691612d8c6060850185612cab565b939092612d9c6080870187612cab565b9790960135926148ce565b5f808080612d3c565b634e487b7160e01b5f52603260045260245ffd5b9190811015612db05760051b8101359061015e19813603018212156122bb570190565b90821015612db0576124e89160051b810190612cab565b601f19810191908211612e0d57565b634e487b7160e01b5f52601160045260245ffd5b91908203918211612e0d57565b906001600160601b03809116911601906001600160601b038211612e0d57565b612e5d82606092949394612cdd565b92016001600160a01b03612e7082612c01565b165f5260016020526001600160601b0360405f20541680612e8f575050565b612e9b612ea092612c01565b6146d3565b565b3d15612ecc573d90612eb38261267d565b91612ec1604051938461265c565b82523d5f602084013e565b606090565b6001600160401b0381116125f75760051b60200190565b903590601e19813603018212156122bb57018035906001600160401b0382116122bb57602001918160061b360383136122bb57565b6020815260406020612f39845183838601526060850190612416565b93015191015290565b90929192612f4f81612ed1565b93612f5d604051958661265c565b60606020868481520192028301928184116122bb57915b838310612f815750505050565b6020606091612f908486612c59565b815201920191612f74565b929192612fa782612ed1565b93612fb5604051958661265c565b602085848152019260061b8201918183116122bb57925b828410612fd95750505050565b6040848303126122bb5760206040918251612ff381612641565b612ffc87612c4a565b8152613009838801612828565b83820152815201930192612fcc565b6020815260a0810191805192608060208401528351809152602060c084019401905f5b8181106130c157505050602081810151838503601f190160408501528051808652948201949101905f5b81811061309157505050604081015160608381019190915201516001600160a01b031660809091015290565b8251805161ffff1687526020908101516001600160e01b0319168188015260409096019590920191600101613065565b8251805161ffff1687526020818101516001600160a01b0316818901526040918201516001600160601b0316918801919091526060909601959092019160010161303b565b9190811015612db05760061b0190565b356001600160e01b0319811681036122bb5790565b9061314590604093969594966060845260608401916127dd565b9460208201520152565b5f9160205f6131616060850185612cab565b908160405192839283378101838152039060025afa156122b05761319261318d5f516040850135614c4f565b614d77565b916131c16040516131a281612626565b5f81528235602082015260208301356040820152846060820152614e68565b60408301936131d08585612ee8565b1590506134bd57613229907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906132136080860186612cab565b93906040519461322286612641565b3691612698565b83526020830152803b15613485576132589187916040518080958194631599ead560e01b835260048301612f1d565b03915afa80156134b25790869161349d575b506020915b6132798686612ee8565b90916132ba61328a86890189612c15565b9490936132b161329c60608c01612c01565b95604051976132aa89612626565b3691612f42565b86523691612f9b565b85840152604083015260018060a01b031660608201526040516132f2816132e48682019485613018565b03601f19810183528261265c565b604051918291518091835e8101838152039060025afa156114ef5783519261331a8184612ee8565b905015158061343f575b6133d15750507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169061335f9080612cab565b823b15610d175760405163ab750e7560e01b815293859385939092849283926133ad927f0000000000000000000000000000000000000000000000000000000000000000916004860161312b565b03915afa8015611050576133bf575050565b6133ca82809261265c565b6102805750565b6133dc859184612ee8565b1561342b576133f060206133fb9201613116565b926080810190612cab565b60049391931161087f57632e2ce35360e21b82526001600160e01b03199081166004529135909116602452604490fd5b634e487b7160e01b82526032600452602482fd5b5061344a8184612ee8565b1561348957602061345b9101613116565b6134686080840184612cab565b60041161348557356001600160e01b031990811691161415613324565b8680fd5b634e487b7160e01b86526032600452602486fd5b816134a79161265c565b610d1757845f61326a565b6040513d88823e3d90fd5b6134f9907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906132136080860186612cab565b83526020830152803b156122bb57613528915f916040518080958194631599ead560e01b835260048301612f1d565b039161c350fa80156122b057613543575b508460209161326f565b6135509195505f9061265c565b5f936020613539565b613565613582916149ca565b6001600160a01b039091165f908152600160205260409020614a04565b5090565b604051905f825f80516020615caf83398151915254916135a583612b79565b808352926001811690811561363457506001146135c9575b612ea09250038361265c565b505f80516020615caf8339815191525f90815290917f42ad5d3e1f2e6e70edcf6d991b8a3023d3fca8047a131592f9edb9fd9b89d57d5b818310613618575050906020612ea0928201016135bd565b6020919350806001915483858901015201910190918492613600565b60209250612ea094915060ff191682840152151560051b8201016135bd565b604051905f825f80516020615cef833981519152549161367283612b79565b8083529260018116908115613634575060011461369557612ea09250038361265c565b505f80516020615cef8339815191525f90815290917f5f9ce34815f8e11431c7bb75a8e6886a91478f7ffc1dbb0a98dc240fddd76b755b8183106136e4575050906020612ea0928201016135bd565b60209193508060019154838589010152019101909184926136cc565b3561ffff811681036122bb5790565b9190811015612db05760051b81013590609e19813603018212156122bb570190565b805115612db05760200190565b8051821015612db05760209160051b010190565b61ffff8211613b855761376482612ed1565b90613772604051928361265c565b828252601f1961378184612ed1565b0136602084013761379183612ed1565b61379e604051918261265c565b838152601f196137ad85612ed1565b0136602083013760408501936137c38587612ee8565b90505f5b8787838310613acc57505050505f5b8181106138fe57505050506138096020926137f15f936152f7565b61381861380086880188612c15565b94909388612ee8565b6132b161329c60608b01612c01565b85840152604083015260018060a01b03166060820152604051613842816132e48682019485613018565b604051918291518091835e8101838152039060025afa156122b0575f517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316916138949080612cab565b919092803b156122bb576138e3935f936040519586948593849363ab750e7560e01b85527f0000000000000000000000000000000000000000000000000000000000000000916004860161312b565b03915afa80156122b0576138f45750565b5f612ea09161265c565b61390981838661370f565b9060205f61391a6060850185612cab565b908160405192839283378101838152039060025afa156122b05761394661318d5f516040850135614c4f565b9161397560405161395681612626565b8381528235602082015260208301356040820152846060820152614e68565b61397f838961373e565b5261398a828661373e565b51613a37576139db927f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316916139cc906080810190612cab565b94906040519561322287612641565b84526020840152803b156122bb57613a0a925f916040518080968194631599ead560e01b835260048301612f1d565b039161c350fa9182156122b057600192613a27575b505b016137d6565b5f613a319161265c565b5f613a1f565b613a74927f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316916139cc906080810190612cab565b84526020840152803b156122bb57613aa3925f916040518080968194631599ead560e01b835260048301612f1d565b03915afa9182156122b057600192613abc575b50613a21565b5f613ac69161265c565b5f613ab6565b613b1261ffff613b0a613b0586613af386613aff6020613af985613af3613b1c9c8e612ee8565b90613106565b01613116565b98612ee8565b613700565b16868961370f565b6080810190612cab565b6004929192116122bb576001613b5461ffff613b4d613b05878f978f613af39163ffffffff60e01b90351699612ee8565b168861373e565b526001600160e01b031916818103613b705750506001016137c7565b632e2ce35360e21b5f5260045260245260445ffd5b506377e4aa5360e11b5f5260045261ffff60245260445ffd5b613ba73461466f565b335f5260016020526001600160601b03613bc860405f209282845416612e2e565b166001600160601b03198254161790556040513481527fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c60203392a2565b82606092612e5d929594955b9291613c1f818386613752565b613c2882612ed1565b93613c36604051958661265c565b828552601f19613c4584612ed1565b015f5b818110613d73575050845f5b848110613d0457505060208201613c6b8184612c15565b9390505f5b848110613c7f57505050505050565b613c898383612c15565b909190811015612db057613cfe613ca860019360608402013690612c59565b613cb861ffff8251168a8961370f565b906001600160601b036040868060a01b036020840151169201511691613ce16060820182612cab565b91613cef6080820182612cab565b959094604083013592356148ce565b01613c70565b80613d27613d15600193888761370f565b613d2160608801612c01565b906147a5565b613d31828561373e565b52613d3c818461373e565b50613d4881878661370f565b357f4321394035f9f33b5a0c036d91d311549f949cdfc2a4fe70bd3745115b248da85f80a201613c54565b806060602080938a01015201613c48565b60405190613d9360808361265c565b605a82527f6c2c496e70757420696e7075742c4f66666572206f66666572290000000000006060837f50726f6f66526571756573742875696e743235362069642c526571756972656d60208201527f656e747320726571756972656d656e74732c737472696e6720696d616765557260408201520152565b60405190613e1a60608361265c565b60268252654c696d69742960d01b6040837f43616c6c6261636b286164647265737320616464722c75696e7439362067617360208201520152565b60405190613e6460608361265c565b60218252602960f81b6040837f496e7075742875696e743820696e707574547970652c6279746573206461746160208201520152565b60405190613ea960c08361265c565b6084825263616b652960e01b60a0837f4f666665722875696e74323536206d696e50726963652c75696e74323536206d60208201527f617850726963652c75696e7436342062696464696e6753746172742c75696e7460408201527f33322072616d705570506572696f642c75696e743332206c6f636b54696d656f60608201527f75742c75696e7433322074696d656f75742c75696e74323536206c6f636b537460808201520152565b60405190613f6360608361265c565b602982526874657320646174612960b81b6040837f5072656469636174652875696e743820707265646963617465547970652c627960208201520152565b60405190613fb060808361265c565b605382527274652c6279746573342073656c6563746f722960681b6060837f526571756972656d656e7473286279746573333220696d61676549642c43616c60208201527f6c6261636b2063616c6c6261636b2c507265646963617465207072656469636160408201520152565b614026613d84565b61402e613e0b565b614036613e55565b9061403f613e9a565b614047613f54565b61404f613fa1565b916040519485946020860197805160208192018a5e860160208101915f83528051926020849201905e016020015f815281516020819301825e015f815281516020819301825e015f815281516020819301825e015f815281516020819301825e015f815203601f19810182526140c5908261265c565b5190209080519060208101516140d9613fa1565b6140e1613e0b565b6140e9613f54565b90604051918291602083019480516020819201875e830160208101915f83528051926020849201905e016020015f815281516020819301825e015f815203601f1981018252614138908261265c565b51902090805190602081015161414c613e0b565b8051906020012090600160a01b6001900381511690602001516001600160601b03166040519160208301938452604083015260608201526060815261419260808261265c565b5190209060408101516141a3613f54565b80519060200120908051906141b7826153f4565b602001518051906020012060405191602083019384526141d6816153f4565b60408301526060820152606081526141ef60808261265c565b5190209063ffffffff60e01b90606001511691604051936020850195865260408501526060840152608083015260a082015260a0815261423060c08261265c565b51902090604081015180519060200120606082015161424d613e55565b8051906020012090805190614261826153f4565b60200151805190602001206040519160208301938452614280816153f4565b604083015260608201526060815261429960808261265c565b51902091608001516142a9613e9a565b60405180602081019280516020819201855e8101602081015f905203602001601f19810182526142d9908261265c565b5190209080519060208101519060408101516001600160401b0316606082015163ffffffff16608083015163ffffffff169160a084015163ffffffff169360c0015194604051966020880198895260408801526060870152608086015260a085015260c084015260e0830152610100820152610100815261435c6101208261265c565b51902092604051946020860196875260408601526060850152608084015260a083015260c082015260c0815261439360e08261265c565b51902090565b908160209103126122bb57516001600160e01b0319811681036122bb5790565b92916143cb612b20610aac36876128cf565b9335600160c01b161561446157916020916143fd93604051809581948293630b135d3f60e11b845289600485016127fd565b03916001600160a01b03165afa9081156122b0575f91614442575b506001600160e01b0319166374eca2c160e11b016144335790565b638baa579f60e01b5f5260045ffd5b61445b915060203d602011610cc357610cb5818361265c565b5f614418565b61447361447991614482943691612698565b846159bc565b909391936159f6565b6001600160a01b039081169116036144335790565b906144a5366080840161284e565b805160208201511061455c5763ffffffff606082015116608082019063ffffffff8251161061455c5763ffffffff90511660a082019063ffffffff8251161061455c576145119063ffffffff6001600160401b0360406145048661541b565b950151169151169061456b565b9262ffffff6001600160401b036145288487614f2b565b161161455c576001600160401b038416904282106145465750509190565b63873fd26b60e01b5f523560045260245260445ffd5b6341abc80160e01b5f5260045ffd5b906001600160401b03809116911601906001600160401b038211612e0d57565b9060408201906001600160401b0380835116911690811115614669576001600160401b036145b88461541b565b168111614662576001600160401b03825116906001600160401b036145e9606086019363ffffffff8551169061456b565b168111156145fb575050506020015190565b614628906001600160401b0363ffffffff61461c6020880151885190612e21565b94511694511690612e21565b925192818102918183041490151715612e0d57811561464e57048101809111612e0d5790565b634e487b7160e01b5f52601260045260245ffd5b5050505f90565b50505190565b6001600160601b038111614689576001600160601b031690565b6306dfcc6560e41b5f52606060045260245260445ffd5b5f80516020615ccf833981519152546001600160a01b031633036146c057565b63118cdaa760e01b5f523360045260245ffd5b9060018060a01b03821691825f5260016020526001600160601b0360405f2054166001600160601b036147058461466f565b1611614792575f808084819461471a8261466f565b88845260016020526001600160601b03806040862092818454160316166001600160601b03198254161790555af1614750612ea2565b50156147835760207f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b6591604051908152a2565b6312171d8360e31b5f5260045ffd5b8263112fed8b60e31b5f5260045260245ffd5b9081356147b1816149ca565b60018060a09493941b0383165f5260016020526147d18160405f20614a04565b9390156148c057825f525f60205260405f2092604051936147f1856125dc565b600281549160018060a01b03831687526001600160401b038360a01c169283602089015262ffffff8160e01c16604089015260f81c60608801526001600160601b03600182015481811660808a015260601c1660a0880152015460c08601524211155f146148ac576020614867970135936157d5565b905b815161487157565b7f210e4fd706e561df48472433bcc50b4589f2c13e784e9992f4c3e6de26eb356460405160208152806148a76020820186612416565b0390a1565b60206148ba970135936155aa565b90614869565b60206148ba9601359261543e565b966001600160a01b03909116959094909392863b156122bb57866001600160601b035f969261493888946149269a6040519b8c9a8b998a9663a12da43f60e01b885260048801526060602488015260648701916127dd565b848103600319016044860152916127dd565b039416f19081614998575b50614994577f5c5960582bfc7a494183b4e9a66bfe8ecffc07a83a48d136e732400f7b98bf5090614972612ea2565b9061498f6040519283928352604060208401526040830190612416565b0390a2565b5050565b5f6149a29161265c565b5f614943565b6126e99062ffffff60406001600160401b03602084015116920151169061456b565b906001600160c11b0319821661455c57602082901c6001600160a01b03169163ffffffff1690565b6302000000821015612db05701905f90565b63ffffffff821691906020831015614a56576401fffffffe905460c01c9160011b169180830460021490151715612e0d576001600160401b03906003831b1616901c9060026001831615159216151590565b91614a619150612dfe565b908160011b9180830460021481151715612e0d5760ff91614a919160071c6001600160f81b0316906001016149f2565b90549060031b1c9116906003821b16901c9060026001831615159216151590565b5f80516020615daf83398151915280546001600160a01b03199081169091555f80516020615ccf83398151915280549182166001600160a01b0393841690811790915591167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b6040516323b872dd60e01b81526001600160a01b03918216600482018190523060248301526044820184905292917f000000000000000000000000000000000000000000000000000000000000000016906020905f9060649082855af19081601f3d1160015f5114161516614c2a575b5015614bee57602081614be5614bc37f1da2c4060997c108162f55c30ad2268924b069210f8c686ba302e1acc6909ccc9461466f565b855f5260018452611c4960405f20916001600160601b03835460601c16612e2e565b604051908152a2565b60405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606490fd5b3b153d171590505f614b8d565b60405190614c4482612641565b5f6020838281520152565b905f6080604051614c5f8161260b565b828152826020820152604051614c7481612641565b8381528360208201526040820152826060820152015260405190614c9782612641565b5f82525f602083015260405190614cad82612641565b8152602081015f815260205f600c6040516b1c9a5cd8cc0b93dd5d1c1d5d60a21b815260025afa156122b0576020915f918251915190516040519185830193845260408301526060820152600160f91b608082015260628152614d1160828261265c565b604051918291518091835e8101838152039060025afa156122b0575f519060405192614d3c8461260b565b83527fa3acc27117418996340b84e5a90f3ef4c49d22c79e44aad822ec9c313e1eb8e2602084015260408301525f6060830152608082015290565b60205f60126040517172697363302e52656365697074436c61696d60701b815260025afa156122b0575f519060608101519181519260208301519360406080850151940193845151906003821015614e5457945160209081015160408051808401978852908101959095526060850193909352608084019690965260a08301949094526001600160f81b031960f894851b811660c0840152931b90921660c4830152600160fa1b60c883015260aa82525f91614e3460ca8261265c565b604051918291518091835e8101838152039060025afa156122b0575f5190565b634e487b7160e01b5f52602160045260245ffd5b6056604051614e7860808261265c565b81815275742c6279746573333220636c61696d4469676573742960501b606060208301927f4173736573736f72436f6d6d69746d656e742875696e7432353620696e64657884527f2c75696e743235362069642c62797465733332207265717565737444696765736040820152015220908051906020810151906060604082015191015191604051936020850195865260408501526060840152608083015260a082015260a0815261439360c08261265c565b906001600160401b03809116911603906001600160401b038211612e0d57565b959492939160018060a01b0316805f526001602052614f6d8560405f20614a04565b906152e3576152cf576001600160401b038416968742116152b757614f9b611bf9612ac9366080850161284e565b94825f52600160205260405f20976001600160601b03895416956001600160601b038816948588106152a5575060018060a01b031696875f52600160205260405f20906001600160601b03825460601c169761014086013580991061529257916001600160601b0380615040936150459796950316166001600160601b03198d5416178c556001600160601b036150318a61466f565b81835460601c16031690612b2e565b614f2b565b936001600160401b03851662ffffff811161527b5750916001600160601b0361515d9261514360ff6150796002989761466f565b92604051996150878b6125dc565b8b8b5260208b019e8f5262ffffff60408c019116815260608b01915f835260808c019788528660a08d019616865260c08c01998a52359e8f5f525f60205260405f209b60018060a01b039060018060a01b039051161660018060a01b03198d5416178c5551908b549062ffffff60e01b905160e01b16916001600160401b0360a01b9060a01b16906affffffffffffffffffffff60a01b191617178a555116889081549060ff60f81b9060f81b169060018060f81b0316179055565b818060018901945116168219845416178355511690612b2e565b5191015563ffffffff82169160208310156151ed576401fffffffe9060011b169180830460021490151715612e0d5782546001600160c01b038116600190931b6001600160401b031660c091821c17901b6001600160c01b031916919091179091557ffb1dd4383bc31d469e205e04236dbca09ae13ab0373414dccbe098a861ddef5590602090604051908152a2565b50906151f890612dfe565b908160011b9282840460021483151715612e0d577ffb1dd4383bc31d469e205e04236dbca09ae13ab0373414dccbe098a861ddef55936020936152769260ff916001916152539160071c6001600160f81b03169083016149f2565b929093161b82548260031b1c179082549060031b91821b915f19901b1916179055565b614be5565b6306dfcc6560e41b5f52601860045260245260445ffd5b8963112fed8b60e31b5f5260045260245ffd5b63112fed8b60e31b5f5260045260245ffd5b879063cfe6a8fd60e01b5f523560045260245260445ffd5b86631cfdeebb60e01b5f523560045260245ffd5b8763a905765160e01b5f523560045260245ffd5b80511561455c5760018151146153eb5780515b60018111615320575061531c90613731565b5190565b60018101808211612e0d5760011c905f5b8160011c811061537f575060018082161461534d575b5061530a565b5f198101908111612e0d57615362908361373e565b515f198201828111612e0d57615378908461373e565b525f615347565b600181901b906001600160ff1b0381168103612e0d5761539f828661373e565b5160018301809311612e0d576153b76001938761373e565b5190818110156153dc575f5260205260405f205b6153d5828761373e565b5201615331565b905f5260205260405f206153cb565b61531c90613731565b60021115614e5457565b6042916040519161190160f01b8352600283015260228201522090565b6126e99063ffffffff60806001600160401b03604084015116920151169061456b565b909395949260609661555e5761545390615a56565b8051156155325760206001600160601b03910151169360018060a01b031690815f52600160205261548860405f209384615b1b565b604051905f80516020615d4f8339815191525f80a26001600160601b03835416918583106155095750506001600160601b038481920316166001600160601b031982541617905560018060a01b03165f5260016020526001600160601b036154f760405f209282845416612e2e565b166001600160601b0319825416179055565b945094955050505063112fed8b60e31b60208301526024820152602481526126e960448261265c565b509394505050506040519063b2e276f760e01b60208301526024820152602481526126e960448261265c565b5093945050505060405190631cfdeebb60e01b60208301526024820152602481526126e960448261265c565b906001600160601b03809116911603906001600160601b038211612e0d57565b919496959390926060976001606085015116151580156157c5575b61579757906155db92911561575e575b50615a56565b80511561574b5760206001600160601b03910151169360018060a01b0316805f5260016020526001600160601b03608060405f2093015116858181115f1461571657906156279161558a565b906001600160601b03835416906001600160601b03831682106156e8575082546bffffffffffffffffffffffff19169190036001600160601b03161790555b5f90815260208190526040812080546affffffffffffffffffffff60a01b81166001600160a01b0385169081176001600160a01b0319929092161760f890811c600290811790911b6001600160f81b031916919091178255015560018060a01b03165f5260016020526001600160601b036154f760405f209282845416612e2e565b9697505050505050506040519063112fed8b60e31b60208301526024820152602481526126e960448261265c565b6001600160601b03925061572d906157369261558a565b82845416612e2e565b166001600160601b0319825416179055615666565b8263b2e276f760e01b5f5260045260245ffd5b6001600160a01b0387165f90815260016020526040902061577f9190615b1b565b835f80516020615d4f8339815191525f80a25f6155d5565b50505050929350505060405190631cfdeebb60e01b60208301526024820152602481526126e960448261265c565b50600260608501511615156155c5565b93969594929092606097600160608701511615158015615920575b6157975760c086015190808203615907575050156158d2575b505081516001600160a01b0393841693168390036158a85760a0612ea093926001600160601b03925f525f6020525f600260408220600160f81b60018060f81b03825416178155826001820155015582608082015116845f5260016020528361587960405f209282845416612e2e565b168419825416179055015116905f526001602052611c4960405f20916001600160601b03835460601c16612e2e565b92935050506040519063a905765160e01b60208301526024820152602481526126e960448261265c565b6158ee9160018060a01b03165f52600160205260405f20615b1b565b805f80516020615d4f8339815191525f80a25f80615809565b85637b54493160e01b5f5260045260245260445260645ffd5b50600260608701511615156157f0565b615938615a92565b615940615ae9565b6040519060208201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452604083015260608201524660808201523060a082015260a0815261439360c08261265c565b60ff5f80516020615d6f8339815191525460401c16156159ad57565b631afcd79f60e31b5f5260045ffd5b81519190604183036159ec576159e59250602082015190606060408401519301515f1a90615bb8565b9192909190565b50505f9160029190565b6004811015614e545780615a08575050565b60018103615a1f5763f645eedf60e01b5f5260045ffd5b60028103615a3a575063fce698f760e01b5f5260045260245ffd5b600314615a445750565b6335e2f38360e21b5f5260045260245ffd5b615a5e614c37565b505c615a68614c37565b506001600160601b0360405191615a7e83612641565b6001607f1b81161515835216602082015290565b615a9a613586565b8051908115615aaa576020012090565b50505f80516020615d0f833981519152548015615ac45790565b507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47090565b615af1613653565b8051908115615b01576020012090565b50505f80516020615d8f833981519152548015615ac45790565b9063ffffffff8116906020821015615b78576401fffffffe9060011b169080820460021490151715612e0d5781546001600160c01b038116600290921b6001600160401b031660c091821c17901b6001600160c01b031916179055565b50615b8290612dfe565b8060011b9080820460021481151715612e0d57612ea09260ff916002916152539160071c6001600160f81b0316906001016149f2565b91906fa2a8918ca85bafe22016d0b997e4df60600160ff1b038411615c25579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa156122b0575f516001600160a01b03811615615c1b57905f905f90565b505f906001905f90565b5050505f9160039190565b90615c545750805115615c4557805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580615c85575b615c65575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b15615c5d56fe405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acea16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1029016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d103a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc1cedb001a5114ea90393cd9f134224e9e1312545ee8a9b9533d780be6a9bf8b7f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d101237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00a164736f6c634300081a000a")]
+    #[sol(rpc, bytecode = "610100346101d557601f615ff538819003918201601f19168301916001600160401b038311848410176101d9578084926060946040528339810103126101d5578051906001600160a01b03821682036101d5576020810151604090910151916001600160a01b03831683036101d5573060805260a05260c05260e0527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c166101c6576002600160401b03196001600160401b0382160161015d575b604051615e0790816101ee823960805181818161185201526118e5015260a0518181816122fa0152818161320601528181613355015281816134ec0152818161388a015281816139be0152613a66015260c051818181610d7d015281816110e8015281816133ad01526138e3015260e05181818161131101528181611457015281816117b601528181611c5d015281816121180152614b790152f35b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f6100c1565b63f92ee8a960e01b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe6080806040526004361015610012575f80fd5b5f905f3560e01c90816308c84e70146122e8575080630cdedb5a146122615780631704f60f146121df57806317e828c4146121cd5780631ce03024146121af57806325d5971f146120785780632abff1f214611f6d5780632e1a7d4d14611f4f5780633336f89914611f34578063380f9c3814611eed5780633b5c226614611ea957806341451f9414611df857806345bc4d1014611a8f5780634f1ef286146118a657806352d1902d1461183f57806353182c6714611824578063553c0248146118085780635b07fdd8146117e55780635fbb4921146117a057806360dfd4a914611708578063635556241461164457806370a0823114611601578063715018a614611582578063775045cb1461156557806379ba5097146115185780638040fdc0146113af5780638094e614146112eb57806381bf6c24146112a257806384b0196e1461117a5780638da5cb5b14611145578063956b0960146111285780639f04f4201461110b5780639fe9428c146110d0578063ad3cb1cc14611087578063ae4449451461106f578063ae7330f114610fc6578063b4206dd214610f87578063c515c15f14610f02578063c7c9636f14610ead578063cb09e7c014610e67578063cb74db1114610e3e578063cb82cc8f14610e20578063cdc9712314610d2a578063cfbebd8b14610a24578063cfc0106e14610a0c578063d0e30db0146109f5578063d7697087146109da578063e30c3978146109a5578063efff97851461096b578063f2800f1a14610914578063f2fde38b1461088e578063f399e22e146102b9578063fb4ccf901461028e5763ffa1ad7414610270575f80fd5b3461028b578060031936011261028b57602060405160018152f35b80fd5b503461028b576102b56102a96102a3366127b1565b91613c3b565b60405191829182612463565b0390f35b503461028b57604036600319011261028b576102d3612329565b906024356001600160401b03811161088a576102f3903690600401612353565b90925f80516020615d9b833981519152549060ff8260401c1615916001600160401b03811680159081610882575b6001149081610878575b15908161086f575b506108605767ffffffffffffffff1981166001175f80516020615d9b8339815191525582610834575b506103656159bd565b61036d6159bd565b6001600160a01b038116156108205761038590614ade565b61038d6159bd565b604091825161039c8482612685565b601081526f12509bdd5b991b195cdcd3585c9ad95d60821b60208201528351906103c68583612685565b60018252603160f81b60208301526103dc6159bd565b6103e46159bd565b8051906001600160401b03821161080c5761040c5f80516020615cdb83398151915254612ba2565b601f811161079d575b50602090601f8311600114610721576104459291889183610617575b50508160011b915f199060031b1c19161790565b5f80516020615cdb833981519152555b8051906001600160401b03821161070d5761047d5f80516020615d1b83398151915254612ba2565b601f811161069e575b50602090601f8311600114610622576104b592918791836106175750508160011b915f199060031b1c19161790565b5f80516020615d1b833981519152555b835f80516020615d3b83398151915255835f80516020615dbb833981519152556001600160401b0381116106035761050781610502600254612ba2565b612bda565b83601f82116001146105945781908596610536949596926105895750508160011b915f199060031b1c19161790565b6002555b610542575080f35b5f80516020615d9b833981519152805460ff60401b1916905551600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a180f35b013590505f80610431565b60028552601f198216955f80516020615cbb83398151915291865b8881106105eb575083600195969798106105d2575b505050811b0160025561053a565b01355f19600384901b60f8161c191690555f80806105c4565b909260206001819286860135815501940191016105af565b634e487b7160e01b84526041600452602484fd5b015190505f80610431565b5f80516020615d1b83398151915287528187209190601f198416885b818110610686575090846001959493921061066e575b505050811b015f80516020615d1b833981519152556104c5565b01515f1960f88460031b161c191690555f8080610654565b9293602060018192878601518155019501930161063e565b5f80516020615d1b83398151915287527f5f9ce34815f8e11431c7bb75a8e6886a91478f7ffc1dbb0a98dc240fddd76b75601f840160051c81019160208510610703575b601f0160051c01905b8181106106f85750610486565b8781556001016106eb565b90915081906106e2565b634e487b7160e01b86526041600452602486fd5b5f80516020615cdb83398151915288528188209190601f198416895b818110610785575090846001959493921061076d575b505050811b015f80516020615cdb83398151915255610455565b01515f1960f88460031b161c191690555f8080610753565b9293602060018192878601518155019501930161073d565b5f80516020615cdb83398151915288527f42ad5d3e1f2e6e70edcf6d991b8a3023d3fca8047a131592f9edb9fd9b89d57d601f840160051c81019160208510610802575b601f0160051c01905b8181106107f75750610415565b8881556001016107ea565b90915081906107e1565b634e487b7160e01b87526041600452602487fd5b631e4fbdf760e01b84526004849052602484fd5b68ffffffffffffffffff191668010000000000000001175f80516020615d9b833981519152555f61035c565b63f92ee8a960e01b8552600485fd5b9050155f610333565b303b15915061032b565b849150610321565b5080fd5b503461028b57602036600319011261028b576108a8612329565b6108b06146cc565b5f80516020615ddb83398151915280546001600160a01b0319166001600160a01b039283169081179091555f80516020615cfb833981519152549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b503461028b57602036600319011261028b576004359061093382613582565b15610959576040816020936001600160401b039352808452205460a01c16604051908152f35b60249163d2be005d60e01b8252600452fd5b503461028b576102b561099161098c61098336612715565b94929093612aa7565b612e77565b60405191829160208352602083019061243f565b503461028b578060031936011261028b575f80516020615ddb833981519152546040516001600160a01b039091168152602090f35b503461028b576102b56102a96109ef366127b1565b91613c2f565b508060031936011261028b57610a09613bc7565b80f35b503461028b57610a09610a1e366127b1565b9161377b565b503461028b57606036600319011261028b576004356001600160401b03811161088a576101608160040191600319903603011261088a576024356001600160401b038111610d2657610a7a903690600401612353565b916044356001600160401b038111610d2257610a9a903690600401612353565b82359391610aa7856149f6565b939096610abc610ab736886128f8565b614047565b91610ace83610ac961595c565b61542a565b97600160c01b1615610ce057604051630b135d3f60e11b81529160209183918291610afe91908c60048501612826565b03816001600160a01b038c165afa908115610cd5578991610ca6575b506001600160e01b0319166374eca2c160e11b01610c97575b604051610b41606082612685565b60218152602081017f4c6f636b526571756573742850726f6f66526571756573742072657175657374815260408201602960f81b9052610b7f613e34565b90610b88613e7e565b610b90613ec3565b610b98613f7d565b8d610ba1613dad565b92610baa613fca565b94604051978897602089019a5180918c5e880160208101918583528051926020849201905e0160200183815281516020819301825e0182815281516020819301825e0190815281516020819301825e018d815281516020819301825e018c815281516020819301825e018b815203601f1981018252610c299082612685565b519020906040519060208201928352604082015260408152610c4c606082612685565b519020610c5761595c565b90610c619161542a565b913690610c6d926126c1565b610c76916159e8565b610c8291939293615a22565b610c8b836144c3565b94610a09969194614f77565b638baa579f60e01b8852600488fd5b610cc8915060203d602011610cce575b610cc08183612685565b8101906143c2565b5f610b1a565b503d610cb6565b6040513d8b823e3d90fd5b610cf2610cf891610d019336916126c1565b886159e8565b90929192615a22565b6001600160a01b03888116911614610b3357638baa579f60e01b8852600488fd5b8480fd5b8280fd5b503461028b578060031936011261028b57604051908060025490610d4d82612ba2565b8085529160018116908115610df95750600114610daf575b6102b584610d7581860382612685565b6040519182917f0000000000000000000000000000000000000000000000000000000000000000835260406020840152604083019061243f565b600281525f80516020615cbb833981519152939250905b808210610ddf57509091508101602001610d7582610d65565b919260018160209254838588010152019101909291610dc6565b60ff191660208087019190915292151560051b85019092019250610d759150839050610d65565b503461028b57602036600319011261028b57610a0960043533614b49565b503461028b57602036600319011261028b576020610e5d600435613582565b6040519015158152f35b503461028b57602036600319011261028b576020906001600160601b03906040906001600160a01b03610e98612329565b16815260018452205460601c16604051908152f35b503461028b57610ebc3661256c565b96959392919490955b818110610eda576102b56102a9898989613c2f565b80610efc610eeb6001938589612ded565b610ef6838789612e10565b91612aa7565b01610ec5565b503461028b57602036600319011261028b57604060e091600435815280602052208054906001600160601b0360026001830154920154916040519360018060a01b03811685526001600160401b038160a01c16602086015262ffffff81871c16604086015260f81c6060850152818116608085015260601c1660a083015260c0820152f35b503461028b57610a09610f99366124c2565b9091610fb2610fa882356149f6565b93909485846143e2565b91610fbc826144c3565b9490933393614f77565b503461028b57606036600319011261028b5780610fe1612329565b6044356001600160401b03811161106b57611000903690600401612353565b6001600160a01b0390921691823b156110665761103992849283604051809681958294636691f64760e01b845260243560048501612826565b03925af1801561105b5761104a5750f35b8161105491612685565b61028b5780f35b6040513d84823e3d90fd5b505050fd5b5050fd5b503461028b57610a0961108136612515565b90613178565b503461028b578060031936011261028b57506102b56040516110aa604082612685565b60058152640352e302e360dc1b602082015260405191829160208352602083019061243f565b503461028b578060031936011261028b5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461028b578060031936011261028b57602060405161c3508152f35b503461028b578060031936011261028b576020604051611d4c8152f35b503461028b578060031936011261028b575f80516020615cfb833981519152546040516001600160a01b039091168152602090f35b503461028b578060031936011261028b575f80516020615d3b83398151915254158061128c575b1561124f576111f3906111b26135af565b906111bb61367c565b906020611201604051936111cf8386612685565b8385525f368137604051968796600f60f81b885260e08589015260e088019061243f565b90868203604088015261243f565b904660608601523060808601528260a086015284820360c08601528080855193848152019401925b82811061123857505050500390f35b835185528695509381019392810192600101611229565b60405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b6044820152606490fd5b505f80516020615dbb83398151915254156111a1565b503461028b57602036600319011261028b576112df60209160406112c76004356149f6565b6001600160a01b039091168352600185529120614a30565b90506040519015158152f35b503461028b5760a036600319011261028b576004358160443560ff811680910361088a577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690813b15610d2657829160e48392604051948593849263d505accf60e01b84523360048501523060248501528960448501526024356064850152608484015260643560a484015260843560c48401525af161139a575b50610a098233614b49565b816113a491612685565b61088a57815f61138f565b503461028b57602036600319011261028b576004356113cc6146cc565b30825260016020526001600160601b03604083205460601c166001600160601b036113f68361469b565b16116115055761142c6114088261469b565b30845260016020526001600160601b03604085209181835460601c16031690612b57565b60405163a9059cbb60e01b815233600482015260248101829052602081604481866001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156114fa5783916114cb575b50156114bc576040519081527ff0ed97f7b968f9d8268bc8d104a11b3586ceeadd0e0af5f73769e2b479f9d0ae60203092a280f35b6312171d8360e31b8252600482fd5b6114ed915060203d6020116114f3575b6114e58183612685565b810190612b8a565b5f611487565b503d6114db565b6040513d85823e3d90fd5b63112fed8b60e31b825230600452602482fd5b503461028b578060031936011261028b575f80516020615ddb83398151915254336001600160a01b039091160361155257610a0933614ade565b63118cdaa760e01b815233600452602490fd5b503461028b576102b561099161157d61098336612715565b612d06565b503461028b578060031936011261028b5761159b6146cc565b5f80516020615ddb83398151915280546001600160a01b03199081169091555f80516020615cfb8339815191528054918216905581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461028b57602036600319011261028b576020906001600160601b03906040906001600160a01b03611632612329565b16815260018452205416604051908152f35b503461028b57602036600319011261028b576004356116616146cc565b30825260016020526001600160601b036040832054166001600160601b036116888361469b565b1611611505576116978161469b565b30835260016020526001600160601b03806040852092818454160316166001600160601b03198254161790558180808084335af16116d3612ecb565b50156114bc576040519081527f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b6560203092a280f35b503461028b57602036600319011261028b57600460606040602093833581528085522060026040519161173a83612605565b805460018060a01b03811684526001600160401b038160a01c168785015262ffffff8160e01c16604085015260f81c848401526001600160601b0360018201548181166080860152851c1660a0840152015460c082015201511615156040519015158152f35b503461028b578060031936011261028b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461028b578060031936011261028b57602061180061595c565b604051908152f35b503461028b578060031936011261028b57602090604051908152f35b503461028b576102b561099161183936612515565b90612e77565b503461028b578060031936011261028b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036118975760206040515f80516020615d5b8339815191528152f35b63703e46dd60e11b8152600490fd5b50604036600319011261028b576118bb612329565b906024356001600160401b03811161088a576118db9036906004016126f7565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016308114908115611a6d575b50611a5e5761191d6146cc565b6040516352d1902d60e01b8152926001600160a01b0381169190602085600481865afa80958596611a2a575b5061196257634c9c8ce360e01b84526004839052602484fd5b9091845f80516020615d5b8339815191528103611a185750813b15611a06575f80516020615d5b83398151915280546001600160a01b031916821790557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8480a281518390156119ec57808360206119e895519101845af46119e2612ecb565b91615c5c565b5080f35b505050346119f75780f35b63b398979f60e01b8152600490fd5b634c9c8ce360e01b8452600452602483fd5b632a87526960e21b8552600452602484fd5b9095506020813d602011611a56575b81611a4660209383612685565b81010312610d225751945f611949565b3d9150611a39565b63703e46dd60e11b8252600482fd5b5f80516020615d5b833981519152546001600160a01b0316141590505f611910565b503461028b57602036600319011261028b57600435611ad0611ab0826149f6565b6001600160a01b0390911680855260016020526040852090929190614a30565b5015611de45781835282602052604083209060405191611aef83612605565b805460018060a01b03811684526001600160401b038160a01c16602085015262ffffff8160e01c16604085015260f81c60608401526001810154600260808501926001600160601b03831684526001600160601b0360a087019360601c168352015460c08501526004606085015116611dd0576001606085015116611dbc576001600160401b03611b7f856149d4565b16421115611d935784865260208690526040862080546001600160f81b03811660f891821c60041790911b6001600160f81b031916178155869060029082600182015501556001600160601b03815116611d4c810290808204611d4c1490151715611d7f57611c046001600160601b03949392612710611c0993049586915116612e4a565b61469b565b916002606060018060a01b038751169601511615155f14611d1b57505060018060a01b03831685526001602052611c5a60408620611c54836001600160601b03835460601c16612e57565b90612b57565b847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561088a57818091602460405180948193630852cd8d60e31b83528960048401525af1801561105b57611d02575b5050907f79ca7c80cf57b513ffdf8aa37ec70e40757f5e0d35219241860bb4b4c2fa7616926001600160601b0360609360405193845216602083015260018060a01b03166040820152a280f35b81611d0f91949394612685565b610d225790845f611cb5565b9093506001600160601b0330943088526001602052611d4760408920611c548685835460601c16612e57565b511690865260016020526001600160601b03611d6a604088209282845416612e57565b166001600160601b0319825416179055611c5a565b634e487b7160e01b87526011600452602487fd5b6044866001600160401b0387611da8886149d4565b9063079c66ab60e41b845260045216602452fd5b631cfdeebb60e01b86526004859052602486fd5b633231064d60e11b86526004859052602486fd5b63d2be005d60e01b83526004829052602483fd5b503461028b57602036600319011261028b5760043590611e1782613582565b1561095957604081602093611e98935280845220600260405191611e3a83612605565b805460018060a01b03811684526001600160401b038160a01c168685015262ffffff8160e01c16604085015260f81c60608401526001600160601b036001820154818116608086015260601c1660a0840152015460c08201526149d4565b6001600160401b0360405191168152f35b503461028b57611eb83661256c565b96959392919490955b818110611ed6576102b56102a9898989613c3b565b80611ee7610eeb6001938589612ded565b01611ec1565b50611ef7366124c2565b505034611f27575b357f7fab7e8a635b9e4d20f8afff898bb2016ab093457ea8adc210f90fdbec6d8dfb8280a280f35b611f2f613bc7565b611eff565b503461028b576102b5610991611f4936612515565b90612d06565b503461028b57602036600319011261028b57610a09600435336146ff565b503461028b57602036600319011261028b576004356001600160401b03811161088a57611f9e903690600401612353565b611fa99291926146cc565b6001600160401b03811161206457611fc681610502600254612ba2565b81601f8211600114611ff95781908394611ff394926105895750508160011b915f199060031b1c19161790565b60025580f35b60028352601f198216935f80516020615cbb83398151915291845b86811061204c5750836001959610612033575b505050811b0160025580f35b01355f19600384901b60f8161c191690555f8080612027565b90926020600181928686013581550194019101612014565b634e487b7160e01b82526041600452602482fd5b503461028b57602036600319011261028b5760043533825260016020526001600160601b03604083205460601c166001600160601b036120b78361469b565b161161219c576120ed6120c98261469b565b33845260016020526001600160601b03604085209181835460601c16031690612b57565b60405163a9059cbb60e01b815233600482015260248101829052602081604481866001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156114fa57839161217d575b50156114bc576040519081527ff0ed97f7b968f9d8268bc8d104a11b3586ceeadd0e0af5f73769e2b479f9d0ae60203392a280f35b612196915060203d6020116114f3576114e58183612685565b5f612148565b63112fed8b60e31b825233600452602482fd5b503461028b578060031936011261028b576020604051620186a08152f35b503461028b57610a09610ef6366124c2565b503461028b576121ee366123b0565b969095919490936001600160a01b039092169190823b15610d22579161222f939185809460405196879586948593636691f64760e01b855260048501612826565b03925af1801561105b5761224c575b6102b56102a9868686613c2f565b612257828092612685565b61028b578061223e565b346122e45761226f366123b0565b93959194909290916001600160a01b0316803b156122e4576122ab965f8094604051998a9586948593636691f64760e01b855260048501612826565b03925af19283156122d9576102b5946102a9946122c9575b50613c3b565b5f6122d391612685565b5f6122c3565b6040513d5f823e3d90fd5b5f80fd5b346122e4575f3660031901126122e4577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b600435906001600160a01b03821682036122e457565b35906001600160a01b03821682036122e457565b9181601f840112156122e4578235916001600160401b0383116122e457602083818601950101116122e457565b9181601f840112156122e4578235916001600160401b0383116122e4576020808501948460051b0101116122e457565b60a06003198201126122e4576004356001600160a01b03811681036122e45791602435916044356001600160401b0381116122e457816123f291600401612353565b929092916064356001600160401b0381116122e4578161241491600401612380565b92909291608435906001600160401b0382116122e45760809082900360031901126122e45760040190565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b602081016020825282518091526040820191602060408360051b8301019401925f915b83831061249557505050505090565b90919293946020806124b3600193603f19868203018752895161243f565b97019301930191939290612486565b9060406003198301126122e4576004356001600160401b0381116122e45761016081840360031901126122e45760040191602435906001600160401b0382116122e45761251191600401612353565b9091565b9060406003198301126122e4576004356001600160401b0381116122e45760a081840360031901126122e45760040191602435906001600160401b0382116122e45760809082900360031901126122e45760040190565b60806003198201126122e4576004356001600160401b0381116122e4578161259691600401612380565b929092916024356001600160401b0381116122e457816125b891600401612380565b929092916044356001600160401b0381116122e457816125da91600401612380565b92909291606435906001600160401b0382116122e45760809082900360031901126122e45760040190565b60e081019081106001600160401b0382111761262057604052565b634e487b7160e01b5f52604160045260245ffd5b60a081019081106001600160401b0382111761262057604052565b608081019081106001600160401b0382111761262057604052565b604081019081106001600160401b0382111761262057604052565b90601f801991011681019081106001600160401b0382111761262057604052565b6001600160401b03811161262057601f01601f191660200190565b9291926126cd826126a6565b916126db6040519384612685565b8294818452818301116122e4578281602093845f960137010152565b9080601f830112156122e457816020612712933591016126c1565b90565b60806003198201126122e4576004356001600160401b0381116122e45761016081830360031901126122e457600401916024356001600160401b0381116122e4578261276391600401612353565b929092916044356001600160401b0381116122e45760a081840360031901126122e45760040191606435906001600160401b0382116122e45760809082900360031901126122e45760040190565b60406003198201126122e4576004356001600160401b0381116122e457816127db91600401612380565b92909291602435906001600160401b0382116122e45760809082900360031901126122e45760040190565b908060209392818452848401375f828201840152601f01601f1916010190565b604090612712949281528160208201520191612806565b35906001600160601b03821682036122e457565b35906001600160e01b0319821682036122e457565b359063ffffffff821682036122e457565b91908260e09103126122e45760405161288f81612605565b8092803582526020810135602083015260408101356001600160401b03811681036122e45760c091829160408501526128ca60608201612866565b60608501526128db60808201612866565b60808501526128ec60a08201612866565b60a08501520135910152565b9190610160838203126122e4576040519061291282612634565b81938035835260208101356001600160401b0381116122e45781018083039060a082126122e45760408051926129478461264f565b82358452601f1901126122e4576040516129608161266a565b61296c6020830161233f565b815261297a6040830161283d565b6020820152602083015260608101356001600160401b0381116122e45781016040818603126122e457604051916129b08361266a565b813560028110156122e45783526020820135926001600160401b0384116122e4576129e2876129f295608095016126f7565b6020820152604085015201612851565b6060820152602084015260408101356001600160401b0381116122e457810182601f820112156122e45782816020612a2c933591016126c1565b604084015260608101356001600160401b0381116122e4578101916040838203126122e45760405192612a5e8461266a565b803560028110156122e45784526020810135926001600160401b0384116122e457608094612a9284612aa2968895016126f7565b6020820152606087015201612877565b910152565b91823590600160c01b821615612b2b57602092612b0292611c0492612af292612adb92871c6001600160a01b0316886143e2565b945b612ae6816144c3565b50506080369101612877565b6001600160401b034216906145b7565b6001600160601b0360405191612b178361266a565b600183521691018190526001607f1b17905d565b5050506020612b02611c04612af2612b51612b49610ab736886128f8565b610ac961595c565b94612add565b80546bffffffffffffffffffffffff60601b191660609290921b6bffffffffffffffffffffffff60601b16919091179055565b908160209103126122e4575180151581036122e45790565b90600182811c92168015612bd0575b6020831014612bbc57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612bb1565b601f8111612be6575050565b60025f5260205f20906020601f840160051c83019310612c20575b601f0160051c01905b818110612c15575050565b5f8155600101612c0a565b9091508190612c01565b356001600160a01b03811681036122e45790565b903590601e19813603018212156122e457018035906001600160401b0382116122e4576020019160608202360383136122e457565b359061ffff821682036122e457565b91908260609103126122e457604051606081018181106001600160401b03821117612620576040526040612aa2818395612cbb81612c73565b8552612cc96020820161233f565b60208601520161283d565b903590601e19813603018212156122e457018035906001600160401b0382116122e4576020019181360383136122e457565b9190612d128184613178565b612d27612d2160608301612c2a565b846147d1565b92803591827f4321394035f9f33b5a0c036d91d311549f949cdfc2a4fe70bd3745115b248da85f80a260208101612d5e8183612c3e565b9050612d6b575b50505050565b612d7491612c3e565b91909115612dd957612dd092612d8d6040933690612c82565b6001600160601b038460018060a01b036020840151169201511691612db56060850185612cd4565b939092612dc56080870187612cd4565b9790960135926148fa565b5f808080612d65565b634e487b7160e01b5f52603260045260245ffd5b9190811015612dd95760051b8101359061015e19813603018212156122e4570190565b90821015612dd9576125119160051b810190612cd4565b601f19810191908211612e3657565b634e487b7160e01b5f52601160045260245ffd5b91908203918211612e3657565b906001600160601b03809116911601906001600160601b038211612e3657565b612e8682606092949394612d06565b92016001600160a01b03612e9982612c2a565b165f5260016020526001600160601b0360405f20541680612eb8575050565b612ec4612ec992612c2a565b6146ff565b565b3d15612ef5573d90612edc826126a6565b91612eea6040519384612685565b82523d5f602084013e565b606090565b6001600160401b0381116126205760051b60200190565b903590601e19813603018212156122e457018035906001600160401b0382116122e457602001918160061b360383136122e457565b6020815260406020612f6284518383860152606085019061243f565b93015191015290565b90929192612f7881612efa565b93612f866040519586612685565b60606020868481520192028301928184116122e457915b838310612faa5750505050565b6020606091612fb98486612c82565b815201920191612f9d565b929192612fd082612efa565b93612fde6040519586612685565b602085848152019260061b8201918183116122e457925b8284106130025750505050565b6040848303126122e4576020604091825161301c8161266a565b61302587612c73565b8152613032838801612851565b83820152815201930192612ff5565b6020815260a0810191805192608060208401528351809152602060c084019401905f5b8181106130ea57505050602081810151838503601f190160408501528051808652948201949101905f5b8181106130ba57505050604081015160608381019190915201516001600160a01b031660809091015290565b8251805161ffff1687526020908101516001600160e01b031916818801526040909601959092019160010161308e565b8251805161ffff1687526020818101516001600160a01b0316818901526040918201516001600160601b03169188019190915260609096019590920191600101613064565b9190811015612dd95760061b0190565b356001600160e01b0319811681036122e45790565b9061316e9060409396959496606084526060840191612806565b9460208201520152565b5f9160205f61318a6060850185612cd4565b908160405192839283378101838152039060025afa156122d9576131bb6131b65f516040850135614c7b565b614da3565b916131ea6040516131cb8161264f565b5f81528235602082015260208301356040820152846060820152614e94565b60408301936131f98585612f11565b1590506134e657613252907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169061323c6080860186612cd4565b93906040519461324b8661266a565b36916126c1565b83526020830152803b156134ae576132819187916040518080958194631599ead560e01b835260048301612f46565b03915afa80156134db579086916134c6575b506020915b6132a28686612f11565b90916132e36132b386890189612c3e565b9490936132da6132c560608c01612c2a565b95604051976132d38961264f565b3691612f6b565b86523691612fc4565b85840152604083015260018060a01b0316606082015260405161331b8161330d8682019485613041565b03601f198101835282612685565b604051918291518091835e8101838152039060025afa156114fa578351926133438184612f11565b9050151580613468575b6133fa5750507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906133889080612cd4565b823b15610d225760405163ab750e7560e01b815293859385939092849283926133d6927f00000000000000000000000000000000000000000000000000000000000000009160048601613154565b03915afa801561105b576133e8575050565b6133f3828092612685565b61028b5750565b613405859184612f11565b15613454576134196020613424920161313f565b926080810190612cd4565b60049391931161088a57632e2ce35360e21b82526001600160e01b03199081166004529135909116602452604490fd5b634e487b7160e01b82526032600452602482fd5b506134738184612f11565b156134b2576020613484910161313f565b6134916080840184612cd4565b6004116134ae57356001600160e01b03199081169116141561334d565b8680fd5b634e487b7160e01b86526032600452602486fd5b816134d091612685565b610d2257845f613293565b6040513d88823e3d90fd5b613522907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169061323c6080860186612cd4565b83526020830152803b156122e457613551915f916040518080958194631599ead560e01b835260048301612f46565b039161c350fa80156122d95761356c575b5084602091613298565b6135799195505f90612685565b5f936020613562565b61358e6135ab916149f6565b6001600160a01b039091165f908152600160205260409020614a30565b5090565b604051905f825f80516020615cdb83398151915254916135ce83612ba2565b808352926001811690811561365d57506001146135f2575b612ec992500383612685565b505f80516020615cdb8339815191525f90815290917f42ad5d3e1f2e6e70edcf6d991b8a3023d3fca8047a131592f9edb9fd9b89d57d5b818310613641575050906020612ec9928201016135e6565b6020919350806001915483858901015201910190918492613629565b60209250612ec994915060ff191682840152151560051b8201016135e6565b604051905f825f80516020615d1b833981519152549161369b83612ba2565b808352926001811690811561365d57506001146136be57612ec992500383612685565b505f80516020615d1b8339815191525f90815290917f5f9ce34815f8e11431c7bb75a8e6886a91478f7ffc1dbb0a98dc240fddd76b755b81831061370d575050906020612ec9928201016135e6565b60209193508060019154838589010152019101909184926136f5565b3561ffff811681036122e45790565b9190811015612dd95760051b81013590609e19813603018212156122e4570190565b805115612dd95760200190565b8051821015612dd95760209160051b010190565b61ffff8211613bae5761378d82612efa565b9061379b6040519283612685565b828252601f196137aa84612efa565b013660208401376137ba83612efa565b6137c76040519182612685565b838152601f196137d685612efa565b0136602083013760408501936137ec8587612f11565b90505f5b8787838310613af557505050505f5b818110613927575050505061383260209261381a5f93615323565b61384161382986880188612c3e565b94909388612f11565b6132da6132c560608b01612c2a565b85840152604083015260018060a01b0316606082015260405161386b8161330d8682019485613041565b604051918291518091835e8101838152039060025afa156122d9575f517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316916138bd9080612cd4565b919092803b156122e45761390c935f936040519586948593849363ab750e7560e01b85527f00000000000000000000000000000000000000000000000000000000000000009160048601613154565b03915afa80156122d95761391d5750565b5f612ec991612685565b613932818386613738565b9060205f6139436060850185612cd4565b908160405192839283378101838152039060025afa156122d95761396f6131b65f516040850135614c7b565b9161399e60405161397f8161264f565b8381528235602082015260208301356040820152846060820152614e94565b6139a88389613767565b526139b38286613767565b51613a6057613a04927f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316916139f5906080810190612cd4565b94906040519561324b8761266a565b84526020840152803b156122e457613a33925f916040518080968194631599ead560e01b835260048301612f46565b039161c350fa9182156122d957600192613a50575b505b016137ff565b5f613a5a91612685565b5f613a48565b613a9d927f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316916139f5906080810190612cd4565b84526020840152803b156122e457613acc925f916040518080968194631599ead560e01b835260048301612f46565b03915afa9182156122d957600192613ae5575b50613a4a565b5f613aef91612685565b5f613adf565b613b3b61ffff613b33613b2e86613b1c86613b286020613b2285613b1c613b459c8e612f11565b9061312f565b0161313f565b98612f11565b613729565b168689613738565b6080810190612cd4565b6004929192116122e4576001613b7d61ffff613b76613b2e878f978f613b1c9163ffffffff60e01b90351699612f11565b1688613767565b526001600160e01b031916818103613b995750506001016137f0565b632e2ce35360e21b5f5260045260245260445ffd5b506377e4aa5360e11b5f5260045261ffff60245260445ffd5b613bd03461469b565b335f5260016020526001600160601b03613bf160405f209282845416612e57565b166001600160601b03198254161790556040513481527fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c60203392a2565b82606092612e86929594955b9291613c4881838661377b565b613c5182612efa565b93613c5f6040519586612685565b828552601f19613c6e84612efa565b015f5b818110613d9c575050845f5b848110613d2d57505060208201613c948184612c3e565b9390505f5b848110613ca857505050505050565b613cb28383612c3e565b909190811015612dd957613d27613cd160019360608402013690612c82565b613ce161ffff8251168a89613738565b906001600160601b036040868060a01b036020840151169201511691613d0a6060820182612cd4565b91613d186080820182612cd4565b959094604083013592356148fa565b01613c99565b80613d50613d3e6001938887613738565b613d4a60608801612c2a565b906147d1565b613d5a8285613767565b52613d658184613767565b50613d71818786613738565b357f4321394035f9f33b5a0c036d91d311549f949cdfc2a4fe70bd3745115b248da85f80a201613c7d565b806060602080938a01015201613c71565b60405190613dbc608083612685565b605a82527f6c2c496e70757420696e7075742c4f66666572206f66666572290000000000006060837f50726f6f66526571756573742875696e743235362069642c526571756972656d60208201527f656e747320726571756972656d656e74732c737472696e6720696d616765557260408201520152565b60405190613e43606083612685565b60268252654c696d69742960d01b6040837f43616c6c6261636b286164647265737320616464722c75696e7439362067617360208201520152565b60405190613e8d606083612685565b60218252602960f81b6040837f496e7075742875696e743820696e707574547970652c6279746573206461746160208201520152565b60405190613ed260c083612685565b6084825263616b652960e01b60a0837f4f666665722875696e74323536206d696e50726963652c75696e74323536206d60208201527f617850726963652c75696e7436342062696464696e6753746172742c75696e7460408201527f33322072616d705570506572696f642c75696e743332206c6f636b54696d656f60608201527f75742c75696e7433322074696d656f75742c75696e74323536206c6f636b537460808201520152565b60405190613f8c606083612685565b602982526874657320646174612960b81b6040837f5072656469636174652875696e743820707265646963617465547970652c627960208201520152565b60405190613fd9608083612685565b605382527274652c6279746573342073656c6563746f722960681b6060837f526571756972656d656e7473286279746573333220696d61676549642c43616c60208201527f6c6261636b2063616c6c6261636b2c507265646963617465207072656469636160408201520152565b61404f613dad565b614057613e34565b61405f613e7e565b90614068613ec3565b614070613f7d565b614078613fca565b916040519485946020860197805160208192018a5e860160208101915f83528051926020849201905e016020015f815281516020819301825e015f815281516020819301825e015f815281516020819301825e015f815281516020819301825e015f815203601f19810182526140ee9082612685565b519020908051906020810151614102613fca565b61410a613e34565b614112613f7d565b90604051918291602083019480516020819201875e830160208101915f83528051926020849201905e016020015f815281516020819301825e015f815203601f19810182526141619082612685565b519020908051906020810151614175613e34565b8051906020012090600160a01b6001900381511690602001516001600160601b0316604051916020830193845260408301526060820152606081526141bb608082612685565b5190209060408101516141cc613f7d565b80519060200120908051906141e082615420565b602001518051906020012060405191602083019384526141ff81615420565b6040830152606082015260608152614218608082612685565b5190209063ffffffff60e01b90606001511691604051936020850195865260408501526060840152608083015260a082015260a0815261425960c082612685565b519020906040810151805190602001206060820151614276613e7e565b805190602001209080519061428a82615420565b602001518051906020012060405191602083019384526142a981615420565b60408301526060820152606081526142c2608082612685565b51902091608001516142d2613ec3565b60405180602081019280516020819201855e8101602081015f905203602001601f19810182526143029082612685565b5190209080519060208101519060408101516001600160401b0316606082015163ffffffff16608083015163ffffffff169160a084015163ffffffff169360c0015194604051966020880198895260408801526060870152608086015260a085015260c084015260e0830152610100820152610100815261438561012082612685565b51902092604051946020860196875260408601526060850152608084015260a083015260c082015260c081526143bc60e082612685565b51902090565b908160209103126122e457516001600160e01b0319811681036122e45790565b92916143f4612b49610ab736876128f8565b9335600160c01b161561448d579160209161442693604051809581948293630b135d3f60e11b84528960048501612826565b03916001600160a01b0316620186a0fa9081156122d9575f9161446e575b506001600160e01b0319166374eca2c160e11b0161445f5790565b638baa579f60e01b5f5260045ffd5b614487915060203d602011610cce57610cc08183612685565b5f614444565b61449f6144a5916144ae9436916126c1565b846159e8565b90939193615a22565b6001600160a01b0390811691160361445f5790565b906144d13660808401612877565b80516020820151106145885763ffffffff606082015116608082019063ffffffff825116106145885763ffffffff90511660a082019063ffffffff825116106145885761453d9063ffffffff6001600160401b03604061453086615447565b9501511691511690614597565b9262ffffff6001600160401b036145548487614f57565b1611614588576001600160401b038416904282106145725750509190565b63873fd26b60e01b5f523560045260245260445ffd5b6341abc80160e01b5f5260045ffd5b906001600160401b03809116911601906001600160401b038211612e3657565b9060408201906001600160401b0380835116911690811115614695576001600160401b036145e484615447565b16811161468e576001600160401b03825116906001600160401b03614615606086019363ffffffff85511690614597565b16811115614627575050506020015190565b614654906001600160401b0363ffffffff6146486020880151885190612e4a565b94511694511690612e4a565b925192818102918183041490151715612e3657811561467a57048101809111612e365790565b634e487b7160e01b5f52601260045260245ffd5b5050505f90565b50505190565b6001600160601b0381116146b5576001600160601b031690565b6306dfcc6560e41b5f52606060045260245260445ffd5b5f80516020615cfb833981519152546001600160a01b031633036146ec57565b63118cdaa760e01b5f523360045260245ffd5b9060018060a01b03821691825f5260016020526001600160601b0360405f2054166001600160601b036147318461469b565b16116147be575f80808481946147468261469b565b88845260016020526001600160601b03806040862092818454160316166001600160601b03198254161790555af161477c612ecb565b50156147af5760207f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b6591604051908152a2565b6312171d8360e31b5f5260045ffd5b8263112fed8b60e31b5f5260045260245ffd5b9081356147dd816149f6565b60018060a09493941b0383165f5260016020526147fd8160405f20614a30565b9390156148ec57825f525f60205260405f20926040519361481d85612605565b600281549160018060a01b03831687526001600160401b038360a01c169283602089015262ffffff8160e01c16604089015260f81c60608801526001600160601b03600182015481811660808a015260601c1660a0880152015460c08601524211155f146148d857602061489397013593615801565b905b815161489d57565b7f210e4fd706e561df48472433bcc50b4589f2c13e784e9992f4c3e6de26eb356460405160208152806148d3602082018661243f565b0390a1565b60206148e6970135936155d6565b90614895565b60206148e69601359261546a565b966001600160a01b03909116959094909392863b156122e457866001600160601b035f969261496488946149529a6040519b8c9a8b998a9663a12da43f60e01b88526004880152606060248801526064870191612806565b84810360031901604486015291612806565b039416f190816149c4575b506149c0577f5c5960582bfc7a494183b4e9a66bfe8ecffc07a83a48d136e732400f7b98bf509061499e612ecb565b906149bb604051928392835260406020840152604083019061243f565b0390a2565b5050565b5f6149ce91612685565b5f61496f565b6127129062ffffff60406001600160401b036020840151169201511690614597565b906001600160c11b0319821661458857602082901c6001600160a01b03169163ffffffff1690565b6302000000821015612dd95701905f90565b63ffffffff821691906020831015614a82576401fffffffe905460c01c9160011b169180830460021490151715612e36576001600160401b03906003831b1616901c9060026001831615159216151590565b91614a8d9150612e27565b908160011b9180830460021481151715612e365760ff91614abd9160071c6001600160f81b031690600101614a1e565b90549060031b1c9116906003821b16901c9060026001831615159216151590565b5f80516020615ddb83398151915280546001600160a01b03199081169091555f80516020615cfb83398151915280549182166001600160a01b0393841690811790915591167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b6040516323b872dd60e01b81526001600160a01b03918216600482018190523060248301526044820184905292917f000000000000000000000000000000000000000000000000000000000000000016906020905f9060649082855af19081601f3d1160015f5114161516614c56575b5015614c1a57602081614c11614bef7f1da2c4060997c108162f55c30ad2268924b069210f8c686ba302e1acc6909ccc9461469b565b855f5260018452611c5460405f20916001600160601b03835460601c16612e57565b604051908152a2565b60405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606490fd5b3b153d171590505f614bb9565b60405190614c708261266a565b5f6020838281520152565b905f6080604051614c8b81612634565b828152826020820152604051614ca08161266a565b8381528360208201526040820152826060820152015260405190614cc38261266a565b5f82525f602083015260405190614cd98261266a565b8152602081015f815260205f600c6040516b1c9a5cd8cc0b93dd5d1c1d5d60a21b815260025afa156122d9576020915f918251915190516040519185830193845260408301526060820152600160f91b608082015260628152614d3d608282612685565b604051918291518091835e8101838152039060025afa156122d9575f519060405192614d6884612634565b83527fa3acc27117418996340b84e5a90f3ef4c49d22c79e44aad822ec9c313e1eb8e2602084015260408301525f6060830152608082015290565b60205f60126040517172697363302e52656365697074436c61696d60701b815260025afa156122d9575f519060608101519181519260208301519360406080850151940193845151906003821015614e8057945160209081015160408051808401978852908101959095526060850193909352608084019690965260a08301949094526001600160f81b031960f894851b811660c0840152931b90921660c4830152600160fa1b60c883015260aa82525f91614e6060ca82612685565b604051918291518091835e8101838152039060025afa156122d9575f5190565b634e487b7160e01b5f52602160045260245ffd5b6056604051614ea4608082612685565b81815275742c6279746573333220636c61696d4469676573742960501b606060208301927f4173736573736f72436f6d6d69746d656e742875696e7432353620696e64657884527f2c75696e743235362069642c62797465733332207265717565737444696765736040820152015220908051906020810151906060604082015191015191604051936020850195865260408501526060840152608083015260a082015260a081526143bc60c082612685565b906001600160401b03809116911603906001600160401b038211612e3657565b959492939160018060a01b0316805f526001602052614f998560405f20614a30565b9061530f576152fb576001600160401b038416968742116152e357614fc7611c04612af23660808501612877565b94825f52600160205260405f20976001600160601b03895416956001600160601b038816948588106152d1575060018060a01b031696875f52600160205260405f20906001600160601b03825460601c16976101408601358099106152be57916001600160601b038061506c936150719796950316166001600160601b03198d5416178c556001600160601b0361505d8a61469b565b81835460601c16031690612b57565b614f57565b936001600160401b03851662ffffff81116152a75750916001600160601b036151899261516f60ff6150a56002989761469b565b92604051996150b38b612605565b8b8b5260208b019e8f5262ffffff60408c019116815260608b01915f835260808c019788528660a08d019616865260c08c01998a52359e8f5f525f60205260405f209b60018060a01b039060018060a01b039051161660018060a01b03198d5416178c5551908b549062ffffff60e01b905160e01b16916001600160401b0360a01b9060a01b16906affffffffffffffffffffff60a01b191617178a555116889081549060ff60f81b9060f81b169060018060f81b0316179055565b818060018901945116168219845416178355511690612b57565b5191015563ffffffff8216916020831015615219576401fffffffe9060011b169180830460021490151715612e365782546001600160c01b038116600190931b6001600160401b031660c091821c17901b6001600160c01b031916919091179091557ffb1dd4383bc31d469e205e04236dbca09ae13ab0373414dccbe098a861ddef5590602090604051908152a2565b509061522490612e27565b908160011b9282840460021483151715612e36577ffb1dd4383bc31d469e205e04236dbca09ae13ab0373414dccbe098a861ddef55936020936152a29260ff9160019161527f9160071c6001600160f81b0316908301614a1e565b929093161b82548260031b1c179082549060031b91821b915f19901b1916179055565b614c11565b6306dfcc6560e41b5f52601860045260245260445ffd5b8963112fed8b60e31b5f5260045260245ffd5b63112fed8b60e31b5f5260045260245ffd5b879063cfe6a8fd60e01b5f523560045260245260445ffd5b86631cfdeebb60e01b5f523560045260245ffd5b8763a905765160e01b5f523560045260245ffd5b8051156145885760018151146154175780515b6001811161534c57506153489061375a565b5190565b60018101808211612e365760011c905f5b8160011c81106153ab5750600180821614615379575b50615336565b5f198101908111612e365761538e9083613767565b515f198201828111612e36576153a49084613767565b525f615373565b600181901b906001600160ff1b0381168103612e36576153cb8286613767565b5160018301809311612e36576153e360019387613767565b519081811015615408575f5260205260405f205b6154018287613767565b520161535d565b905f5260205260405f206153f7565b6153489061375a565b60021115614e8057565b6042916040519161190160f01b8352600283015260228201522090565b6127129063ffffffff60806001600160401b036040840151169201511690614597565b909395949260609661558a5761547f90615a82565b80511561555e5760206001600160601b03910151169360018060a01b031690815f5260016020526154b460405f209384615b47565b604051905f80516020615d7b8339815191525f80a26001600160601b03835416918583106155355750506001600160601b038481920316166001600160601b031982541617905560018060a01b03165f5260016020526001600160601b0361552360405f209282845416612e57565b166001600160601b0319825416179055565b945094955050505063112fed8b60e31b6020830152602482015260248152612712604482612685565b509394505050506040519063b2e276f760e01b6020830152602482015260248152612712604482612685565b5093945050505060405190631cfdeebb60e01b6020830152602482015260248152612712604482612685565b906001600160601b03809116911603906001600160601b038211612e3657565b919496959390926060976001606085015116151580156157f1575b6157c3579061560792911561578a575b50615a82565b8051156157775760206001600160601b03910151169360018060a01b0316805f5260016020526001600160601b03608060405f2093015116858181115f146157425790615653916155b6565b906001600160601b03835416906001600160601b0383168210615714575082546bffffffffffffffffffffffff19169190036001600160601b03161790555b5f90815260208190526040812080546affffffffffffffffffffff60a01b81166001600160a01b0385169081176001600160a01b0319929092161760f890811c600290811790911b6001600160f81b031916919091178255015560018060a01b03165f5260016020526001600160601b0361552360405f209282845416612e57565b9697505050505050506040519063112fed8b60e31b6020830152602482015260248152612712604482612685565b6001600160601b03925061575990615762926155b6565b82845416612e57565b166001600160601b0319825416179055615692565b8263b2e276f760e01b5f5260045260245ffd5b6001600160a01b0387165f9081526001602052604090206157ab9190615b47565b835f80516020615d7b8339815191525f80a25f615601565b50505050929350505060405190631cfdeebb60e01b6020830152602482015260248152612712604482612685565b50600260608501511615156155f1565b9396959492909260609760016060870151161515801561594c575b6157c35760c086015190808203615933575050156158fe575b505081516001600160a01b0393841693168390036158d45760a0612ec993926001600160601b03925f525f6020525f600260408220600160f81b60018060f81b03825416178155826001820155015582608082015116845f526001602052836158a560405f209282845416612e57565b168419825416179055015116905f526001602052611c5460405f20916001600160601b03835460601c16612e57565b92935050506040519063a905765160e01b6020830152602482015260248152612712604482612685565b61591a9160018060a01b03165f52600160205260405f20615b47565b805f80516020615d7b8339815191525f80a25f80615835565b85637b54493160e01b5f5260045260245260445260645ffd5b506002606087015116151561581c565b615964615abe565b61596c615b15565b6040519060208201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452604083015260608201524660808201523060a082015260a081526143bc60c082612685565b60ff5f80516020615d9b8339815191525460401c16156159d957565b631afcd79f60e31b5f5260045ffd5b8151919060418303615a1857615a119250602082015190606060408401519301515f1a90615be4565b9192909190565b50505f9160029190565b6004811015614e805780615a34575050565b60018103615a4b5763f645eedf60e01b5f5260045ffd5b60028103615a66575063fce698f760e01b5f5260045260245ffd5b600314615a705750565b6335e2f38360e21b5f5260045260245ffd5b615a8a614c63565b505c615a94614c63565b506001600160601b0360405191615aaa8361266a565b6001607f1b81161515835216602082015290565b615ac66135af565b8051908115615ad6576020012090565b50505f80516020615d3b833981519152548015615af05790565b507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47090565b615b1d61367c565b8051908115615b2d576020012090565b50505f80516020615dbb833981519152548015615af05790565b9063ffffffff8116906020821015615ba4576401fffffffe9060011b169080820460021490151715612e365781546001600160c01b038116600290921b6001600160401b031660c091821c17901b6001600160c01b031916179055565b50615bae90612e27565b8060011b9080820460021481151715612e3657612ec99260ff9160029161527f9160071c6001600160f81b031690600101614a1e565b91906fa2a8918ca85bafe22016d0b997e4df60600160ff1b038411615c51579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa156122d9575f516001600160a01b03811615615c4757905f905f90565b505f906001905f90565b5050505f9160039190565b90615c805750805115615c7157805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580615cb1575b615c91575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b15615c8956fe405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acea16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1029016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d103a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc1cedb001a5114ea90393cd9f134224e9e1312545ee8a9b9533d780be6a9bf8b7f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d101237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00a164736f6c634300081a000a")]
     contract BoundlessMarket {
         constructor(address verifier, bytes32 assessorId, address stakeTokenContract) {}
             function initialize(address initialOwner, string calldata imageUrl) {}
@@ -23,7 +23,7 @@ alloy::sol! {
 }
 
 alloy::sol! {
-    #[sol(rpc, bytecode = "60e0806040523461030f57610e97803803809161001c8285610313565b833981019060608183031261030f5780516001600160a01b038116810361030f576020820151604083015190926001600160401b03821161030f570183601f8201121561030f578051906001600160401b0382116102fb576040519461008c601f8401601f191660200187610313565b8286526020838301011161030f57815f9260208093018388015e8501015260805260c081905281516001600160401b0381116102fb575f54600181811c911680156102f1575b60208210146102dd57601f811161027b575b50602092601f821160011461021c57928192935f92610211575b50508160011b915f199060031b1c1916175f555b60205f602b6040517f72697363302e536574496e636c7573696f6e526563656970745665726966696581526a72506172616d657465727360a81b8482015260025afa15610206575f602091815190604051908482019283526040820152600160f81b606082015260428152610188606282610313565b604051918291518091835e8101838152039060025afa15610206575f516001600160e01b03191660a052604051610b609081610337823960805181818161048f015281816106a701526108c9015260a0518181816106e80152610824015260c05181818161012301528181610517015281816109460152610b0e0152f35b6040513d5f823e3d90fd5b015190505f806100fe565b601f198216935f8052805f20915f5b868110610263575083600195961061024b575b505050811b015f55610112565b01515f1960f88460031b161c191690555f808061023e565b9192602060018192868501518155019401920161022b565b5f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f830160051c810191602084106102d3575b601f0160051c01905b8181106102c857506100e4565b5f81556001016102bb565b90915081906102b2565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100d2565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b601f909101601f19168101906001600160401b038211908210176102fb5760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c908163053c238d146106d65750806308c84e70146106925780631599ead51461061d57806348cbdfca146105ee5780636691f64714610459578063ab750e75146101d9578063cdc97123146100c55763ffa1ad7414610076575f80fd5b346100c257806003193601126100c257506100be6040516100986040826107b3565b60058152640302e342e360dc1b6020820152604051918291602083526020830190610745565b0390f35b80fd5b50346100c257806003193601126100c25760405190808054908160011c916001811680156101cf575b6020841081146101bb578386529081156101945750600114610155575b6100be8461011b818603826107b3565b6040519182917f00000000000000000000000000000000000000000000000000000000000000008352604060208401526040830190610745565b80805260208120939250905b80821061017a5750909150810160200161011b8261010b565b919260018160209254838588010152019101909291610161565b60ff191660208087019190915292151560051b8501909201925061011b915083905061010b565b634e487b7160e01b83526022600452602483fd5b92607f16926100ee565b50346100c25760603660031901126100c2576004356001600160401b0381116104555761020a903690600401610718565b9082608060405161021a81610769565b82815282602082015260405161022f81610798565b8381528360208201526040820152826060820152015260405161025181610798565b83815283602082015260405161026681610798565b6044358152846020820191818352602082600c6040516b1c9a5cd8cc0b93dd5d1c1d5d60a21b815260025afa15610448576020928251915190516040519185830193845260408301526060820152600160f91b6080820152606281526102cd6082826107b3565b604051918291518091835e8101838152039060025afa1561043d57835190604051906102f882610769565b602435825260208201907fa3acc27117418996340b84e5a90f3ef4c49d22c79e44aad822ec9c313e1eb8e282526040830190815260608301938785526080840190815260208860126040517172697363302e52656365697074436c61696d60701b815260025afa1561043257875194519351925190519082515192600384101561041e575160209081015160408051808401998a52908101979097526060870195909552608086019190915260a08501919091526001600160f81b031960f892831b811660c08601529290911b90911660c4830152600160fa1b60c883015260aa82529185916103e960ca826107b3565b604051918291518091835e8101838152039060025afa1561041357610410918351916107f4565b80f35b6040513d84823e3d90fd5b634e487b7160e01b8a52602160045260248afd5b6040513d89823e3d90fd5b6040513d85823e3d90fd5b50604051903d90823e3d90fd5b5080fd5b50346105ea5760403660031901126105ea576004356024356001600160401b0381116105ea5761048d903690600401610718565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660205f816104c487610b08565b604051918183925191829101835e8101838152039060025afa156105df575f51813b156105ea575f90604051928380809363ab750e7560e01b82526060600483015261051460648301898b6107d4565b907f00000000000000000000000000000000000000000000000000000000000000006024840152604483015203915afa80156105df576105a7575b50907fcb874ca5a04ca17d10924a9784b666fb412b518f2394912f61f4ddf614c5de1691838552600160205260408520600160ff198254161790556105a16040519283926020845260208401916107d4565b0390a280f35b7fcb874ca5a04ca17d10924a9784b666fb412b518f2394912f61f4ddf614c5de16929194505f6105d6916107b3565b5f93909161054f565b6040513d5f823e3d90fd5b5f80fd5b346105ea5760203660031901126105ea576004355f526001602052602060ff60405f2054166040519015158152f35b346105ea5760203660031901126105ea576004356001600160401b0381116105ea5780360360406003198201126105ea57600482013590602219018112156105ea5781016004810135906001600160401b0382116105ea576024019080360382136105ea576024610690930135916107f4565b005b346105ea575f3660031901126105ea576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346105ea575f3660031901126105ea577f00000000000000000000000000000000000000000000000000000000000000006001600160e01b0319168152602090f35b9181601f840112156105ea578235916001600160401b0383116105ea57602083818601950101116105ea57565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b60a081019081106001600160401b0382111761078457604052565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761078457604052565b90601f801991011681019081106001600160401b0382111761078457604052565b908060209392818452848401375f828201840152601f01601f1916010190565b9290919260405161080481610798565b60608152606060208201529280600411806105ea576001600160e01b03197f0000000000000000000000000000000000000000000000000000000000000000811690843516808203610af3575050600482116109b2575b505050815192905f915b84518310156108a75760208360051b86010151908181105f14610896575f52602052600160405f205b920191610865565b905f52602052600160405f2061088e565b602090930180515191945091501561098c5760205f816108f160018060a01b037f000000000000000000000000000000000000000000000000000000000000000016945195610b08565b604051918183925191829101835e8101838152039060025afa156105df575f5191813b156105ea575f916109439160405180958194829363ab750e7560e01b8452606060048501526064840190610745565b907f00000000000000000000000000000000000000000000000000000000000000006024840152604483015203915afa80156105df576109805750565b5f61098a916107b3565b565b505f52600160205260ff60405f205416156109a357565b63439cc0cd60e01b5f5260045ffd5b90919293506105ea57810190602081830360031901126105ea576004810135906001600160401b0382116105ea570190604082820360031901126105ea57604051916109fd83610798565b60048101356001600160401b0381116105ea5760049082010182601f820112156105ea578035906001600160401b038211610784578160051b60405192610a4760208301856107b3565b8352602080840191830101918583116105ea57602001905b828210610ae357505050835260248101356001600160401b0381116105ea57600491010181601f820112156105ea578035906001600160401b0382116107845760405192610ab7601f8401601f1916602001856107b3565b828452602083830101116105ea57815f92602080930183860137830101526020820152905f808061085b565b8135815260209182019101610a5f565b632e2ce35360e21b5f5260045260245260445ffd5b604051907f00000000000000000000000000000000000000000000000000000000000000006020830152600160ff1b6040830152606082015260608152610b506080826107b3565b9056fea164736f6c634300081a000a")]
+    #[sol(rpc, bytecode = "60e0806040523461030f57610ec2803803809161001c8285610313565b833981019060608183031261030f5780516001600160a01b038116810361030f576020820151604083015190926001600160401b03821161030f570183601f8201121561030f578051906001600160401b0382116102fb576040519461008c601f8401601f191660200187610313565b8286526020838301011161030f57815f9260208093018388015e8501015260805260c081905281516001600160401b0381116102fb575f54600181811c911680156102f1575b60208210146102dd57601f811161027b575b50602092601f821160011461021c57928192935f92610211575b50508160011b915f199060031b1c1916175f555b60205f602b6040517f72697363302e536574496e636c7573696f6e526563656970745665726966696581526a72506172616d657465727360a81b8482015260025afa15610206575f602091815190604051908482019283526040820152600160f81b606082015260428152610188606282610313565b604051918291518091835e8101838152039060025afa15610206575f516001600160e01b03191660a052604051610b8b9081610337823960805181818161048f015281816106a701526108f4015260a0518181816106e80152610823015260c05181818161012301528181610517015281816109710152610b390152f35b6040513d5f823e3d90fd5b015190505f806100fe565b601f198216935f8052805f20915f5b868110610263575083600195961061024b575b505050811b015f55610112565b01515f1960f88460031b161c191690555f808061023e565b9192602060018192868501518155019401920161022b565b5f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f830160051c810191602084106102d3575b601f0160051c01905b8181106102c857506100e4565b5f81556001016102bb565b90915081906102b2565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100d2565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b601f909101601f19168101906001600160401b038211908210176102fb5760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c908163053c238d146106d65750806308c84e70146106925780631599ead51461061d57806348cbdfca146105ee5780636691f64714610459578063ab750e75146101d9578063cdc97123146100c55763ffa1ad7414610076575f80fd5b346100c257806003193601126100c257506100be6040516100986040826107b3565b60058152640302e362e360dc1b6020820152604051918291602083526020830190610745565b0390f35b80fd5b50346100c257806003193601126100c25760405190808054908160011c916001811680156101cf575b6020841081146101bb578386529081156101945750600114610155575b6100be8461011b818603826107b3565b6040519182917f00000000000000000000000000000000000000000000000000000000000000008352604060208401526040830190610745565b80805260208120939250905b80821061017a5750909150810160200161011b8261010b565b919260018160209254838588010152019101909291610161565b60ff191660208087019190915292151560051b8501909201925061011b915083905061010b565b634e487b7160e01b83526022600452602483fd5b92607f16926100ee565b50346100c25760603660031901126100c2576004356001600160401b0381116104555761020a903690600401610718565b9082608060405161021a81610769565b82815282602082015260405161022f81610798565b8381528360208201526040820152826060820152015260405161025181610798565b83815283602082015260405161026681610798565b6044358152846020820191818352602082600c6040516b1c9a5cd8cc0b93dd5d1c1d5d60a21b815260025afa15610448576020928251915190516040519185830193845260408301526060820152600160f91b6080820152606281526102cd6082826107b3565b604051918291518091835e8101838152039060025afa1561043d57835190604051906102f882610769565b602435825260208201907fa3acc27117418996340b84e5a90f3ef4c49d22c79e44aad822ec9c313e1eb8e282526040830190815260608301938785526080840190815260208860126040517172697363302e52656365697074436c61696d60701b815260025afa1561043257875194519351925190519082515192600384101561041e575160209081015160408051808401998a52908101979097526060870195909552608086019190915260a08501919091526001600160f81b031960f892831b811660c08601529290911b90911660c4830152600160fa1b60c883015260aa82529185916103e960ca826107b3565b604051918291518091835e8101838152039060025afa1561041357610410918351916107f4565b80f35b6040513d84823e3d90fd5b634e487b7160e01b8a52602160045260248afd5b6040513d89823e3d90fd5b6040513d85823e3d90fd5b50604051903d90823e3d90fd5b5080fd5b50346105ea5760403660031901126105ea576004356024356001600160401b0381116105ea5761048d903690600401610718565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660205f816104c487610b33565b604051918183925191829101835e8101838152039060025afa156105df575f51813b156105ea575f90604051928380809363ab750e7560e01b82526060600483015261051460648301898b6107d4565b907f00000000000000000000000000000000000000000000000000000000000000006024840152604483015203915afa80156105df576105a7575b50907fcb874ca5a04ca17d10924a9784b666fb412b518f2394912f61f4ddf614c5de1691838552600160205260408520600160ff198254161790556105a16040519283926020845260208401916107d4565b0390a280f35b7fcb874ca5a04ca17d10924a9784b666fb412b518f2394912f61f4ddf614c5de16929194505f6105d6916107b3565b5f93909161054f565b6040513d5f823e3d90fd5b5f80fd5b346105ea5760203660031901126105ea576004355f526001602052602060ff60405f2054166040519015158152f35b346105ea5760203660031901126105ea576004356001600160401b0381116105ea5780360360406003198201126105ea57600482013590602219018112156105ea5781016004810135906001600160401b0382116105ea576024019080360382136105ea576024610690930135916107f4565b005b346105ea575f3660031901126105ea576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346105ea575f3660031901126105ea577f00000000000000000000000000000000000000000000000000000000000000006001600160e01b0319168152602090f35b9181601f840112156105ea578235916001600160401b0383116105ea57602083818601950101116105ea57565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b60a081019081106001600160401b0382111761078457604052565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761078457604052565b90601f801991011681019081106001600160401b0382111761078457604052565b908060209392818452848401375f828201840152601f01601f1916010190565b91909160405161080381610798565b60608152606060208201529280600411806105ea576001600160e01b03197f0000000000000000000000000000000000000000000000000000000000000000811690843516808203610b1e575050600482116109dd575b5050506040516020810191674c4541465f54414760c01b83526028820152602881526108876048826107b3565b5190208151925f915b84518310156108d25760208360051b86010151908181105f146108c1575f52602052600160405f205b920191610890565b905f52602052600160405f206108b9565b60209093018051519194509150156109b75760205f8161091c60018060a01b037f000000000000000000000000000000000000000000000000000000000000000016945195610b33565b604051918183925191829101835e8101838152039060025afa156105df575f5191813b156105ea575f9161096e9160405180958194829363ab750e7560e01b8452606060048501526064840190610745565b907f00000000000000000000000000000000000000000000000000000000000000006024840152604483015203915afa80156105df576109ab5750565b5f6109b5916107b3565b565b505f52600160205260ff60405f205416156109ce57565b63439cc0cd60e01b5f5260045ffd5b90919293506105ea57810190602081830360031901126105ea576004810135906001600160401b0382116105ea570190604082820360031901126105ea5760405191610a2883610798565b60048101356001600160401b0381116105ea5760049082010182601f820112156105ea578035906001600160401b038211610784578160051b60405192610a7260208301856107b3565b8352602080840191830101918583116105ea57602001905b828210610b0e57505050835260248101356001600160401b0381116105ea57600491010181601f820112156105ea578035906001600160401b0382116107845760405192610ae2601f8401601f1916602001856107b3565b828452602083830101116105ea57815f92602080930183860137830101526020820152905f808061085a565b8135815260209182019101610a8a565b632e2ce35360e21b5f5260045260245260445ffd5b604051907f00000000000000000000000000000000000000000000000000000000000000006020830152600160ff1b6040830152606082015260608152610b7b6080826107b3565b9056fea164736f6c634300081a000a")]
     contract RiscZeroSetVerifier {
         constructor(address verifier, bytes32 imageId, string memory imageUrl) {}
     }
diff --git a/crates/broker/src/config.rs b/crates/broker/src/config.rs
index a67d574c6c..4911491cc2 100644
--- a/crates/broker/src/config.rs
+++ b/crates/broker/src/config.rs
@@ -49,7 +49,7 @@ mod defaults {
     }
 }
 /// All configuration related to markets mechanics
-#[derive(Deserialize, Serialize)]
+#[derive(Debug, Deserialize, Serialize)]
 #[non_exhaustive]
 pub struct MarketConf {
     /// Mega Cycle price (in native token)
@@ -160,7 +160,7 @@ impl Default for MarketConf {
 }
 
 /// All configuration related to prover (bonsai / Bento) mechanics
-#[derive(Deserialize, Serialize)]
+#[derive(Debug, Deserialize, Serialize)]
 pub struct ProverConf {
     /// Number of retries to poll for proving status. Provides a little durability
     /// for transient failures.
@@ -191,6 +191,10 @@ pub struct ProverConf {
     pub set_builder_guest_path: Option<PathBuf>,
     /// Assessor ELF path
     pub assessor_set_guest_path: Option<PathBuf>,
+    /// Max critical task retries on recoverable failures.
+    ///
+    /// None indicates there are infinite number of retries.
+    pub max_critical_task_retries: Option<u32>,
 }
 
 impl Default for ProverConf {
@@ -205,12 +209,13 @@ impl Default for ProverConf {
             proof_retry_sleep_ms: 1000,
             set_builder_guest_path: None,
             assessor_set_guest_path: None,
+            max_critical_task_retries: None,
         }
     }
 }
 
 /// All configuration related to batching / aggregation
-#[derive(Deserialize, Serialize)]
+#[derive(Debug, Deserialize, Serialize)]
 pub struct BatcherConfig {
     /// Max batch duration before publishing (in seconds)
     pub batch_max_time: Option<u64>,
@@ -261,7 +266,7 @@ impl Default for BatcherConfig {
 }
 
 /// Top level config for the broker service
-#[derive(Deserialize, Serialize, Default)]
+#[derive(Deserialize, Serialize, Default, Debug)]
 pub struct Config {
     /// Market / bidding configurations
     pub market: MarketConf,
@@ -295,7 +300,7 @@ pub enum ConfigErr {
     InvalidConfig,
 }
 
-#[derive(Clone, Default)]
+#[derive(Clone, Default, Debug)]
 pub struct ConfigLock {
     config: Arc<RwLock<Config>>,
 }
diff --git a/crates/broker/src/lib.rs b/crates/broker/src/lib.rs
index a190ffb2bc..7810d6159f 100644
--- a/crates/broker/src/lib.rs
+++ b/crates/broker/src/lib.rs
@@ -28,6 +28,7 @@ use risc0_zkvm::sha::Digest;
 pub use rpc_retry_policy::CustomRetryPolicy;
 use serde::{Deserialize, Serialize};
 use storage::UriHandlerBuilder;
+use task::{RetryPolicy, Supervisor};
 use tokio::task::JoinSet;
 use url::Url;
 
@@ -364,8 +365,10 @@ where
     pub async fn start_service(&self) -> Result<()> {
         let mut supervisor_tasks: JoinSet<Result<()>> = JoinSet::new();
 
+        let config = self.config_watcher.config.clone();
+
         let loopback_blocks = {
-            let config = match self.config_watcher.config.lock_all() {
+            let config = match config.lock_all() {
                 Ok(res) => res,
                 Err(err) => anyhow::bail!("Failed to lock config in watcher: {err:?}"),
             };
@@ -379,8 +382,10 @@ where
         );
 
         let cloned_chain_monitor = chain_monitor.clone();
+        let cloned_config = config.clone();
         supervisor_tasks.spawn(async move {
-            task::supervisor(1, cloned_chain_monitor)
+            Supervisor::new(cloned_chain_monitor, cloned_config)
+                .spawn()
                 .await
                 .context("Failed to start chain monitor")?;
             Ok(())
@@ -401,8 +406,12 @@ where
 
         tracing::debug!("Estimated block time: {block_times}");
 
+        let cloned_config = config.clone();
         supervisor_tasks.spawn(async move {
-            task::supervisor(1, market_monitor).await.context("Failed to start market monitor")?;
+            Supervisor::new(market_monitor, cloned_config)
+                .spawn()
+                .await
+                .context("Failed to start market monitor")?;
             Ok(())
         });
 
@@ -419,8 +428,10 @@ where
                     client.clone(),
                     self.args.private_key.clone(),
                 ));
+            let cloned_config = config.clone();
             supervisor_tasks.spawn(async move {
-                task::supervisor(1, offchain_market_monitor)
+                Supervisor::new(offchain_market_monitor, cloned_config)
+                    .spawn()
                     .await
                     .context("Failed to start offchain market monitor")?;
                 Ok(())
@@ -428,28 +439,24 @@ where
         }
 
         // Construct the prover object interface
-        let prover: provers::ProverObj = if let (Some(bonsai_api_key), Some(bonsai_api_url)) =
+        let prover: provers::ProverObj = if risc0_zkvm::is_dev_mode() {
+            tracing::warn!("WARNING: Running the Broker in dev mode does not generate valid receipts. \
+            Receipts generated from this process are invalid and should never be used in production.");
+            Arc::new(provers::DefaultProver::new())
+        } else if let (Some(bonsai_api_key), Some(bonsai_api_url)) =
             (self.args.bonsai_api_key.as_ref(), self.args.bonsai_api_url.as_ref())
         {
             tracing::info!("Configured to run with Bonsai backend");
             Arc::new(
-                provers::Bonsai::new(
-                    self.config_watcher.config.clone(),
-                    bonsai_api_url.as_ref(),
-                    bonsai_api_key,
-                )
-                .context("Failed to construct Bonsai client")?,
+                provers::Bonsai::new(config.clone(), bonsai_api_url.as_ref(), bonsai_api_key)
+                    .context("Failed to construct Bonsai client")?,
             )
         } else if let Some(bento_api_url) = self.args.bento_api_url.as_ref() {
             tracing::info!("Configured to run with Bento backend");
 
             Arc::new(
-                provers::Bonsai::new(
-                    self.config_watcher.config.clone(),
-                    bento_api_url.as_ref(),
-                    "",
-                )
-                .context("Failed to initialize Bento client")?,
+                provers::Bonsai::new(config.clone(), bento_api_url.as_ref(), "")
+                    .context("Failed to initialize Bento client")?,
             )
         } else {
             Arc::new(provers::DefaultProver::new())
@@ -458,14 +465,18 @@ where
         // Spin up the order picker to pre-flight and find orders to lock
         let order_picker = Arc::new(order_picker::OrderPicker::new(
             self.db.clone(),
-            self.config_watcher.config.clone(),
+            config.clone(),
             prover.clone(),
             self.args.boundless_market_address,
             self.provider.clone(),
             chain_monitor.clone(),
         ));
+        let cloned_config = config.clone();
         supervisor_tasks.spawn(async move {
-            task::supervisor(1, order_picker).await.context("Failed to start order picker")?;
+            Supervisor::new(order_picker, cloned_config)
+                .spawn()
+                .await
+                .context("Failed to start order picker")?;
             Ok(())
         });
 
@@ -473,27 +484,29 @@ where
             self.db.clone(),
             self.provider.clone(),
             chain_monitor.clone(),
-            self.config_watcher.config.clone(),
+            config.clone(),
             block_times,
             self.args.boundless_market_address,
         )?);
+        let cloned_config = config.clone();
         supervisor_tasks.spawn(async move {
-            task::supervisor(1, order_monitor).await.context("Failed to start order monitor")?;
+            Supervisor::new(order_monitor, cloned_config)
+                .spawn()
+                .await
+                .context("Failed to start order monitor")?;
             Ok(())
         });
 
         let proving_service = Arc::new(
-            proving::ProvingService::new(
-                self.db.clone(),
-                prover.clone(),
-                self.config_watcher.config.clone(),
-            )
-            .await
-            .context("Failed to initialize proving service")?,
+            proving::ProvingService::new(self.db.clone(), prover.clone(), config.clone())
+                .await
+                .context("Failed to initialize proving service")?,
         );
 
+        let cloned_config = config.clone();
         supervisor_tasks.spawn(async move {
-            task::supervisor(1, proving_service)
+            Supervisor::new(proving_service, cloned_config)
+                .spawn()
                 .await
                 .context("Failed to start proving service")?;
             Ok(())
@@ -513,29 +526,39 @@ where
                 assessor_img_data.1,
                 self.args.boundless_market_address,
                 prover_addr,
-                self.config_watcher.config.clone(),
+                config.clone(),
                 prover.clone(),
             )
             .await
             .context("Failed to initialize aggregator service")?,
         );
 
+        let cloned_config = config.clone();
         supervisor_tasks.spawn(async move {
-            task::supervisor(1, aggregator).await.context("Failed to start aggregator service")?;
+            Supervisor::new(aggregator, cloned_config)
+                .with_retry_policy(RetryPolicy::CRITICAL_SERVICE)
+                .spawn()
+                .await
+                .context("Failed to start aggregator service")?;
             Ok(())
         });
 
         let submitter = Arc::new(submitter::Submitter::new(
             self.db.clone(),
-            self.config_watcher.config.clone(),
+            config.clone(),
             prover.clone(),
             self.provider.clone(),
             self.args.set_verifier_address,
             self.args.boundless_market_address,
             set_builder_img_data.0,
         )?);
+        let cloned_config = config.clone();
         supervisor_tasks.spawn(async move {
-            task::supervisor(1, submitter).await.context("Failed to start submitter service")?;
+            Supervisor::new(submitter, cloned_config)
+                .with_retry_policy(RetryPolicy::CRITICAL_SERVICE)
+                .spawn()
+                .await
+                .context("Failed to start submitter service")?;
             Ok(())
         });
 
diff --git a/crates/broker/src/offchain_market_monitor.rs b/crates/broker/src/offchain_market_monitor.rs
index ec41f924f2..95b30b9585 100644
--- a/crates/broker/src/offchain_market_monitor.rs
+++ b/crates/broker/src/offchain_market_monitor.rs
@@ -33,7 +33,7 @@ impl OffchainMarketMonitor {
     ) -> Result<(), SupervisorErr> {
         // TODO: retry until it can reestablish a connection.
         tracing::debug!("Connecting to off-chain market: {}", client.base_url);
-        let socket = client.connect_async(signer).await.map_err(SupervisorErr::Fault)?;
+        let socket = client.connect_async(signer).await.map_err(SupervisorErr::Recover)?;
 
         let stream = order_stream(socket);
         tracing::info!("Subscribed to offchain Order stream");
diff --git a/crates/broker/src/task.rs b/crates/broker/src/task.rs
index f40a1db799..17928b19ba 100644
--- a/crates/broker/src/task.rs
+++ b/crates/broker/src/task.rs
@@ -1,13 +1,15 @@
-// Copyright (c) 2024 RISC Zero, Inc.
+// Copyright (c) 2025 RISC Zero, Inc.
 //
 // All rights reserved.
 
-use std::{future::Future, pin::Pin, sync::Arc};
+use std::{future::Future, pin::Pin, sync::Arc, time::Duration};
 
-use anyhow::{Error as AnyhowErr, Result as AnyhowRes};
+use anyhow::{Context, Error as AnyhowErr, Result as AnyhowRes};
 use thiserror::Error;
 use tokio::task::JoinSet;
 
+use crate::config::ConfigLock;
+
 #[derive(Error, Debug)]
 pub enum SupervisorErr {
     /// Restart / replace the task after failure
@@ -25,44 +27,159 @@ pub trait RetryTask {
     fn spawn(&self) -> RetryRes;
 }
 
-/// Start and monitor a RetryTask impl with [count] tasks
-pub async fn supervisor(count: usize, task: Arc<impl RetryTask>) -> AnyhowRes<()> {
-    let mut tasks = JoinSet::new();
+/// Configuration for retry behavior in the supervisor
+#[derive(Debug, Clone)]
+pub(crate) struct RetryPolicy {
+    /// Initial delay between retry attempts
+    pub delay: Duration,
+    /// Multiplier applied to the delay after each retry
+    pub backoff_multiplier: f64,
+    /// Maximum delay between retries, regardless of backoff
+    pub max_delay: Duration,
+    /// Duration after which to reset the retry counter if a task runs successfully
+    pub reset_after: Option<Duration>,
+    pub(crate) critical: bool,
+}
 
-    for i in 0..count {
-        tracing::debug!("Spawning task: {i}");
-        tasks.spawn(task.spawn());
+impl Default for RetryPolicy {
+    fn default() -> Self {
+        Self {
+            delay: std::time::Duration::from_millis(500),
+            backoff_multiplier: 1.5,
+            max_delay: std::time::Duration::from_secs(60),
+            // Reset the backoff after 5 minutes of running without a failure.
+            reset_after: Some(std::time::Duration::from_secs(60 * 5)),
+            critical: false,
+        }
     }
+}
 
-    while let Some(res) = tasks.join_next().await {
-        match res {
-            Ok(task_res) => match task_res {
-                Ok(_) => tracing::debug!("Task exited cleanly"),
-                Err(err) => match err {
-                    SupervisorErr::Recover(err) => {
-                        tracing::warn!(
-                            "Recoverable failure detected: {err:?}, spawning replacement"
-                        );
-                        tasks.spawn(task.spawn());
-                    }
-                    SupervisorErr::Fault(err) => {
-                        tracing::error!("FAULT: Hard failure detect: {err:?}");
-                        anyhow::bail!("Hard failure in supervisor task");
+impl RetryPolicy {
+    pub(crate) const CRITICAL_SERVICE: RetryPolicy = RetryPolicy {
+        delay: std::time::Duration::from_millis(100),
+        backoff_multiplier: 1.5,
+        max_delay: std::time::Duration::from_secs(2),
+        reset_after: Some(std::time::Duration::from_secs(60)),
+        critical: true,
+    };
+}
+
+/// Supervisor for managing and monitoring tasks with retry capabilities
+pub(crate) struct Supervisor<T: RetryTask> {
+    /// The task to be supervised
+    task: Arc<T>,
+    /// Configuration for retry behavior
+    retry_policy: RetryPolicy,
+    config: ConfigLock,
+}
+
+impl<T> Supervisor<T>
+where
+    T: RetryTask + Send,
+{
+    /// Create a new supervisor with a single task
+    pub fn new(task: Arc<T>, config: ConfigLock) -> Self {
+        Self { task, retry_policy: RetryPolicy::default(), config }
+    }
+
+    /// Configure the retry policy
+    pub fn with_retry_policy(mut self, retry_policy: RetryPolicy) -> Self {
+        self.retry_policy = retry_policy;
+        self
+    }
+
+    /// Run the supervisor, monitoring tasks and handling retries
+    pub async fn spawn(self) -> AnyhowRes<()> {
+        let mut tasks = JoinSet::new();
+        let mut retry_count = 0;
+        let mut current_delay = self.retry_policy.delay;
+        let mut last_spawn_time = std::time::Instant::now();
+
+        // Spawn initial task
+        tracing::debug!("Spawning task");
+        tasks.spawn(self.task.spawn());
+
+        while let Some(res) = tasks.join_next().await {
+            // Check if we should reset the retry counter based on how long the task ran
+            if let Some(reset_duration) = self.retry_policy.reset_after {
+                let task_duration = last_spawn_time.elapsed();
+                if task_duration >= reset_duration && retry_count > 0 {
+                    tracing::info!(
+                        "Task ran successfully for {:?}, resetting retry counter from {}",
+                        task_duration,
+                        retry_count
+                    );
+                    retry_count = 0;
+                    current_delay = self.retry_policy.delay; // Reset delay to initial value
+                }
+            }
+            match res {
+                Ok(task_res) => match task_res {
+                    Ok(()) => {
+                        tracing::debug!("Task exited cleanly");
                     }
+                    Err(err) => match err {
+                        SupervisorErr::Recover(err) => {
+                            if self.retry_policy.critical {
+                                let max_retries = {
+                                    let config =
+                                        self.config.lock_all().context("Failed to read config")?;
+                                    config.prover.max_critical_task_retries
+                                };
+
+                                // Check if we've exceeded max retries
+                                if let Some(max) = max_retries {
+                                    if retry_count >= max {
+                                        tracing::error!(
+                                            "Exceeded maximum retries ({max}) for task"
+                                        );
+                                        anyhow::bail!("Exceeded maximum retries for task");
+                                    }
+                                }
+                            }
+
+                            tracing::warn!(
+                                "Recoverable failure detected: {err:?}, spawning replacement (retry {})",
+                                retry_count + 1,
+                            );
+                            tracing::debug!("Waiting {:?} before retry", current_delay);
+
+                            // Instead of sleeping here, wrap the task spawn with a delay
+                            let task_clone = self.task.clone();
+                            let t = task_clone.spawn();
+                            tasks.spawn(async move {
+                                // Apply calculated retry delay before spawning the task
+                                tokio::time::sleep(current_delay).await;
+                                t.await
+                            });
+
+                            retry_count += 1;
+                            last_spawn_time = std::time::Instant::now() + current_delay;
+
+                            // Update the delay for next retry, ensuring it doesn't exceed max_delay
+                            current_delay = current_delay
+                                .mul_f64(self.retry_policy.backoff_multiplier)
+                                .min(self.retry_policy.max_delay);
+                        }
+                        SupervisorErr::Fault(err) => {
+                            tracing::error!("FAULT: Hard failure detected: {err:?}");
+                            anyhow::bail!("Hard failure in supervisor task");
+                        }
+                    },
                 },
-            },
-            Err(err) => {
-                if err.is_cancelled() {
-                    tracing::warn!("Task was canceled, treating it like a clean exit");
-                } else {
-                    tracing::error!("ABORT: supervisor join failed");
-                    anyhow::bail!(err);
+                Err(err) => {
+                    if err.is_cancelled() {
+                        tracing::warn!("Task was canceled, treating it like a clean exit");
+                    } else {
+                        tracing::error!("ABORT: supervisor join failed");
+                        anyhow::bail!(err);
+                    }
                 }
             }
         }
-    }
 
-    Ok(())
+        Ok(())
+    }
 }
 
 #[cfg(test)]
@@ -131,9 +248,9 @@ mod tests {
     #[traced_test]
     async fn supervisor_simple() {
         let task = Arc::new(TestTask::new());
-        let count = 2;
         task.tx(0).await.unwrap();
-        let supervisor_task = supervisor(count, task.clone());
+
+        let supervisor_task = Supervisor::new(task.clone(), ConfigLock::default()).spawn();
 
         task.tx(0).await.unwrap();
         task.tx(0).await.unwrap();
@@ -149,13 +266,44 @@ mod tests {
     #[should_panic(expected = "Hard failure in supervisor task")]
     async fn supervisor_fault() {
         let task = Arc::new(TestTask::new());
-        let count = 2;
         task.tx(0).await.unwrap();
 
-        let supervisor_task = supervisor(count, task.clone());
+        let supervisor_task = Supervisor::new(task.clone(), ConfigLock::default()).spawn();
+
         task.tx(3).await.unwrap();
         task.close();
 
         supervisor_task.await.unwrap();
     }
+
+    #[tokio::test]
+    #[traced_test]
+    async fn supervisor_with_retry_policy() {
+        let task = Arc::new(TestTask::new());
+        let config = ConfigLock::default();
+        config.load_write().unwrap().prover.max_critical_task_retries = Some(3);
+
+        let supervisor_task = Supervisor::new(task.clone(), config)
+            .with_retry_policy(RetryPolicy {
+                delay: std::time::Duration::from_millis(10),
+                backoff_multiplier: 2.0,
+                max_delay: std::time::Duration::from_millis(500),
+                reset_after: None,
+                critical: true,
+            })
+            .spawn();
+
+        // Trigger 3 recoverable errors
+        task.tx(2).await.unwrap();
+        task.tx(2).await.unwrap();
+        task.tx(2).await.unwrap();
+        // Then a successful task
+        task.tx(0).await.unwrap();
+
+        task.tx(2).await.unwrap();
+        task.close();
+
+        let res = supervisor_task.await;
+        assert!(res.unwrap_err().to_string().contains("Exceeded maximum retries for task"));
+    }
 }


Reviews:
user: login: willpote
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T18:51:15Z
user: login: austinabell
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T19:30:31Z
user: login: austinabell
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T19:32:44Z
user: login: willpote
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T20:10:57Z
user: login: austinabell
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T20:25:32Z
user: login: willpote
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T14:09:05Z
user: login: austinabell
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T15:02:41Z
user: login: willpote
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T15:23:47Z
user: login: austinabell
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T20:43:25Z
user: login: willpote
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T13:44:58Z

Review comments:
diff_hunk: @@ -25,44 +25,159 @@ pub trait RetryTask {
     fn spawn(&self) -> RetryRes;
 }
 
-/// Start and monitor a RetryTask impl with [count] tasks
-pub async fn supervisor(count: usize, task: Arc<impl RetryTask>) -> AnyhowRes<()> {
-    let mut tasks = JoinSet::new();
+/// Configuration for retry behavior in the supervisor
+#[derive(Debug, Clone)]
+pub(crate) struct RetryPolicy {
+    /// Initial delay between retry attempts
+    pub delay: std::time::Duration,
+    /// Multiplier applied to the delay after each retry
+    pub backoff_multiplier: f64,
+    /// Maximum delay between retries, regardless of backoff
+    pub max_delay: std::time::Duration,
+    /// Maximum number of consecutive retries before giving up (None for unlimited)
+    pub max_retries: Option<usize>,
+    /// Duration after which to reset the retry counter if a task runs successfully
+    pub reset_after: Option<std::time::Duration>,
+}
 
-    for i in 0..count {
-        tracing::debug!("Spawning task: {i}");
-        tasks.spawn(task.spawn());
+impl Default for RetryPolicy {
+    fn default() -> Self {
+        Self {
+            delay: std::time::Duration::from_millis(500),
+            backoff_multiplier: 1.5,
+            max_delay: std::time::Duration::from_secs(60),
+            max_retries: None,
+            // Reset the backoff after 5 minutes of running without a failure.
+            reset_after: Some(std::time::Duration::from_secs(60 * 5)),
+        }
     }
+}
 
-    while let Some(res) = tasks.join_next().await {
-        match res {
-            Ok(task_res) => match task_res {
-                Ok(_) => tracing::debug!("Task exited cleanly"),
-                Err(err) => match err {
-                    SupervisorErr::Recover(err) => {
-                        tracing::warn!(
-                            "Recoverable failure detected: {err:?}, spawning replacement"
-                        );
-                        tasks.spawn(task.spawn());
-                    }
-                    SupervisorErr::Fault(err) => {
-                        tracing::error!("FAULT: Hard failure detect: {err:?}");
-                        anyhow::bail!("Hard failure in supervisor task");
+impl RetryPolicy {
+    pub(crate) const CRITICAL_SERVICE: RetryPolicy = RetryPolicy {
+        delay: std::time::Duration::from_millis(100),
+        backoff_multiplier: 1.5,
+        max_delay: std::time::Duration::from_secs(2),
+        max_retries: None,
path: crates/broker/src/task.rs
user: login: willpote
body: What do you think about setting a max retries for critical services? My thinking is that If a critical service keeps erroring out and retrying, then after some time we should throw a hard error (which should trigger an alarm) and try a full restart, wdyt?
created_at: 2025-04-16T18:49:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -462,7 +472,7 @@ where
             chain_monitor.clone(),
         ));
         supervisor_tasks.spawn(async move {
-            task::supervisor(1, order_picker).await.context("Failed to start order picker")?;
+            Supervisor::new(order_picker).spawn().await.context("Failed to start order picker")?;
path: crates/broker/src/lib.rs
user: login: willpote
body: Curious the thinking behind which services are critical vs not. I mean isn't every service critical for generating proofs except the off-chain market monitor?
created_at: 2025-04-16T18:51:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -25,44 +25,159 @@ pub trait RetryTask {
     fn spawn(&self) -> RetryRes;
 }
 
-/// Start and monitor a RetryTask impl with [count] tasks
-pub async fn supervisor(count: usize, task: Arc<impl RetryTask>) -> AnyhowRes<()> {
-    let mut tasks = JoinSet::new();
+/// Configuration for retry behavior in the supervisor
+#[derive(Debug, Clone)]
+pub(crate) struct RetryPolicy {
+    /// Initial delay between retry attempts
+    pub delay: std::time::Duration,
+    /// Multiplier applied to the delay after each retry
+    pub backoff_multiplier: f64,
+    /// Maximum delay between retries, regardless of backoff
+    pub max_delay: std::time::Duration,
+    /// Maximum number of consecutive retries before giving up (None for unlimited)
+    pub max_retries: Option<usize>,
+    /// Duration after which to reset the retry counter if a task runs successfully
+    pub reset_after: Option<std::time::Duration>,
+}
 
-    for i in 0..count {
-        tracing::debug!("Spawning task: {i}");
-        tasks.spawn(task.spawn());
+impl Default for RetryPolicy {
+    fn default() -> Self {
+        Self {
+            delay: std::time::Duration::from_millis(500),
+            backoff_multiplier: 1.5,
+            max_delay: std::time::Duration::from_secs(60),
+            max_retries: None,
+            // Reset the backoff after 5 minutes of running without a failure.
+            reset_after: Some(std::time::Duration::from_secs(60 * 5)),
+        }
     }
+}
 
-    while let Some(res) = tasks.join_next().await {
-        match res {
-            Ok(task_res) => match task_res {
-                Ok(_) => tracing::debug!("Task exited cleanly"),
-                Err(err) => match err {
-                    SupervisorErr::Recover(err) => {
-                        tracing::warn!(
-                            "Recoverable failure detected: {err:?}, spawning replacement"
-                        );
-                        tasks.spawn(task.spawn());
-                    }
-                    SupervisorErr::Fault(err) => {
-                        tracing::error!("FAULT: Hard failure detect: {err:?}");
-                        anyhow::bail!("Hard failure in supervisor task");
+impl RetryPolicy {
+    pub(crate) const CRITICAL_SERVICE: RetryPolicy = RetryPolicy {
+        delay: std::time::Duration::from_millis(100),
+        backoff_multiplier: 1.5,
+        max_delay: std::time::Duration::from_secs(2),
+        max_retries: None,
path: crates/broker/src/task.rs
user: login: austinabell
body: The fault would take down the node. It only would retry if however the broker is configured to restart completely. I set it like this as a default because these services are cheap to restart, and also don't have any components that will behave differently if faulting and restarting from scratch, but it's also possible that I'm missing some side effects. Happy to add a max retries on this, but also worried that causing a full restart might cause more delays which puts stake at risk. I don't hold this intuition strongly, and tradeoff feels roughly equal, so if you ack this and still feel that way, I'll make the change.
created_at: 2025-04-16T19:30:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -462,7 +472,7 @@ where
             chain_monitor.clone(),
         ));
         supervisor_tasks.spawn(async move {
-            task::supervisor(1, order_picker).await.context("Failed to start order picker")?;
+            Supervisor::new(order_picker).spawn().await.context("Failed to start order picker")?;
path: crates/broker/src/lib.rs
user: login: austinabell
body: Critical might not be the best naming, but I added those to the ones I did because:
- It affects already locked stake, not as urgent for sth like order picker because especially on a failure there isn't a rush to get the service up again asap
- Those "critical" ones are cheap to startup, and don't have external calls to make to initialize, so there isn't really a reason to wait too long before retrying (keeping as close to immediately restarting as it was before)
created_at: 2025-04-16T19:32:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -25,44 +25,159 @@ pub trait RetryTask {
     fn spawn(&self) -> RetryRes;
 }
 
-/// Start and monitor a RetryTask impl with [count] tasks
-pub async fn supervisor(count: usize, task: Arc<impl RetryTask>) -> AnyhowRes<()> {
-    let mut tasks = JoinSet::new();
+/// Configuration for retry behavior in the supervisor
+#[derive(Debug, Clone)]
+pub(crate) struct RetryPolicy {
+    /// Initial delay between retry attempts
+    pub delay: std::time::Duration,
+    /// Multiplier applied to the delay after each retry
+    pub backoff_multiplier: f64,
+    /// Maximum delay between retries, regardless of backoff
+    pub max_delay: std::time::Duration,
+    /// Maximum number of consecutive retries before giving up (None for unlimited)
+    pub max_retries: Option<usize>,
+    /// Duration after which to reset the retry counter if a task runs successfully
+    pub reset_after: Option<std::time::Duration>,
+}
 
-    for i in 0..count {
-        tracing::debug!("Spawning task: {i}");
-        tasks.spawn(task.spawn());
+impl Default for RetryPolicy {
+    fn default() -> Self {
+        Self {
+            delay: std::time::Duration::from_millis(500),
+            backoff_multiplier: 1.5,
+            max_delay: std::time::Duration::from_secs(60),
+            max_retries: None,
+            // Reset the backoff after 5 minutes of running without a failure.
+            reset_after: Some(std::time::Duration::from_secs(60 * 5)),
+        }
     }
+}
 
-    while let Some(res) = tasks.join_next().await {
-        match res {
-            Ok(task_res) => match task_res {
-                Ok(_) => tracing::debug!("Task exited cleanly"),
-                Err(err) => match err {
-                    SupervisorErr::Recover(err) => {
-                        tracing::warn!(
-                            "Recoverable failure detected: {err:?}, spawning replacement"
-                        );
-                        tasks.spawn(task.spawn());
-                    }
-                    SupervisorErr::Fault(err) => {
-                        tracing::error!("FAULT: Hard failure detect: {err:?}");
-                        anyhow::bail!("Hard failure in supervisor task");
+impl RetryPolicy {
+    pub(crate) const CRITICAL_SERVICE: RetryPolicy = RetryPolicy {
+        delay: std::time::Duration::from_millis(100),
+        backoff_multiplier: 1.5,
+        max_delay: std::time::Duration::from_secs(2),
+        max_retries: None,
path: crates/broker/src/task.rs
user: login: willpote
body: Hmm yeah. In theory the stake at risk could go both ways- like if the submitter keeps crashing, but the order_monitor keeps locking orders, we might actually want to fully error out in that case. But I see your point.

Maybe it should be configurable and default to something high like 10? In our case I think we'd likely want to have some max retry set where if some service continues to keep crashing we error out and let ECS handle restarting the broker from scratch. But I could see some provers may have a setup that doesn't handle restarting for them.


created_at: 2025-04-16T20:10:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -25,44 +25,159 @@ pub trait RetryTask {
     fn spawn(&self) -> RetryRes;
 }
 
-/// Start and monitor a RetryTask impl with [count] tasks
-pub async fn supervisor(count: usize, task: Arc<impl RetryTask>) -> AnyhowRes<()> {
-    let mut tasks = JoinSet::new();
+/// Configuration for retry behavior in the supervisor
+#[derive(Debug, Clone)]
+pub(crate) struct RetryPolicy {
+    /// Initial delay between retry attempts
+    pub delay: std::time::Duration,
+    /// Multiplier applied to the delay after each retry
+    pub backoff_multiplier: f64,
+    /// Maximum delay between retries, regardless of backoff
+    pub max_delay: std::time::Duration,
+    /// Maximum number of consecutive retries before giving up (None for unlimited)
+    pub max_retries: Option<usize>,
+    /// Duration after which to reset the retry counter if a task runs successfully
+    pub reset_after: Option<std::time::Duration>,
+}
 
-    for i in 0..count {
-        tracing::debug!("Spawning task: {i}");
-        tasks.spawn(task.spawn());
+impl Default for RetryPolicy {
+    fn default() -> Self {
+        Self {
+            delay: std::time::Duration::from_millis(500),
+            backoff_multiplier: 1.5,
+            max_delay: std::time::Duration::from_secs(60),
+            max_retries: None,
+            // Reset the backoff after 5 minutes of running without a failure.
+            reset_after: Some(std::time::Duration::from_secs(60 * 5)),
+        }
     }
+}
 
-    while let Some(res) = tasks.join_next().await {
-        match res {
-            Ok(task_res) => match task_res {
-                Ok(_) => tracing::debug!("Task exited cleanly"),
-                Err(err) => match err {
-                    SupervisorErr::Recover(err) => {
-                        tracing::warn!(
-                            "Recoverable failure detected: {err:?}, spawning replacement"
-                        );
-                        tasks.spawn(task.spawn());
-                    }
-                    SupervisorErr::Fault(err) => {
-                        tracing::error!("FAULT: Hard failure detect: {err:?}");
-                        anyhow::bail!("Hard failure in supervisor task");
+impl RetryPolicy {
+    pub(crate) const CRITICAL_SERVICE: RetryPolicy = RetryPolicy {
+        delay: std::time::Duration::from_millis(100),
+        backoff_multiplier: 1.5,
+        max_delay: std::time::Duration::from_secs(2),
+        max_retries: None,
path: crates/broker/src/task.rs
user: login: austinabell
body: That seems reasonable, this is ~9s of retries, which should probably be more than enough for any temporal db issue and short enough to avoid executing and locking orders

[`ff3b885` (#526)](https://github.com/boundless-xyz/boundless/pull/526/commits/ff3b8856296befa5e475fae1857dc16d0b7ff82b)
created_at: 2025-04-16T20:25:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -25,44 +25,159 @@ pub trait RetryTask {
     fn spawn(&self) -> RetryRes;
 }
 
-/// Start and monitor a RetryTask impl with [count] tasks
-pub async fn supervisor(count: usize, task: Arc<impl RetryTask>) -> AnyhowRes<()> {
-    let mut tasks = JoinSet::new();
+/// Configuration for retry behavior in the supervisor
+#[derive(Debug, Clone)]
+pub(crate) struct RetryPolicy {
+    /// Initial delay between retry attempts
+    pub delay: std::time::Duration,
+    /// Multiplier applied to the delay after each retry
+    pub backoff_multiplier: f64,
+    /// Maximum delay between retries, regardless of backoff
+    pub max_delay: std::time::Duration,
+    /// Maximum number of consecutive retries before giving up (None for unlimited)
+    pub max_retries: Option<usize>,
+    /// Duration after which to reset the retry counter if a task runs successfully
+    pub reset_after: Option<std::time::Duration>,
+}
 
-    for i in 0..count {
-        tracing::debug!("Spawning task: {i}");
-        tasks.spawn(task.spawn());
+impl Default for RetryPolicy {
+    fn default() -> Self {
+        Self {
+            delay: std::time::Duration::from_millis(500),
+            backoff_multiplier: 1.5,
+            max_delay: std::time::Duration::from_secs(60),
+            max_retries: None,
+            // Reset the backoff after 5 minutes of running without a failure.
+            reset_after: Some(std::time::Duration::from_secs(60 * 5)),
+        }
     }
+}
 
-    while let Some(res) = tasks.join_next().await {
-        match res {
-            Ok(task_res) => match task_res {
-                Ok(_) => tracing::debug!("Task exited cleanly"),
-                Err(err) => match err {
-                    SupervisorErr::Recover(err) => {
-                        tracing::warn!(
-                            "Recoverable failure detected: {err:?}, spawning replacement"
-                        );
-                        tasks.spawn(task.spawn());
-                    }
-                    SupervisorErr::Fault(err) => {
-                        tracing::error!("FAULT: Hard failure detect: {err:?}");
-                        anyhow::bail!("Hard failure in supervisor task");
+impl RetryPolicy {
+    pub(crate) const CRITICAL_SERVICE: RetryPolicy = RetryPolicy {
+        delay: std::time::Duration::from_millis(100),
+        backoff_multiplier: 1.5,
+        max_delay: std::time::Duration::from_secs(2),
+        max_retries: None,
path: crates/broker/src/task.rs
user: login: willpote
body: Ah sorry, what I was actually proposing was that it could be configurable as part of `broker.toml`
created_at: 2025-04-17T14:09:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -25,44 +25,159 @@ pub trait RetryTask {
     fn spawn(&self) -> RetryRes;
 }
 
-/// Start and monitor a RetryTask impl with [count] tasks
-pub async fn supervisor(count: usize, task: Arc<impl RetryTask>) -> AnyhowRes<()> {
-    let mut tasks = JoinSet::new();
+/// Configuration for retry behavior in the supervisor
+#[derive(Debug, Clone)]
+pub(crate) struct RetryPolicy {
+    /// Initial delay between retry attempts
+    pub delay: std::time::Duration,
+    /// Multiplier applied to the delay after each retry
+    pub backoff_multiplier: f64,
+    /// Maximum delay between retries, regardless of backoff
+    pub max_delay: std::time::Duration,
+    /// Maximum number of consecutive retries before giving up (None for unlimited)
+    pub max_retries: Option<usize>,
+    /// Duration after which to reset the retry counter if a task runs successfully
+    pub reset_after: Option<std::time::Duration>,
+}
 
-    for i in 0..count {
-        tracing::debug!("Spawning task: {i}");
-        tasks.spawn(task.spawn());
+impl Default for RetryPolicy {
+    fn default() -> Self {
+        Self {
+            delay: std::time::Duration::from_millis(500),
+            backoff_multiplier: 1.5,
+            max_delay: std::time::Duration::from_secs(60),
+            max_retries: None,
+            // Reset the backoff after 5 minutes of running without a failure.
+            reset_after: Some(std::time::Duration::from_secs(60 * 5)),
+        }
     }
+}
 
-    while let Some(res) = tasks.join_next().await {
-        match res {
-            Ok(task_res) => match task_res {
-                Ok(_) => tracing::debug!("Task exited cleanly"),
-                Err(err) => match err {
-                    SupervisorErr::Recover(err) => {
-                        tracing::warn!(
-                            "Recoverable failure detected: {err:?}, spawning replacement"
-                        );
-                        tasks.spawn(task.spawn());
-                    }
-                    SupervisorErr::Fault(err) => {
-                        tracing::error!("FAULT: Hard failure detect: {err:?}");
-                        anyhow::bail!("Hard failure in supervisor task");
+impl RetryPolicy {
+    pub(crate) const CRITICAL_SERVICE: RetryPolicy = RetryPolicy {
+        delay: std::time::Duration::from_millis(100),
+        backoff_multiplier: 1.5,
+        max_delay: std::time::Duration::from_secs(2),
+        max_retries: None,
path: crates/broker/src/task.rs
user: login: austinabell
body: All parts of this, or just the retry?
created_at: 2025-04-17T15:02:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -25,44 +25,159 @@ pub trait RetryTask {
     fn spawn(&self) -> RetryRes;
 }
 
-/// Start and monitor a RetryTask impl with [count] tasks
-pub async fn supervisor(count: usize, task: Arc<impl RetryTask>) -> AnyhowRes<()> {
-    let mut tasks = JoinSet::new();
+/// Configuration for retry behavior in the supervisor
+#[derive(Debug, Clone)]
+pub(crate) struct RetryPolicy {
+    /// Initial delay between retry attempts
+    pub delay: std::time::Duration,
+    /// Multiplier applied to the delay after each retry
+    pub backoff_multiplier: f64,
+    /// Maximum delay between retries, regardless of backoff
+    pub max_delay: std::time::Duration,
+    /// Maximum number of consecutive retries before giving up (None for unlimited)
+    pub max_retries: Option<usize>,
+    /// Duration after which to reset the retry counter if a task runs successfully
+    pub reset_after: Option<std::time::Duration>,
+}
 
-    for i in 0..count {
-        tracing::debug!("Spawning task: {i}");
-        tasks.spawn(task.spawn());
+impl Default for RetryPolicy {
+    fn default() -> Self {
+        Self {
+            delay: std::time::Duration::from_millis(500),
+            backoff_multiplier: 1.5,
+            max_delay: std::time::Duration::from_secs(60),
+            max_retries: None,
+            // Reset the backoff after 5 minutes of running without a failure.
+            reset_after: Some(std::time::Duration::from_secs(60 * 5)),
+        }
     }
+}
 
-    while let Some(res) = tasks.join_next().await {
-        match res {
-            Ok(task_res) => match task_res {
-                Ok(_) => tracing::debug!("Task exited cleanly"),
-                Err(err) => match err {
-                    SupervisorErr::Recover(err) => {
-                        tracing::warn!(
-                            "Recoverable failure detected: {err:?}, spawning replacement"
-                        );
-                        tasks.spawn(task.spawn());
-                    }
-                    SupervisorErr::Fault(err) => {
-                        tracing::error!("FAULT: Hard failure detect: {err:?}");
-                        anyhow::bail!("Hard failure in supervisor task");
+impl RetryPolicy {
+    pub(crate) const CRITICAL_SERVICE: RetryPolicy = RetryPolicy {
+        delay: std::time::Duration::from_millis(100),
+        backoff_multiplier: 1.5,
+        max_delay: std::time::Duration::from_secs(2),
+        max_retries: None,
path: crates/broker/src/task.rs
user: login: willpote
body: I was thinking all of it, though as optional fields. Essentially wanted to make it possible for each prover to configure whether to retry critical services indefinitely or exit out
created_at: 2025-04-17T15:23:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -25,44 +25,159 @@ pub trait RetryTask {
     fn spawn(&self) -> RetryRes;
 }
 
-/// Start and monitor a RetryTask impl with [count] tasks
-pub async fn supervisor(count: usize, task: Arc<impl RetryTask>) -> AnyhowRes<()> {
-    let mut tasks = JoinSet::new();
+/// Configuration for retry behavior in the supervisor
+#[derive(Debug, Clone)]
+pub(crate) struct RetryPolicy {
+    /// Initial delay between retry attempts
+    pub delay: std::time::Duration,
+    /// Multiplier applied to the delay after each retry
+    pub backoff_multiplier: f64,
+    /// Maximum delay between retries, regardless of backoff
+    pub max_delay: std::time::Duration,
+    /// Maximum number of consecutive retries before giving up (None for unlimited)
+    pub max_retries: Option<usize>,
+    /// Duration after which to reset the retry counter if a task runs successfully
+    pub reset_after: Option<std::time::Duration>,
+}
 
-    for i in 0..count {
-        tracing::debug!("Spawning task: {i}");
-        tasks.spawn(task.spawn());
+impl Default for RetryPolicy {
+    fn default() -> Self {
+        Self {
+            delay: std::time::Duration::from_millis(500),
+            backoff_multiplier: 1.5,
+            max_delay: std::time::Duration::from_secs(60),
+            max_retries: None,
+            // Reset the backoff after 5 minutes of running without a failure.
+            reset_after: Some(std::time::Duration::from_secs(60 * 5)),
+        }
     }
+}
 
-    while let Some(res) = tasks.join_next().await {
-        match res {
-            Ok(task_res) => match task_res {
-                Ok(_) => tracing::debug!("Task exited cleanly"),
-                Err(err) => match err {
-                    SupervisorErr::Recover(err) => {
-                        tracing::warn!(
-                            "Recoverable failure detected: {err:?}, spawning replacement"
-                        );
-                        tasks.spawn(task.spawn());
-                    }
-                    SupervisorErr::Fault(err) => {
-                        tracing::error!("FAULT: Hard failure detect: {err:?}");
-                        anyhow::bail!("Hard failure in supervisor task");
+impl RetryPolicy {
+    pub(crate) const CRITICAL_SERVICE: RetryPolicy = RetryPolicy {
+        delay: std::time::Duration::from_millis(100),
+        backoff_multiplier: 1.5,
+        max_delay: std::time::Duration::from_secs(2),
+        max_retries: None,
path: crates/broker/src/task.rs
user: login: austinabell
body: I can try to add what seems essential. 8+ configuration options for this seems like a pain to maintain, unless some user asks for it.
created_at: 2025-04-17T20:43:25Z
author_association: CONTRIBUTOR

PR comments:
user: login: linear[bot]
created_at: 2025-04-16T16:50:58Z
body: <p><a href="https://linear.app/risczero/issue/BM-770/support-running-a-prover-without-an-order-stream-url">BM-770 Support running a prover without an order stream URL</a></p>
author_association: NONE
user: login: linear[bot]
created_at: 2025-04-16T16:51:48Z
body: <p><a href="https://linear.app/risczero/issue/BM-752/improve-handling-of-new-order-stream-deployments-in-the-prover">BM-752 Improve handling of new order stream deployments in the prover</a></p>
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-17T14:10:55Z
body: 🚀 Documentation Preview

Deployment URL: https://boundless-documentation-ocq0adlhn-risczero.vercel.app

_Updated at: 2025-04-18 14:05:23 UTC_
author_association: NONE