diff --git a/sdks/uniswapx-sdk/abis/V3DutchOrderReactor.json b/sdks/uniswapx-sdk/abis/V3DutchOrderReactor.json new file mode 100644 index 000000000..f1acfdd37 --- /dev/null +++ b/sdks/uniswapx-sdk/abis/V3DutchOrderReactor.json @@ -0,0 +1 @@ +{"abi":[{"type":"constructor","inputs":[{"name":"_permit2","type":"address","internalType":"contract IPermit2"},{"name":"_protocolFeeOwner","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"receive","stateMutability":"payable"},{"type":"function","name":"execute","inputs":[{"name":"order","type":"tuple","internalType":"struct SignedOrder","components":[{"name":"order","type":"bytes","internalType":"bytes"},{"name":"sig","type":"bytes","internalType":"bytes"}]}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"executeBatch","inputs":[{"name":"orders","type":"tuple[]","internalType":"struct SignedOrder[]","components":[{"name":"order","type":"bytes","internalType":"bytes"},{"name":"sig","type":"bytes","internalType":"bytes"}]}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"executeBatchWithCallback","inputs":[{"name":"orders","type":"tuple[]","internalType":"struct SignedOrder[]","components":[{"name":"order","type":"bytes","internalType":"bytes"},{"name":"sig","type":"bytes","internalType":"bytes"}]},{"name":"callbackData","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"executeWithCallback","inputs":[{"name":"order","type":"tuple","internalType":"struct SignedOrder","components":[{"name":"order","type":"bytes","internalType":"bytes"},{"name":"sig","type":"bytes","internalType":"bytes"}]},{"name":"callbackData","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"feeController","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IProtocolFeeController"}],"stateMutability":"view"},{"type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"permit2","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IPermit2"}],"stateMutability":"view"},{"type":"function","name":"setProtocolFeeController","inputs":[{"name":"_newFeeController","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"transferOwnership","inputs":[{"name":"newOwner","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"Fill","inputs":[{"name":"orderHash","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"filler","type":"address","indexed":true,"internalType":"address"},{"name":"swapper","type":"address","indexed":true,"internalType":"address"},{"name":"nonce","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"name":"user","type":"address","indexed":true,"internalType":"address"},{"name":"newOwner","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"ProtocolFeeControllerSet","inputs":[{"name":"oldFeeController","type":"address","indexed":false,"internalType":"address"},{"name":"newFeeController","type":"address","indexed":false,"internalType":"address"}],"anonymous":false},{"type":"error","name":"DeadlineReached","inputs":[]},{"type":"error","name":"DuplicateFeeOutput","inputs":[{"name":"duplicateToken","type":"address","internalType":"address"}]},{"type":"error","name":"FeeTooLarge","inputs":[{"name":"token","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"recipient","type":"address","internalType":"address"}]},{"type":"error","name":"IndexOutOfBounds","inputs":[]},{"type":"error","name":"InputAndOutputFees","inputs":[]},{"type":"error","name":"InvalidCosignature","inputs":[]},{"type":"error","name":"InvalidCosignerInput","inputs":[]},{"type":"error","name":"InvalidCosignerOutput","inputs":[]},{"type":"error","name":"InvalidDecayCurve","inputs":[]},{"type":"error","name":"InvalidFeeToken","inputs":[{"name":"feeToken","type":"address","internalType":"address"}]},{"type":"error","name":"InvalidReactor","inputs":[]},{"type":"error","name":"NativeTransferFailed","inputs":[]},{"type":"error","name":"NoExclusiveOverride","inputs":[]}],"bytecode":{"object":"0x60a06040523480156200001157600080fd5b50604051620044c4380380620044c48339810160408190526200003491620000b8565b600080546001600160a01b0319166001600160a01b03831690811782556040518492849283928392907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350506001600255506001600160a01b031660805250620000f79050565b6001600160a01b0381168114620000b557600080fd5b50565b60008060408385031215620000cc57600080fd5b8251620000d9816200009f565b6020840151909250620000ec816200009f565b809150509250929050565b6080516143ab620001196000396000818160e00152611a5901526143ab6000f3fe60806040526004361061009a5760003560e01c80632d771389116100695780636999b3771161004e5780636999b377146101715780638da5cb5b1461019e578063f2fde38b146101cb57600080fd5b80632d7713891461013e5780633f62192e1461015e57600080fd5b80630d335884146100a65780630d7a16c3146100bb57806312261ee7146100ce57806313fb72c71461012b57600080fd5b366100a157005b600080fd5b6100b96100b4366004612e6a565b6101eb565b005b6100b96100c9366004612f18565b610364565b3480156100da57600080fd5b506101027f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100b9610139366004612f5a565b6104c5565b34801561014a57600080fd5b506100b9610159366004612ff8565b610683565b6100b961016c366004613015565b61078f565b34801561017d57600080fd5b506001546101029073ffffffffffffffffffffffffffffffffffffffff1681565b3480156101aa57600080fd5b506000546101029073ffffffffffffffffffffffffffffffffffffffff1681565b3480156101d757600080fd5b506100b96101e6366004612ff8565b610894565b6101f3610985565b604080516001808252818301909252600091816020015b6040805161016081018252600060a0820181815260c0830182905260e0830182905261010083018290526101208301829052606061014084018190529083528351808201855282815260208082018490528186018490528085019190915293830181905280830152608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161020a5790505090506102b2846109f6565b816000815181106102c5576102c5613079565b60200260200101819052506102d981610b67565b6040517f585da628000000000000000000000000000000000000000000000000000000008152339063585da628906103199084908790879060040161327c565b600060405180830381600087803b15801561033357600080fd5b505af1158015610347573d6000803e3d6000fd5b5050505061035481610bb8565b5061035f6001600255565b505050565b61036c610985565b8060008167ffffffffffffffff8111156103885761038861304a565b60405190808252806020026020018201604052801561044357816020015b6040805161016081018252600060a0820181815260c0830182905260e0830182905261010083018290526101208301829052606061014084018190529083528351808201855282815260208082018490528186018490528085019190915293830181905280830152608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816103a65790505b50905060005b828110156104a25761047d85858381811061046657610466613079565b90506020028101906104789190613342565b6109f6565b82828151811061048f5761048f613079565b6020908102919091010152600101610449565b506104ac81610b67565b6104b581610bb8565b50506104c16001600255565b5050565b6104cd610985565b8260008167ffffffffffffffff8111156104e9576104e961304a565b6040519080825280602002602001820160405280156105a457816020015b6040805161016081018252600060a0820181815260c0830182905260e0830182905261010083018290526101208301829052606061014084018190529083528351808201855282815260208082018490528186018490528085019190915293830181905280830152608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816105075790505b50905060005b828110156105ec576105c787878381811061046657610466613079565b8282815181106105d9576105d9613079565b60209081029190910101526001016105aa565b506105f681610b67565b6040517f585da628000000000000000000000000000000000000000000000000000000008152339063585da628906106369084908890889060040161327c565b600060405180830381600087803b15801561065057600080fd5b505af1158015610664573d6000803e3d6000fd5b5050505061067181610bb8565b505061067d6001600255565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610709576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527fb904ae9529e373e48bc82df4326cceaf1b4c472babf37f5b7dec46fecc6b53e0910160405180910390a15050565b610797610985565b604080516001808252818301909252600091816020015b6040805161016081018252600060a0820181815260c0830182905260e0830182905261010083018290526101208301829052606061014084018190529083528351808201855282815260208082018490528186018490528085019190915293830181905280830152608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816107ae579050509050610856826109f6565b8160008151811061086957610869613079565b602002602001018190525061087d81610b67565b61088681610bb8565b506108916001600255565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610700565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b60028054036109f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610700565b60028055565b6040805161016081018252600060a0820181815260c0830182905260e083018290526101008301829052610120830182905260606101408401819052908352835180820185528281526020808201849052818601849052840152928201839052828201929092526080810182905290610a6f8380613380565b810190610a7c919061394e565b90506000610a8982610d0b565b9050610a958183610ff1565b610a9e8261104d565b610aa7826111b1565b6040805160a080820190925283518152908301515160608401516020830191610ad091906112e0565b815260a0840151516080850151602090920191610aec91611374565b8152602001858060200190610b019190613380565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602090810183905260a0840151908101518151604090920151929550610b6092869290611459565b5050919050565b805160005b8181101561035f576000838281518110610b8857610b88613079565b60200260200101519050610b9b81611466565b610ba58133611956565b610baf8133611a57565b50600101610b6c565b805160005b81811015610cfa576000838281518110610bd957610bd9613079565b602002602001015190506000816040015151905060005b81811015610c5a57600083604001518281518110610c1057610c10613079565b60200260200101519050610c5181604001518260200151836000015173ffffffffffffffffffffffffffffffffffffffff16611e599092919063ffffffff16565b50600101610bf0565b5081600001516020015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16868581518110610ca357610ca3613079565b6020026020010151608001517f78ad7ec0e9f89e74012afa58738b6b661c024cb0fd185ee2f616c0a28924bd66856000015160400151604051610ce891815260200190565b60405180910390a45050600101610bbd565b5047156104c1576104c13347611ea0565b6040517f563344757463684f72646572280000000000000000000000000000000000000060208201527f4f72646572496e666f20696e666f2c0000000000000000000000000000000000602d8201527f6164647265737320636f7369676e65722c000000000000000000000000000000603c8201527f75696e74323536207374617274696e67426173654665652c0000000000000000604d8201527f56334475746368496e7075742062617365496e7075742c00000000000000000060658201527f563344757463684f75747075745b5d20626173654f7574707574732900000000607c820152600090609801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f4e6f6e6c696e656172447574636844656361792800000000000000000000000060208301527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060348301527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000604b83015290606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815260c08301909152608d8083529091906142e96020830139604051602001610eee90613a66565b604051602081830303815290604052604051602001610f0c90613b78565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610f4b9594939291602001613cb0565b60405160208183030381529060405280519060200120610f6e8360000151611f3a565b83602001518460400151610f858660600151611fd4565b610f928760800151612125565b60408051602081019790975286019490945273ffffffffffffffffffffffffffffffffffffffff9092166060850152608084015260a083015260c082015260e0015b604051602081830303815290604052805190602001209050919050565b805160600151421115611030576040517fb08ce5b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101516104c19061104383856121c6565b8360c00151612239565b60a081015160600151156110b9578060600151602001518160a001516060015111156110a5576040517fac9143e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a081015160609081015190820151602001525b8060800151518160a00151608001515114611100576040517fa305df8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60808101515160005b8181101561035f5760008360800151828151811061112957611129613079565b6020026020010151905060008460a0015160800151838151811061114f5761114f613079565b60200260200101519050806000146111a757816020015181101561119f576040517fa305df8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602082018190525b5050600101611109565b60006111ca82604001514861236190919063ffffffff16565b9050816060015160800151600014611236576000633b9aca00828460600151608001516111f79190613d4a565b6112019190613d96565b905061122b81600085606001516060015186606001516020015161239c909392919063ffffffff16565b606084015160200152505b60808201515160005b8181101561067d5760008460800151828151811061125f5761125f613079565b602002602001015190508060a001516000146112d7576000633b9aca00858360a0015161128c9190613d4a565b6112969190613d96565b608083015160208401519192506112d0919083907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6123bc565b6020830152505b5060010161123f565b61131a6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b600061133684604001518560200151856000886060015161244e565b6040805160608082018352875173ffffffffffffffffffffffffffffffffffffffff1682526020820193909352959091015190850152509192915050565b81516060908067ffffffffffffffff8111156113925761139261304a565b6040519080825280602002602001820160405280156113fb57816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816113b05790505b50915060005b818110156114515761142c85828151811061141e5761141e613079565b602002602001015185612518565b83828151811061143e5761143e613079565b6020908102919091010152600101611401565b505092915050565b61067d84848484436125ca565b60015473ffffffffffffffffffffffffffffffffffffffff166114865750565b6001546040517f8aa6cf0300000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff1690638aa6cf03906114dd908590600401613e25565b600060405180830381865afa1580156114fa573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115409190810190613e38565b60408301515181519192509060006115588284613f08565b67ffffffffffffffff8111156115705761157061304a565b6040519080825280602002602001820160405280156115d957816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161158e5790505b50905060005b8381101561162a57856040015181815181106115fd576115fd613079565b602002602001015182828151811061161757611617613079565b60209081029190910101526001016115df565b5060008060005b8481101561194557600087828151811061164d5761164d613079565b6020026020010151905060005b8281101561170b5788818151811061167457611674613079565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff16036117035781516040517ffff0830300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610700565b60010161165a565b506000805b888110156117cc5760008b60400151828151811061173057611730613079565b60200260200101519050836000015173ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff16036117c35785156117ad576040517fedc7e2e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101516117bc9084613f08565b9250600196505b50600101611710565b50815160208b01515173ffffffffffffffffffffffffffffffffffffffff91821691160361184557841561182c576040517fedc7e2e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808b0151015161183e9082613f08565b9050600193505b8060000361189a5781516040517feddf07f500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610700565b6118a8816005612710612673565b8260200151111561191b578151602083015160408085015190517f82e7565600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841660048201526024810192909252919091166044820152606401610700565b8186848a018151811061193057611930613079565b60209081029190910101525050600101611631565b505050604090940193909352505050565b81515173ffffffffffffffffffffffffffffffffffffffff1630146119a7576040517f4ddf4a6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81516080015173ffffffffffffffffffffffffffffffffffffffff16156104c1578151608001516040517f6e84ba2b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690636e84ba2b90611a239084908690600401613f1b565b60006040518083038186803b158015611a3b57600080fd5b505afa158015611a4f573d6000803e3d6000fd5b505050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663137c29fe611b17846040805160a0810182526000606082018181526080830182905282526020820181905291810191909152506040805160a081018252602080840180515173ffffffffffffffffffffffffffffffffffffffff1660608085019182529151850151608085015283528451840151918301919091529251909201519082015290565b6040805180820182526000808252602091820152815180830190925273ffffffffffffffffffffffffffffffffffffffff8616825280870151810151908201528560000151602001518660800151604051602001611be4907f4e6f6e6c696e656172447574636844656361792800000000000000000000000081527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060148201527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000602b82015260440190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815260c08301909152608d8083529091906142e960208301396040518060600160405280602e81526020016142bb602e9139604051602001611c4e90613a66565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f563344757463684f72646572280000000000000000000000000000000000000060208401527f4f72646572496e666f20696e666f2c0000000000000000000000000000000000602d8401527f6164647265737320636f7369676e65722c000000000000000000000000000000603c8401527f75696e74323536207374617274696e67426173654665652c0000000000000000604d8401527f56334475746368496e7075742062617365496e7075742c00000000000000000060658401527f563344757463684f75747075745b5d20626173654f7574707574732900000000607c840152815160788185030181526098840190925291611d7e9060b801613b78565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611dbe969594939291602001613f4a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905260608a01517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b168352611e2b9695949392600401613ffd565b600060405180830381600087803b158015611e4557600080fd5b505af1158015611a4f573d6000803e3d6000fd5b73ffffffffffffffffffffffffffffffffffffffff8316611e7e5761035f8282611ea0565b61035f73ffffffffffffffffffffffffffffffffffffffff84163384846126af565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611efa576040519150601f19603f3d011682016040523d82523d6000602084013e611eff565b606091505b505090508061035f576040517ff4b3b1bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060c00160405280608d81526020016142e9608d913980516020918201208351848301516040808701516060880151608089015160a08a01518051908901209351610fd498939492939192910196875273ffffffffffffffffffffffffffffffffffffffff958616602088015293851660408701526060860192909252608085015290911660a083015260c082015260e00190565b6000604051602001611fe590613a66565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f4e6f6e6c696e656172447574636844656361792800000000000000000000000060208401527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060348401527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000604b84015281516044818503018152606484019092526120a5929091906084016140b8565b60405160208183030381529060405280519060200120826000015183602001516120d2856040015161279a565b60608087015160808089015160408051602081019990995273ffffffffffffffffffffffffffffffffffffffff909716968801969096529186019390935284015260a083015260c082015260e001610fd4565b600080825160200267ffffffffffffffff8111156121455761214561304a565b6040519080825280601f01601f19166020018201604052801561216f576020820181803683370190505b50835190915060005b818110156121b65760006121a486838151811061219757612197613079565b6020026020010151612898565b60208381028601015250600101612178565b5050805160209091012092915050565b6000818360a001516040516020016121de91906140e7565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261221a929160200161416c565b6040516020818303038152906040528051906020012090505b92915050565b600080828060200190518101906122509190614192565b9150915060008360408151811061226957612269613079565b0160209081015160408051600080825293810180835289905260f89290921c9082018190526060820186905260808201859052925060019060a0016020604051602081039080840390855afa1580156122c6573d6000803e3d6000fd5b5050506020604051035190508073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16141580612321575073ffffffffffffffffffffffffffffffffffffffff8116155b15612358576040517fd7815be100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60008183101561238f5761237d61237884846141b6565b6129fc565b6123889060006141c9565b9050612233565b61238861237883856141b6565b60006123b3856123ac86846141c9565b85856123bc565b95945050505050565b60008084121561241f5760006123d1856141f0565b9050856123fe827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6141b6565b101561240d5782915050612446565b6124178187613f08565b91505061243b565b8385101561242e575081612446565b61243884866141b6565b90505b6123b3818484612ab2565b949350505050565b600060108660200151511115612490576040517f0e99676600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b43841015806124a25750602086015151155b156124b9576124b2858484612ab2565b90506123b3565b60006124c585436141b6565b90506000806000806124d78b86612ac7565b935093509350935060006124fa8561ffff168561ffff168861ffff168686612c89565b90506125088b828b8b6123bc565b9c9b505050505050505050505050565b60408051606081018252600080825260208201819052918101919091526000612570846040015185602001518587608001517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61244e565b90506040518060600160405280856000015173ffffffffffffffffffffffffffffffffffffffff168152602001828152602001856060015173ffffffffffffffffffffffffffffffffffffffff1681525091505092915050565b6125d5848483612d0e565b61266c5781612610576040517fb9ec1e9600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604085015160005b815181101561235857600082828151811061263557612635613079565b6020026020010151905061265e856127106126509190613f08565b602083015190612710612d5a565b602090910152600101612618565b5050505050565b6000827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04841183021582026126a857600080fd5b5091020490565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff841660248201528260448201526020600060648360008a5af13d15601f3d116001600051141617169150508061266c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401610700565b6040517f4e6f6e6c696e656172447574636844656361792800000000000000000000000060208201527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060348201527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000604b82015260009060640160405160208183030381529060405280519060200120826000015183602001516040516020016128459190614228565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120908301949094528101919091526060810191909152608001610fd4565b60006040516020016128a990613b78565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f4e6f6e6c696e656172447574636844656361792800000000000000000000000060208401527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060348401527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000604b8401528151604481850301815260648401909252612969929091906084016140b8565b6040516020818303038152906040528051906020012082600001518360200151612996856040015161279a565b60608087015160808089015160a0808b015160408051602081019b909b5273ffffffffffffffffffffffffffffffffffffffff998a16908b01529489019690965290870193909352939093169184019190915260c083015260e082015261010001610fd4565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115612aae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e743235360000000000000000000000000000000000000000000000006064820152608401610700565b5090565b6000612446612ac18585612d9e565b83612db6565b6000806000806000612ada876000015190565b905061ffff8616612aec826000612dc5565b61ffff1610612b30576000612b018282612dc5565b60008960200151600081518110612b1a57612b1a613079565b6020026020010151945094509450945050612c80565b60006001886020015151612b44919061425e565b905060015b8161ffff168161ffff1611612c14578761ffff16612b748261ffff1685612dc590919063ffffffff16565b61ffff1610612c0257612b96612b8b60018361425e565b849061ffff16612dc5565b612ba48461ffff8416612dc5565b60208b0151612bb460018561425e565b61ffff1681518110612bc857612bc8613079565b60200260200101518b602001518461ffff1681518110612bea57612bea613079565b60200260200101519650965096509650505050612c80565b80612c0c81614279565b915050612b49565b50612c238261ffff8316612dc5565b612c318361ffff8416612dc5565b89602001518361ffff1681518110612c4b57612c4b613079565b60200260200101518a602001518461ffff1681518110612c6d57612c6d613079565b6020026020010151955095509550955050505b92959194509250565b6000848410612c995750806123b3565b6000612ca587866141b6565b90506000612cb388886141b6565b9050600085851215612ce557612cd58383612cce888a6141c9565b9190612673565b612cde906141f0565b9050612cf7565b612cf48383612cce89896141c9565b90505b612d01818761429a565b9998505050505050505050565b600073ffffffffffffffffffffffffffffffffffffffff84161580612d3257508282115b80612446575073ffffffffffffffffffffffffffffffffffffffff8416331490509392505050565b6000827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0484118302158202612d8f57600080fd5b50910281810615159190040190565b6000818311612dad5781612daf565b825b9392505050565b6000818310612dad5781612daf565b600060108210612e01576040517f4e23d03500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506010021c90565b600060408284031215612e1b57600080fd5b50919050565b60008083601f840112612e3357600080fd5b50813567ffffffffffffffff811115612e4b57600080fd5b602083019150836020828501011115612e6357600080fd5b9250929050565b600080600060408486031215612e7f57600080fd5b833567ffffffffffffffff80821115612e9757600080fd5b612ea387838801612e09565b94506020860135915080821115612eb957600080fd5b50612ec686828701612e21565b9497909650939450505050565b60008083601f840112612ee557600080fd5b50813567ffffffffffffffff811115612efd57600080fd5b6020830191508360208260051b8501011115612e6357600080fd5b60008060208385031215612f2b57600080fd5b823567ffffffffffffffff811115612f4257600080fd5b612f4e85828601612ed3565b90969095509350505050565b60008060008060408587031215612f7057600080fd5b843567ffffffffffffffff80821115612f8857600080fd5b612f9488838901612ed3565b90965094506020870135915080821115612fad57600080fd5b50612fba87828801612e21565b95989497509550505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461089157600080fd5b8035612ff381612fc6565b919050565b60006020828403121561300a57600080fd5b8135612daf81612fc6565b60006020828403121561302757600080fd5b813567ffffffffffffffff81111561303e57600080fd5b61244684828501612e09565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60005b838110156130c35781810151838201526020016130ab565b50506000910152565b600081518084526130e48160208601602086016130a8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60008151808452602080850194506020840160005b83811015613176578151805173ffffffffffffffffffffffffffffffffffffffff908116895284820151858a015260409182015116908801526060909601959082019060010161312b565b509495945050505050565b6000815160e0845273ffffffffffffffffffffffffffffffffffffffff8082511660e08601528060208301511661010086015260408201516101208601526060820151610140860152806080830151166101608601525060a0810151905060c06101808501526131f56101a08501826130cc565b905060208301516132336020860182805173ffffffffffffffffffffffffffffffffffffffff16825260208082015190830152604090810151910152565b506040830151848203608086015261324b8282613116565b915050606083015184820360a086015261326582826130cc565b915050608083015160c08501528091505092915050565b6000604082016040835280865180835260608501915060608160051b8601019250602080890160005b838110156132f1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526132df868351613181565b955093820193908201906001016132a5565b5050858403818701528684528688828601376000848801820152601f9096017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092019094019695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261337657600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126133b557600080fd5b83018035915067ffffffffffffffff8211156133d057600080fd5b602001915036819003821315612e6357600080fd5b60405160c0810167ffffffffffffffff811182821017156134085761340861304a565b60405290565b6040805190810167ffffffffffffffff811182821017156134085761340861304a565b60405160a0810167ffffffffffffffff811182821017156134085761340861304a565b60405160e0810167ffffffffffffffff811182821017156134085761340861304a565b6040516060810167ffffffffffffffff811182821017156134085761340861304a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156134e1576134e161304a565b604052919050565b600082601f8301126134fa57600080fd5b813567ffffffffffffffff8111156135145761351461304a565b61354560207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161349a565b81815284602083860101111561355a57600080fd5b816020850160208301376000918101602001919091529392505050565b600060c0828403121561358957600080fd5b6135916133e5565b9050813561359e81612fc6565b815260208201356135ae81612fc6565b80602083015250604082013560408201526060820135606082015260808201356135d781612fc6565b608082015260a082013567ffffffffffffffff8111156135f657600080fd5b613602848285016134e9565b60a08301525092915050565b600067ffffffffffffffff8211156136285761362861304a565b5060051b60200190565b60006040828403121561364457600080fd5b61364c61340e565b90508135815260208083013567ffffffffffffffff81111561366d57600080fd5b8301601f8101851361367e57600080fd5b803561369161368c8261360e565b61349a565b81815260059190911b820183019083810190878311156136b057600080fd5b928401925b828410156136ce578335825292840192908401906136b5565b8085870152505050505092915050565b600060a082840312156136f057600080fd5b6136f8613431565b9050813561370581612fc6565b815260208281013590820152604082013567ffffffffffffffff81111561372b57600080fd5b61373784828501613632565b604083015250606082013560608201526080820135608082015292915050565b600082601f83011261376857600080fd5b8135602061377861368c8361360e565b82815260059290921b8401810191818101908684111561379757600080fd5b8286015b8481101561387457803567ffffffffffffffff808211156137bc5760008081fd5b818901915060c0807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848d030112156137f55760008081fd5b6137fd6133e5565b8784013561380a81612fc6565b8152604084810135898301526060808601358581111561382a5760008081fd5b6138388f8c838a0101613632565b83850152506080945084860135915061385082612fc6565b82015260a0848101359382019390935292013590820152835291830191830161379b565b509695505050505050565b600060a0828403121561389157600080fd5b613899613431565b9050813581526020808301356138ae81612fc6565b8082840152506040830135604083015260608301356060830152608083013567ffffffffffffffff8111156138e257600080fd5b8301601f810185136138f357600080fd5b803561390161368c8261360e565b81815260059190911b8201830190838101908783111561392057600080fd5b928401925b8284101561393e57833582529284019290840190613925565b6080860152509295945050505050565b60006020828403121561396057600080fd5b813567ffffffffffffffff8082111561397857600080fd5b9083019060e0828603121561398c57600080fd5b613994613454565b8235828111156139a357600080fd5b6139af87828601613577565b8252506139be60208401612fe8565b6020820152604083013560408201526060830135828111156139df57600080fd5b6139eb878286016136de565b606083015250608083013582811115613a0357600080fd5b613a0f87828601613757565b60808301525060a083013582811115613a2757600080fd5b613a338782860161387f565b60a08301525060c083013582811115613a4b57600080fd5b613a57878286016134e9565b60c08301525095945050505050565b7f56334475746368496e707574280000000000000000000000000000000000000081527f6164647265737320746f6b656e2c000000000000000000000000000000000000600d8201527f75696e74323536207374617274416d6f756e742c000000000000000000000000601b8201527f4e6f6e6c696e656172447574636844656361792063757276652c000000000000602f8201527f75696e74323536206d6178416d6f756e742c000000000000000000000000000060498201527f75696e743235362061646a7573746d656e745065724777656942617365466565605b8201527f2900000000000000000000000000000000000000000000000000000000000000607b8201526000607c8201612233565b7f563344757463684f75747075742800000000000000000000000000000000000081527f6164647265737320746f6b656e2c000000000000000000000000000000000000600e8201527f75696e74323536207374617274416d6f756e742c000000000000000000000000601c8201527f4e6f6e6c696e656172447574636844656361792063757276652c00000000000060308201527f6164647265737320726563697069656e742c0000000000000000000000000000604a8201527f75696e74323536206d696e416d6f756e742c0000000000000000000000000000605c8201527f75696e743235362061646a7573746d656e745065724777656942617365466565606e8201527f2900000000000000000000000000000000000000000000000000000000000000608e8201526000608f8201612233565b60008651613cc2818460208b016130a8565b865190830190613cd6818360208b016130a8565b8651910190613ce9818360208a016130a8565b8551910190613cfc8183602089016130a8565b8451910190613d0f8183602088016130a8565b01979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202600082127f800000000000000000000000000000000000000000000000000000000000000084141615613d8257613d82613d1b565b818105831482151761223357612233613d1b565b600082613dcc577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615613e2057613e20613d1b565b500590565b602081526000612daf6020830184613181565b60006020808385031215613e4b57600080fd5b825167ffffffffffffffff811115613e6257600080fd5b8301601f81018513613e7357600080fd5b8051613e8161368c8261360e565b81815260609182028301840191848201919088841115613ea057600080fd5b938501935b83851015613efc5780858a031215613ebd5760008081fd5b613ec5613477565b8551613ed081612fc6565b81528587015187820152604080870151613ee981612fc6565b9082015283529384019391850191613ea5565b50979650505050505050565b8082018082111561223357612233613d1b565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006124466040830184613181565b7f563344757463684f72646572207769746e65737329000000000000000000000081526000601588516020613f8482848701838e016130a8565b895191850191613f9981858501848e016130a8565b8951920191613fad81858501848d016130a8565b8851920191613fc181858501848c016130a8565b8751920191613fd581858501848b016130a8565b8651920191613fe981858501848a016130a8565b919091019091019998505050505050505050565b600061014061402d838a51805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b602089015160408401526040890151606084015261406e6080840189805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b73ffffffffffffffffffffffffffffffffffffffff871660c08401528560e0840152806101008401526140a3818401866130cc565b9050828103610120840152612d0181856130cc565b600083516140ca8184602088016130a8565b8351908301906140de8183602088016130a8565b01949350505050565b6000602080835260c0830184518285015273ffffffffffffffffffffffffffffffffffffffff828601511660408501526040850151606085015260608501516080850152608085015160a08086015281815180845260e0870191508483019350600092505b80831015613874578351825292840192600192909201919084019061414c565b828152600082516141848160208501602087016130a8565b919091016020019392505050565b600080604083850312156141a557600080fd5b505080516020909101519092909150565b8181038181111561223357612233613d1b565b81810360008312801583831316838312821617156141e9576141e9613d1b565b5092915050565b60007f8000000000000000000000000000000000000000000000000000000000000000820361422157614221613d1b565b5060000390565b815160009082906020808601845b8381101561425257815185529382019390820190600101614236565b50929695505050505050565b61ffff8281168282160390808211156141e9576141e9613d1b565b600061ffff80831681810361429057614290613d1b565b6001019392505050565b808201828112600083128015821682158216171561145157611451613d1b56fe546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e74294f72646572496e666f28616464726573732072656163746f722c6164647265737320737761707065722c75696e74323536206e6f6e63652c75696e7432353620646561646c696e652c61646472657373206164646974696f6e616c56616c69646174696f6e436f6e74726163742c6279746573206164646974696f6e616c56616c69646174696f6e4461746129a2646970667358221220cfaf36c7e3c9798dfd6bc92252ac740ff42fa3a7b113877282829c51de339a4d64736f6c63430008180033","sourceMap":"1368:4834:71:-:0;;;2049:101;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1045:5:41;:14;;-1:-1:-1;;;;;;1045:14:41;-1:-1:-1;;;;;1045:14:41;;;;;;;1075:40;;2119:8:71;;1045:14:41;;;;;;:5;1075:40;;1045:5;;1075:40;-1:-1:-1;;1716:1:27;1821:7;:22;-1:-1:-1;;;;;;1352:18:69::1;;::::0;-1:-1:-1;1368:4834:71;;-1:-1:-1;1368:4834:71;14:141:90;-1:-1:-1;;;;;99:31:90;;89:42;;79:70;;145:1;142;135:12;79:70;14:141;:::o;160:423::-;257:6;265;318:2;306:9;297:7;293:23;289:32;286:52;;;334:1;331;324:12;286:52;366:9;360:16;385:41;420:5;385:41;:::i;:::-;495:2;480:18;;474:25;445:5;;-1:-1:-1;508:43:90;474:25;508:43;:::i;:::-;570:7;560:17;;;160:423;;;;;:::o;:::-;1368:4834:71;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x60806040526004361061009a5760003560e01c80632d771389116100695780636999b3771161004e5780636999b377146101715780638da5cb5b1461019e578063f2fde38b146101cb57600080fd5b80632d7713891461013e5780633f62192e1461015e57600080fd5b80630d335884146100a65780630d7a16c3146100bb57806312261ee7146100ce57806313fb72c71461012b57600080fd5b366100a157005b600080fd5b6100b96100b4366004612e6a565b6101eb565b005b6100b96100c9366004612f18565b610364565b3480156100da57600080fd5b506101027f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100b9610139366004612f5a565b6104c5565b34801561014a57600080fd5b506100b9610159366004612ff8565b610683565b6100b961016c366004613015565b61078f565b34801561017d57600080fd5b506001546101029073ffffffffffffffffffffffffffffffffffffffff1681565b3480156101aa57600080fd5b506000546101029073ffffffffffffffffffffffffffffffffffffffff1681565b3480156101d757600080fd5b506100b96101e6366004612ff8565b610894565b6101f3610985565b604080516001808252818301909252600091816020015b6040805161016081018252600060a0820181815260c0830182905260e0830182905261010083018290526101208301829052606061014084018190529083528351808201855282815260208082018490528186018490528085019190915293830181905280830152608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161020a5790505090506102b2846109f6565b816000815181106102c5576102c5613079565b60200260200101819052506102d981610b67565b6040517f585da628000000000000000000000000000000000000000000000000000000008152339063585da628906103199084908790879060040161327c565b600060405180830381600087803b15801561033357600080fd5b505af1158015610347573d6000803e3d6000fd5b5050505061035481610bb8565b5061035f6001600255565b505050565b61036c610985565b8060008167ffffffffffffffff8111156103885761038861304a565b60405190808252806020026020018201604052801561044357816020015b6040805161016081018252600060a0820181815260c0830182905260e0830182905261010083018290526101208301829052606061014084018190529083528351808201855282815260208082018490528186018490528085019190915293830181905280830152608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816103a65790505b50905060005b828110156104a25761047d85858381811061046657610466613079565b90506020028101906104789190613342565b6109f6565b82828151811061048f5761048f613079565b6020908102919091010152600101610449565b506104ac81610b67565b6104b581610bb8565b50506104c16001600255565b5050565b6104cd610985565b8260008167ffffffffffffffff8111156104e9576104e961304a565b6040519080825280602002602001820160405280156105a457816020015b6040805161016081018252600060a0820181815260c0830182905260e0830182905261010083018290526101208301829052606061014084018190529083528351808201855282815260208082018490528186018490528085019190915293830181905280830152608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816105075790505b50905060005b828110156105ec576105c787878381811061046657610466613079565b8282815181106105d9576105d9613079565b60209081029190910101526001016105aa565b506105f681610b67565b6040517f585da628000000000000000000000000000000000000000000000000000000008152339063585da628906106369084908890889060040161327c565b600060405180830381600087803b15801561065057600080fd5b505af1158015610664573d6000803e3d6000fd5b5050505061067181610bb8565b505061067d6001600255565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610709576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527fb904ae9529e373e48bc82df4326cceaf1b4c472babf37f5b7dec46fecc6b53e0910160405180910390a15050565b610797610985565b604080516001808252818301909252600091816020015b6040805161016081018252600060a0820181815260c0830182905260e0830182905261010083018290526101208301829052606061014084018190529083528351808201855282815260208082018490528186018490528085019190915293830181905280830152608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816107ae579050509050610856826109f6565b8160008151811061086957610869613079565b602002602001018190525061087d81610b67565b61088681610bb8565b506108916001600255565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610700565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b60028054036109f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610700565b60028055565b6040805161016081018252600060a0820181815260c0830182905260e083018290526101008301829052610120830182905260606101408401819052908352835180820185528281526020808201849052818601849052840152928201839052828201929092526080810182905290610a6f8380613380565b810190610a7c919061394e565b90506000610a8982610d0b565b9050610a958183610ff1565b610a9e8261104d565b610aa7826111b1565b6040805160a080820190925283518152908301515160608401516020830191610ad091906112e0565b815260a0840151516080850151602090920191610aec91611374565b8152602001858060200190610b019190613380565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602090810183905260a0840151908101518151604090920151929550610b6092869290611459565b5050919050565b805160005b8181101561035f576000838281518110610b8857610b88613079565b60200260200101519050610b9b81611466565b610ba58133611956565b610baf8133611a57565b50600101610b6c565b805160005b81811015610cfa576000838281518110610bd957610bd9613079565b602002602001015190506000816040015151905060005b81811015610c5a57600083604001518281518110610c1057610c10613079565b60200260200101519050610c5181604001518260200151836000015173ffffffffffffffffffffffffffffffffffffffff16611e599092919063ffffffff16565b50600101610bf0565b5081600001516020015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16868581518110610ca357610ca3613079565b6020026020010151608001517f78ad7ec0e9f89e74012afa58738b6b661c024cb0fd185ee2f616c0a28924bd66856000015160400151604051610ce891815260200190565b60405180910390a45050600101610bbd565b5047156104c1576104c13347611ea0565b6040517f563344757463684f72646572280000000000000000000000000000000000000060208201527f4f72646572496e666f20696e666f2c0000000000000000000000000000000000602d8201527f6164647265737320636f7369676e65722c000000000000000000000000000000603c8201527f75696e74323536207374617274696e67426173654665652c0000000000000000604d8201527f56334475746368496e7075742062617365496e7075742c00000000000000000060658201527f563344757463684f75747075745b5d20626173654f7574707574732900000000607c820152600090609801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f4e6f6e6c696e656172447574636844656361792800000000000000000000000060208301527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060348301527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000604b83015290606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815260c08301909152608d8083529091906142e96020830139604051602001610eee90613a66565b604051602081830303815290604052604051602001610f0c90613b78565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610f4b9594939291602001613cb0565b60405160208183030381529060405280519060200120610f6e8360000151611f3a565b83602001518460400151610f858660600151611fd4565b610f928760800151612125565b60408051602081019790975286019490945273ffffffffffffffffffffffffffffffffffffffff9092166060850152608084015260a083015260c082015260e0015b604051602081830303815290604052805190602001209050919050565b805160600151421115611030576040517fb08ce5b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101516104c19061104383856121c6565b8360c00151612239565b60a081015160600151156110b9578060600151602001518160a001516060015111156110a5576040517fac9143e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a081015160609081015190820151602001525b8060800151518160a00151608001515114611100576040517fa305df8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60808101515160005b8181101561035f5760008360800151828151811061112957611129613079565b6020026020010151905060008460a0015160800151838151811061114f5761114f613079565b60200260200101519050806000146111a757816020015181101561119f576040517fa305df8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602082018190525b5050600101611109565b60006111ca82604001514861236190919063ffffffff16565b9050816060015160800151600014611236576000633b9aca00828460600151608001516111f79190613d4a565b6112019190613d96565b905061122b81600085606001516060015186606001516020015161239c909392919063ffffffff16565b606084015160200152505b60808201515160005b8181101561067d5760008460800151828151811061125f5761125f613079565b602002602001015190508060a001516000146112d7576000633b9aca00858360a0015161128c9190613d4a565b6112969190613d96565b608083015160208401519192506112d0919083907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6123bc565b6020830152505b5060010161123f565b61131a6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b600061133684604001518560200151856000886060015161244e565b6040805160608082018352875173ffffffffffffffffffffffffffffffffffffffff1682526020820193909352959091015190850152509192915050565b81516060908067ffffffffffffffff8111156113925761139261304a565b6040519080825280602002602001820160405280156113fb57816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816113b05790505b50915060005b818110156114515761142c85828151811061141e5761141e613079565b602002602001015185612518565b83828151811061143e5761143e613079565b6020908102919091010152600101611401565b505092915050565b61067d84848484436125ca565b60015473ffffffffffffffffffffffffffffffffffffffff166114865750565b6001546040517f8aa6cf0300000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff1690638aa6cf03906114dd908590600401613e25565b600060405180830381865afa1580156114fa573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115409190810190613e38565b60408301515181519192509060006115588284613f08565b67ffffffffffffffff8111156115705761157061304a565b6040519080825280602002602001820160405280156115d957816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161158e5790505b50905060005b8381101561162a57856040015181815181106115fd576115fd613079565b602002602001015182828151811061161757611617613079565b60209081029190910101526001016115df565b5060008060005b8481101561194557600087828151811061164d5761164d613079565b6020026020010151905060005b8281101561170b5788818151811061167457611674613079565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff16036117035781516040517ffff0830300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610700565b60010161165a565b506000805b888110156117cc5760008b60400151828151811061173057611730613079565b60200260200101519050836000015173ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff16036117c35785156117ad576040517fedc7e2e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101516117bc9084613f08565b9250600196505b50600101611710565b50815160208b01515173ffffffffffffffffffffffffffffffffffffffff91821691160361184557841561182c576040517fedc7e2e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808b0151015161183e9082613f08565b9050600193505b8060000361189a5781516040517feddf07f500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610700565b6118a8816005612710612673565b8260200151111561191b578151602083015160408085015190517f82e7565600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841660048201526024810192909252919091166044820152606401610700565b8186848a018151811061193057611930613079565b60209081029190910101525050600101611631565b505050604090940193909352505050565b81515173ffffffffffffffffffffffffffffffffffffffff1630146119a7576040517f4ddf4a6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81516080015173ffffffffffffffffffffffffffffffffffffffff16156104c1578151608001516040517f6e84ba2b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690636e84ba2b90611a239084908690600401613f1b565b60006040518083038186803b158015611a3b57600080fd5b505afa158015611a4f573d6000803e3d6000fd5b505050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663137c29fe611b17846040805160a0810182526000606082018181526080830182905282526020820181905291810191909152506040805160a081018252602080840180515173ffffffffffffffffffffffffffffffffffffffff1660608085019182529151850151608085015283528451840151918301919091529251909201519082015290565b6040805180820182526000808252602091820152815180830190925273ffffffffffffffffffffffffffffffffffffffff8616825280870151810151908201528560000151602001518660800151604051602001611be4907f4e6f6e6c696e656172447574636844656361792800000000000000000000000081527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060148201527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000602b82015260440190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815260c08301909152608d8083529091906142e960208301396040518060600160405280602e81526020016142bb602e9139604051602001611c4e90613a66565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f563344757463684f72646572280000000000000000000000000000000000000060208401527f4f72646572496e666f20696e666f2c0000000000000000000000000000000000602d8401527f6164647265737320636f7369676e65722c000000000000000000000000000000603c8401527f75696e74323536207374617274696e67426173654665652c0000000000000000604d8401527f56334475746368496e7075742062617365496e7075742c00000000000000000060658401527f563344757463684f75747075745b5d20626173654f7574707574732900000000607c840152815160788185030181526098840190925291611d7e9060b801613b78565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611dbe969594939291602001613f4a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905260608a01517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b168352611e2b9695949392600401613ffd565b600060405180830381600087803b158015611e4557600080fd5b505af1158015611a4f573d6000803e3d6000fd5b73ffffffffffffffffffffffffffffffffffffffff8316611e7e5761035f8282611ea0565b61035f73ffffffffffffffffffffffffffffffffffffffff84163384846126af565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611efa576040519150601f19603f3d011682016040523d82523d6000602084013e611eff565b606091505b505090508061035f576040517ff4b3b1bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060c00160405280608d81526020016142e9608d913980516020918201208351848301516040808701516060880151608089015160a08a01518051908901209351610fd498939492939192910196875273ffffffffffffffffffffffffffffffffffffffff958616602088015293851660408701526060860192909252608085015290911660a083015260c082015260e00190565b6000604051602001611fe590613a66565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f4e6f6e6c696e656172447574636844656361792800000000000000000000000060208401527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060348401527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000604b84015281516044818503018152606484019092526120a5929091906084016140b8565b60405160208183030381529060405280519060200120826000015183602001516120d2856040015161279a565b60608087015160808089015160408051602081019990995273ffffffffffffffffffffffffffffffffffffffff909716968801969096529186019390935284015260a083015260c082015260e001610fd4565b600080825160200267ffffffffffffffff8111156121455761214561304a565b6040519080825280601f01601f19166020018201604052801561216f576020820181803683370190505b50835190915060005b818110156121b65760006121a486838151811061219757612197613079565b6020026020010151612898565b60208381028601015250600101612178565b5050805160209091012092915050565b6000818360a001516040516020016121de91906140e7565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261221a929160200161416c565b6040516020818303038152906040528051906020012090505b92915050565b600080828060200190518101906122509190614192565b9150915060008360408151811061226957612269613079565b0160209081015160408051600080825293810180835289905260f89290921c9082018190526060820186905260808201859052925060019060a0016020604051602081039080840390855afa1580156122c6573d6000803e3d6000fd5b5050506020604051035190508073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16141580612321575073ffffffffffffffffffffffffffffffffffffffff8116155b15612358576040517fd7815be100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60008183101561238f5761237d61237884846141b6565b6129fc565b6123889060006141c9565b9050612233565b61238861237883856141b6565b60006123b3856123ac86846141c9565b85856123bc565b95945050505050565b60008084121561241f5760006123d1856141f0565b9050856123fe827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6141b6565b101561240d5782915050612446565b6124178187613f08565b91505061243b565b8385101561242e575081612446565b61243884866141b6565b90505b6123b3818484612ab2565b949350505050565b600060108660200151511115612490576040517f0e99676600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b43841015806124a25750602086015151155b156124b9576124b2858484612ab2565b90506123b3565b60006124c585436141b6565b90506000806000806124d78b86612ac7565b935093509350935060006124fa8561ffff168561ffff168861ffff168686612c89565b90506125088b828b8b6123bc565b9c9b505050505050505050505050565b60408051606081018252600080825260208201819052918101919091526000612570846040015185602001518587608001517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61244e565b90506040518060600160405280856000015173ffffffffffffffffffffffffffffffffffffffff168152602001828152602001856060015173ffffffffffffffffffffffffffffffffffffffff1681525091505092915050565b6125d5848483612d0e565b61266c5781612610576040517fb9ec1e9600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604085015160005b815181101561235857600082828151811061263557612635613079565b6020026020010151905061265e856127106126509190613f08565b602083015190612710612d5a565b602090910152600101612618565b5050505050565b6000827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04841183021582026126a857600080fd5b5091020490565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff841660248201528260448201526020600060648360008a5af13d15601f3d116001600051141617169150508061266c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401610700565b6040517f4e6f6e6c696e656172447574636844656361792800000000000000000000000060208201527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060348201527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000604b82015260009060640160405160208183030381529060405280519060200120826000015183602001516040516020016128459190614228565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120908301949094528101919091526060810191909152608001610fd4565b60006040516020016128a990613b78565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f4e6f6e6c696e656172447574636844656361792800000000000000000000000060208401527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060348401527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000604b8401528151604481850301815260648401909252612969929091906084016140b8565b6040516020818303038152906040528051906020012082600001518360200151612996856040015161279a565b60608087015160808089015160a0808b015160408051602081019b909b5273ffffffffffffffffffffffffffffffffffffffff998a16908b01529489019690965290870193909352939093169184019190915260c083015260e082015261010001610fd4565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115612aae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e743235360000000000000000000000000000000000000000000000006064820152608401610700565b5090565b6000612446612ac18585612d9e565b83612db6565b6000806000806000612ada876000015190565b905061ffff8616612aec826000612dc5565b61ffff1610612b30576000612b018282612dc5565b60008960200151600081518110612b1a57612b1a613079565b6020026020010151945094509450945050612c80565b60006001886020015151612b44919061425e565b905060015b8161ffff168161ffff1611612c14578761ffff16612b748261ffff1685612dc590919063ffffffff16565b61ffff1610612c0257612b96612b8b60018361425e565b849061ffff16612dc5565b612ba48461ffff8416612dc5565b60208b0151612bb460018561425e565b61ffff1681518110612bc857612bc8613079565b60200260200101518b602001518461ffff1681518110612bea57612bea613079565b60200260200101519650965096509650505050612c80565b80612c0c81614279565b915050612b49565b50612c238261ffff8316612dc5565b612c318361ffff8416612dc5565b89602001518361ffff1681518110612c4b57612c4b613079565b60200260200101518a602001518461ffff1681518110612c6d57612c6d613079565b6020026020010151955095509550955050505b92959194509250565b6000848410612c995750806123b3565b6000612ca587866141b6565b90506000612cb388886141b6565b9050600085851215612ce557612cd58383612cce888a6141c9565b9190612673565b612cde906141f0565b9050612cf7565b612cf48383612cce89896141c9565b90505b612d01818761429a565b9998505050505050505050565b600073ffffffffffffffffffffffffffffffffffffffff84161580612d3257508282115b80612446575073ffffffffffffffffffffffffffffffffffffffff8416331490509392505050565b6000827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0484118302158202612d8f57600080fd5b50910281810615159190040190565b6000818311612dad5781612daf565b825b9392505050565b6000818310612dad5781612daf565b600060108210612e01576040517f4e23d03500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506010021c90565b600060408284031215612e1b57600080fd5b50919050565b60008083601f840112612e3357600080fd5b50813567ffffffffffffffff811115612e4b57600080fd5b602083019150836020828501011115612e6357600080fd5b9250929050565b600080600060408486031215612e7f57600080fd5b833567ffffffffffffffff80821115612e9757600080fd5b612ea387838801612e09565b94506020860135915080821115612eb957600080fd5b50612ec686828701612e21565b9497909650939450505050565b60008083601f840112612ee557600080fd5b50813567ffffffffffffffff811115612efd57600080fd5b6020830191508360208260051b8501011115612e6357600080fd5b60008060208385031215612f2b57600080fd5b823567ffffffffffffffff811115612f4257600080fd5b612f4e85828601612ed3565b90969095509350505050565b60008060008060408587031215612f7057600080fd5b843567ffffffffffffffff80821115612f8857600080fd5b612f9488838901612ed3565b90965094506020870135915080821115612fad57600080fd5b50612fba87828801612e21565b95989497509550505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461089157600080fd5b8035612ff381612fc6565b919050565b60006020828403121561300a57600080fd5b8135612daf81612fc6565b60006020828403121561302757600080fd5b813567ffffffffffffffff81111561303e57600080fd5b61244684828501612e09565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60005b838110156130c35781810151838201526020016130ab565b50506000910152565b600081518084526130e48160208601602086016130a8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60008151808452602080850194506020840160005b83811015613176578151805173ffffffffffffffffffffffffffffffffffffffff908116895284820151858a015260409182015116908801526060909601959082019060010161312b565b509495945050505050565b6000815160e0845273ffffffffffffffffffffffffffffffffffffffff8082511660e08601528060208301511661010086015260408201516101208601526060820151610140860152806080830151166101608601525060a0810151905060c06101808501526131f56101a08501826130cc565b905060208301516132336020860182805173ffffffffffffffffffffffffffffffffffffffff16825260208082015190830152604090810151910152565b506040830151848203608086015261324b8282613116565b915050606083015184820360a086015261326582826130cc565b915050608083015160c08501528091505092915050565b6000604082016040835280865180835260608501915060608160051b8601019250602080890160005b838110156132f1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526132df868351613181565b955093820193908201906001016132a5565b5050858403818701528684528688828601376000848801820152601f9096017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092019094019695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261337657600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126133b557600080fd5b83018035915067ffffffffffffffff8211156133d057600080fd5b602001915036819003821315612e6357600080fd5b60405160c0810167ffffffffffffffff811182821017156134085761340861304a565b60405290565b6040805190810167ffffffffffffffff811182821017156134085761340861304a565b60405160a0810167ffffffffffffffff811182821017156134085761340861304a565b60405160e0810167ffffffffffffffff811182821017156134085761340861304a565b6040516060810167ffffffffffffffff811182821017156134085761340861304a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156134e1576134e161304a565b604052919050565b600082601f8301126134fa57600080fd5b813567ffffffffffffffff8111156135145761351461304a565b61354560207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161349a565b81815284602083860101111561355a57600080fd5b816020850160208301376000918101602001919091529392505050565b600060c0828403121561358957600080fd5b6135916133e5565b9050813561359e81612fc6565b815260208201356135ae81612fc6565b80602083015250604082013560408201526060820135606082015260808201356135d781612fc6565b608082015260a082013567ffffffffffffffff8111156135f657600080fd5b613602848285016134e9565b60a08301525092915050565b600067ffffffffffffffff8211156136285761362861304a565b5060051b60200190565b60006040828403121561364457600080fd5b61364c61340e565b90508135815260208083013567ffffffffffffffff81111561366d57600080fd5b8301601f8101851361367e57600080fd5b803561369161368c8261360e565b61349a565b81815260059190911b820183019083810190878311156136b057600080fd5b928401925b828410156136ce578335825292840192908401906136b5565b8085870152505050505092915050565b600060a082840312156136f057600080fd5b6136f8613431565b9050813561370581612fc6565b815260208281013590820152604082013567ffffffffffffffff81111561372b57600080fd5b61373784828501613632565b604083015250606082013560608201526080820135608082015292915050565b600082601f83011261376857600080fd5b8135602061377861368c8361360e565b82815260059290921b8401810191818101908684111561379757600080fd5b8286015b8481101561387457803567ffffffffffffffff808211156137bc5760008081fd5b818901915060c0807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848d030112156137f55760008081fd5b6137fd6133e5565b8784013561380a81612fc6565b8152604084810135898301526060808601358581111561382a5760008081fd5b6138388f8c838a0101613632565b83850152506080945084860135915061385082612fc6565b82015260a0848101359382019390935292013590820152835291830191830161379b565b509695505050505050565b600060a0828403121561389157600080fd5b613899613431565b9050813581526020808301356138ae81612fc6565b8082840152506040830135604083015260608301356060830152608083013567ffffffffffffffff8111156138e257600080fd5b8301601f810185136138f357600080fd5b803561390161368c8261360e565b81815260059190911b8201830190838101908783111561392057600080fd5b928401925b8284101561393e57833582529284019290840190613925565b6080860152509295945050505050565b60006020828403121561396057600080fd5b813567ffffffffffffffff8082111561397857600080fd5b9083019060e0828603121561398c57600080fd5b613994613454565b8235828111156139a357600080fd5b6139af87828601613577565b8252506139be60208401612fe8565b6020820152604083013560408201526060830135828111156139df57600080fd5b6139eb878286016136de565b606083015250608083013582811115613a0357600080fd5b613a0f87828601613757565b60808301525060a083013582811115613a2757600080fd5b613a338782860161387f565b60a08301525060c083013582811115613a4b57600080fd5b613a57878286016134e9565b60c08301525095945050505050565b7f56334475746368496e707574280000000000000000000000000000000000000081527f6164647265737320746f6b656e2c000000000000000000000000000000000000600d8201527f75696e74323536207374617274416d6f756e742c000000000000000000000000601b8201527f4e6f6e6c696e656172447574636844656361792063757276652c000000000000602f8201527f75696e74323536206d6178416d6f756e742c000000000000000000000000000060498201527f75696e743235362061646a7573746d656e745065724777656942617365466565605b8201527f2900000000000000000000000000000000000000000000000000000000000000607b8201526000607c8201612233565b7f563344757463684f75747075742800000000000000000000000000000000000081527f6164647265737320746f6b656e2c000000000000000000000000000000000000600e8201527f75696e74323536207374617274416d6f756e742c000000000000000000000000601c8201527f4e6f6e6c696e656172447574636844656361792063757276652c00000000000060308201527f6164647265737320726563697069656e742c0000000000000000000000000000604a8201527f75696e74323536206d696e416d6f756e742c0000000000000000000000000000605c8201527f75696e743235362061646a7573746d656e745065724777656942617365466565606e8201527f2900000000000000000000000000000000000000000000000000000000000000608e8201526000608f8201612233565b60008651613cc2818460208b016130a8565b865190830190613cd6818360208b016130a8565b8651910190613ce9818360208a016130a8565b8551910190613cfc8183602089016130a8565b8451910190613d0f8183602088016130a8565b01979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202600082127f800000000000000000000000000000000000000000000000000000000000000084141615613d8257613d82613d1b565b818105831482151761223357612233613d1b565b600082613dcc577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615613e2057613e20613d1b565b500590565b602081526000612daf6020830184613181565b60006020808385031215613e4b57600080fd5b825167ffffffffffffffff811115613e6257600080fd5b8301601f81018513613e7357600080fd5b8051613e8161368c8261360e565b81815260609182028301840191848201919088841115613ea057600080fd5b938501935b83851015613efc5780858a031215613ebd5760008081fd5b613ec5613477565b8551613ed081612fc6565b81528587015187820152604080870151613ee981612fc6565b9082015283529384019391850191613ea5565b50979650505050505050565b8082018082111561223357612233613d1b565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006124466040830184613181565b7f563344757463684f72646572207769746e65737329000000000000000000000081526000601588516020613f8482848701838e016130a8565b895191850191613f9981858501848e016130a8565b8951920191613fad81858501848d016130a8565b8851920191613fc181858501848c016130a8565b8751920191613fd581858501848b016130a8565b8651920191613fe981858501848a016130a8565b919091019091019998505050505050505050565b600061014061402d838a51805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b602089015160408401526040890151606084015261406e6080840189805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b73ffffffffffffffffffffffffffffffffffffffff871660c08401528560e0840152806101008401526140a3818401866130cc565b9050828103610120840152612d0181856130cc565b600083516140ca8184602088016130a8565b8351908301906140de8183602088016130a8565b01949350505050565b6000602080835260c0830184518285015273ffffffffffffffffffffffffffffffffffffffff828601511660408501526040850151606085015260608501516080850152608085015160a08086015281815180845260e0870191508483019350600092505b80831015613874578351825292840192600192909201919084019061414c565b828152600082516141848160208501602087016130a8565b919091016020019392505050565b600080604083850312156141a557600080fd5b505080516020909101519092909150565b8181038181111561223357612233613d1b565b81810360008312801583831316838312821617156141e9576141e9613d1b565b5092915050565b60007f8000000000000000000000000000000000000000000000000000000000000000820361422157614221613d1b565b5060000390565b815160009082906020808601845b8381101561425257815185529382019390820190600101614236565b50929695505050505050565b61ffff8281168282160390808211156141e9576141e9613d1b565b600061ffff80831681810361429057614290613d1b565b6001019392505050565b808201828112600083128015821682158216171561145157611451613d1b56fe546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e74294f72646572496e666f28616464726573732072656163746f722c6164647265737320737761707065722c75696e74323536206e6f6e63652c75696e7432353620646561646c696e652c61646472657373206164646974696f6e616c56616c69646174696f6e436f6e74726163742c6279746573206164646974696f6e616c56616c69646174696f6e4461746129a2646970667358221220cfaf36c7e3c9798dfd6bc92252ac740ff42fa3a7b113877282829c51de339a4d64736f6c63430008180033","sourceMap":"1368:4834:71:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1721:435:69;;;;;;:::i;:::-;;:::i;:::-;;2191:453;;;;;;:::i;:::-;;:::i;1212:33::-;;;;;;;;;;;;;;;;;;2288:42:90;2276:55;;;2258:74;;2246:2;2231:18;1212:33:69;;;;;;;2679:614;;;;;;:::i;:::-;;:::i;4161:289:46:-;;;;;;;;;;-1:-1:-1;4161:289:46;;;;;:::i;:::-;;:::i;1412:274:69:-;;;;;;:::i;:::-;;:::i;1479:43:46:-;;;;;;;;;;-1:-1:-1;1479:43:46;;;;;;;;690:20:41;;;;;;;;;;-1:-1:-1;690:20:41;;;;;;;;1312:161;;;;;;;;;;-1:-1:-1;1312:161:41;;;;;:::i;:::-;;:::i;1721:435:69:-;2261:21:27;:19;:21::i;:::-;1932:22:69::1;::::0;;1952:1:::1;1932:22:::0;;;;;::::1;::::0;;;1892:37:::1;::::0;1932:22:::1;;;;-1:-1:-1::0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1932:22:69;;;;;;;::::1;::::0;::::1;;;;;1892:62;;1984:15;1993:5;1984:8;:15::i;:::-;1964:14;1979:1;1964:17;;;;;;;;:::i;:::-;;;;;;:35;;;;2010:24;2019:14;2010:8;:24::i;:::-;2044:74;::::0;;;;2061:10:::1;::::0;2044:44:::1;::::0;:74:::1;::::0;2089:14;;2105:12;;;;2044:74:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;2128:21;2134:14;2128:5;:21::i;:::-;1882:274;2303:20:27::0;1716:1;2809:7;:22;2629:209;2303:20;1721:435:69;;;:::o;2191:453::-;2261:21:27;:19;:21::i;:::-;2316:6:69;2293:20:::1;2316:6:::0;2379:33:::1;::::0;::::1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2379:33:69;;;;;;;::::1;::::0;::::1;;;;;;2339:73;;2452:9;2447:115;2471:12;2467:1;:16;2447:115;;;2528:19;2537:6;;2544:1;2537:9;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;2528:8;:19::i;:::-;2508:14;2523:1;2508:17;;;;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;:39;2485:3:::1;;2447:115;;;;2582:24;2591:14;2582:8;:24::i;:::-;2616:21;2622:14;2616:5;:21::i;:::-;2283:361;;2303:20:27::0;1716:1;2809:7;:22;2629:209;2303:20;2191:453:69;;:::o;2679:614::-;2261:21:27;:19;:21::i;:::-;2881:6:69;2858:20:::1;2881:6:::0;2944:33:::1;::::0;::::1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2944:33:69;;;;;;;::::1;::::0;::::1;;;;;;2904:73;;3017:9;3012:115;3036:12;3032:1;:16;3012:115;;;3093:19;3102:6;;3109:1;3102:9;;;;;;;:::i;3093:19::-;3073:14;3088:1;3073:17;;;;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;:39;3050:3:::1;;3012:115;;;;3147:24;3156:14;3147:8;:24::i;:::-;3181:74;::::0;;;;3198:10:::1;::::0;3181:44:::1;::::0;:74:::1;::::0;3226:14;;3242:12;;;;3181:74:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;3265:21;3271:14;3265:5;:21::i;:::-;2848:445;;2303:20:27::0;1716:1;2809:7;:22;2629:209;2303:20;2679:614:69;;;;:::o;4161:289:46:-;778:5:41;;;;764:10;:19;756:44;;;;;;;9611:2:90;756:44:41;;;9593:21:90;9650:2;9630:18;;;9623:30;9689:14;9669:18;;;9662:42;9721:18;;756:44:41;;;;;;;;;4286:13:46::1;::::0;;::::1;4310:57:::0;;::::1;::::0;;::::1;::::0;::::1;::::0;;;4382:61:::1;::::0;;4286:13;;;::::1;9985:34:90::0;;;10050:2;10035:18;;10028:43;;;;4382:61:46::1;::::0;9897:18:90;4382:61:46::1;;;;;;;4241:209;4161:289:::0;:::o;1412:274:69:-;2261:21:27;:19;:21::i;:::-;1546:22:69::1;::::0;;1566:1:::1;1546:22:::0;;;;;::::1;::::0;;;1506:37:::1;::::0;1546:22:::1;;;;-1:-1:-1::0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1546:22:69;;;;;;;::::1;::::0;::::1;;;;;1506:62;;1598:15;1607:5;1598:8;:15::i;:::-;1578:14;1593:1;1578:17;;;;;;;;:::i;:::-;;;;;;:35;;;;1624:24;1633:14;1624:8;:24::i;:::-;1658:21;1664:14;1658:5;:21::i;:::-;1496:190;2303:20:27::0;1716:1;2809:7;:22;2629:209;2303:20;1412:274:69;:::o;1312:161:41:-;778:5;;;;764:10;:19;756:44;;;;;;;9611:2:90;756:44:41;;;9593:21:90;9650:2;9630:18;;;9623:30;9689:14;9669:18;;;9662:42;9721:18;;756:44:41;9409:336:90;756:44:41;1392:5:::1;:16:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;1424:42:::1;::::0;1392:16;;1445:10:::1;::::0;1424:42:::1;::::0;1392:5;1424:42:::1;1312:161:::0;:::o;2336:287:27:-;1759:1;2468:7;;:19;2460:63;;;;;;;10284:2:90;2460:63:27;;;10266:21:90;10323:2;10303:18;;;10296:30;10362:33;10342:18;;;10335:61;10413:18;;2460:63:27;10082:355:90;2460:63:27;1759:1;2598:18;;2336:287::o;2188:1051:71:-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2409:17:71;:11;;:17;:::i;:::-;2398:45;;;;;;;:::i;:::-;2370:73;;2555:17;2575:12;:5;:10;:12::i;:::-;2555:32;;2598;2613:9;2624:5;2598:14;:32::i;:::-;2640:33;2667:5;2640:26;:33::i;:::-;2683:31;2708:5;2683:24;:31::i;:::-;2741:278;;;;;;;;;;2775:10;;2741:278;;2828:18;;;;:34;2806:15;;;;2741:278;;;;2806:57;;:15;:21;:57::i;:::-;2741:278;;2910:18;;;;:34;2886:17;;;;2741:278;;;;;2886:59;;:23;:59::i;:::-;2741:278;;;;2964:11;:15;;;;;;;;:::i;:::-;2741:278;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;2741:278:71;;;-1:-1:-1;2741:278:71;;;;;;;3085:18;;;;:34;;;;3133;;3181:41;;;;;2725:294;;-1:-1:-1;3029:203:71;;2725:294;;3133:34;3029:42;:203::i;:::-;2360:879;;2188:1051;;;:::o;3441:405:69:-;3532:13;;3509:20;3579:251;3603:12;3599:1;:16;3579:251;;;3640:26;3669:6;3676:1;3669:9;;;;;;;;:::i;:::-;;;;;;;3640:38;;3696:18;3708:5;3696:11;:18::i;:::-;3732:26;:5;3747:10;3732:14;:26::i;:::-;3776:39;3797:5;3804:10;3776:20;:39::i;:::-;-1:-1:-1;3617:3:69;;3579:251;;3968:1267;4056:13;;4033:20;4236:536;4260:12;4256:1;:16;4236:536;;;4297:34;4334:6;4341:1;4334:9;;;;;;;;:::i;:::-;;;;;;;4297:46;;4361:21;4385:13;:21;;;:28;4361:52;;4436:9;4431:217;4455:13;4451:1;:17;4431:217;;;4497:25;4525:13;:21;;;4547:1;4525:24;;;;;;;;:::i;:::-;;;;;;;4497:52;;4571:58;4597:6;:16;;;4615:6;:13;;;4571:6;:12;;;:25;;;;:58;;;;;:::i;:::-;-1:-1:-1;4470:3:69;;4431:217;;;;4704:13;:18;;;:26;;;4671:86;;4692:10;4671:86;;4676:6;4683:1;4676:9;;;;;;;;:::i;:::-;;;;;;;:14;;;4671:86;4732:13;:18;;;:24;;;4671:86;;;;20962:25:90;;20950:2;20935:18;;20816:177;4671:86:69;;;;;;;;-1:-1:-1;;4274:3:69;;4236:536;;;-1:-1:-1;5112:21:69;:25;5108:121;;5153:65;5184:10;5196:21;5153:30;:65::i;7182:373:68:-;2997:214;;21717:15:90;2997:214:68;;;21705:28:90;21763:17;21749:12;;;21742:39;21811:19;21797:12;;;21790:41;21861:26;21847:12;;;21840:48;21918:25;21904:12;;;21897:47;21974:30;21960:12;;;21953:52;7246:7:68;;22021:13:90;;2997:214:68;;;;;;;;;;;;;;22461:22:90;2997:214:68;4123:96;;22449:35:90;22514:25;22500:12;;;22493:47;22570:27;22556:12;;;22549:49;2997:214:68;22614:12:90;;4123:96:68;;;;;;;;;;4442:28;;;;;;;;;;4123:96;;;4442:28;4123:96;4442:28;;;3263:218;;;;;;;:::i;:::-;;;;;;;;;;;;;3672:249;;;;;;;:::i;:::-;;;;;;;;;;;;;;;4356:179;;;;;;3672:249;4356:179;;:::i;:::-;;;;;;;;;;;;;4585:21;;;;;;7356:17;:5;:10;;;:15;:17::i;:::-;7391:5;:14;;;7423:5;:21;;;7462;7467:5;:15;;;7462:4;:21::i;:::-;7501:23;7506:5;:17;;;7501:4;:23::i;:::-;7295:243;;;;;;26405:25:90;;;;26446:18;;26439:34;;;;26521:42;26509:55;;;26489:18;;;26482:83;26581:18;;;26574:34;26624:19;;;26617:35;26668:19;;;26661:35;26377:19;;7295:243:68;;;;;;;;;;;;;7272:276;;;;;;7265:283;;7182:373;;;:::o;5911:289:71:-;6009:10;;:19;;;6031:15;-1:-1:-1;6005:92:71;;;6069:17;;;;;;;;;;;;;;6005:92;6126:14;;;;6107:86;;6142:31;6126:5;6163:9;6142:20;:31::i;:::-;6175:5;:17;;;6107:18;:86::i;3627:985::-;3718:18;;;;:30;;;:35;3714:267;;3806:5;:15;;;:27;;;3773:5;:18;;;:30;;;:60;3769:128;;;3860:22;;;;;;;;;;;;;;3769:128;3940:18;;;;:30;;;;;3910:15;;;;:27;;:60;3714:267;4038:5;:17;;;:24;3995:5;:18;;;:32;;;:39;:67;3991:128;;4085:23;;;;;;;;;;;;;;3991:128;4152:17;;;;:24;4128:21;4186:420;4210:13;4206:1;:17;4186:420;;;4244:27;4274:5;:17;;;4292:1;4274:20;;;;;;;;:::i;:::-;;;;;;;4244:50;;4308:20;4331:5;:18;;;:32;;;4364:1;4331:35;;;;;;;;:::i;:::-;;;;;;;4308:58;;4384:12;4400:1;4384:17;4380:216;;4440:6;:18;;;4425:12;:33;4421:110;;;4489:23;;;;;;;;;;;;;;4421:110;4548:18;;;:33;;;4380:216;-1:-1:-1;;4225:3:71;;4186:420;;4618:1086;4748:19;4770:40;4788:5;:21;;;4770:13;:17;;:40;;;;:::i;:::-;4748:62;;4871:5;:15;;;:40;;;4915:1;4871:45;4867:308;;4932:17;5018:6;5003:12;4959:5;:15;;;:40;;;4952:63;;;;:::i;:::-;:72;;;;:::i;:::-;4932:92;;5084:80;5123:10;5135:1;5138:5;:15;;;:25;;;5084:5;:15;;;:27;;;:38;;:80;;;;;;:::i;:::-;5038:15;;;;:27;;:126;-1:-1:-1;4867:308:71;5255:17;;;;:24;5231:21;5289:409;5313:13;5309:1;:17;5289:409;;;5347:27;5377:5;:17;;;5395:1;5377:20;;;;;;;;:::i;:::-;;;;;;;5347:50;;5415:6;:31;;;5450:1;5415:36;5411:277;;5471:18;5549:6;5534:12;5499:6;:31;;;5492:54;;;;:::i;:::-;:63;;;;:::i;:::-;5637:16;;;;5594:18;;;;5471:84;;-1:-1:-1;5594:79:71;;:18;5471:84;;5655:17;5594:29;:79::i;:::-;5573:18;;;:100;-1:-1:-1;5411:277:71;-1:-1:-1;5328:3:71;;5289:409;;5897:331:62;6011:24;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;6011:24:62;6051:20;6074:74;6080:5;:11;;;6093:5;:17;;;6112:15;6129:1;6132:5;:15;;;6074:5;:74::i;:::-;6167:54;;;;;;;;;6178:11;;6167:54;;;;;;;;;;;6205:15;;;;;6167:54;;;;-1:-1:-1;6167:54:62;;5897:331;-1:-1:-1;;5897:331:62:o;5297:379::-;5482:14;;5416:27;;5482:14;5515:31;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;5515:31:62;;;;;;;;;;;;;;;5506:40;;5561:9;5556:114;5580:12;5576:1;:16;5556:114;;;5625:34;5631:7;5639:1;5631:10;;;;;;;;:::i;:::-;;;;;;;5643:15;5625:5;:34::i;:::-;5613:6;5620:1;5613:9;;;;;;;;:::i;:::-;;;;;;;;;;:46;5594:3;;5556:114;;;;5449:227;5297:379;;;;:::o;1709:306:59:-;1912:96;1937:5;1944:9;1955:14;1971:22;1995:12;1912:24;:96::i;1825:2185:46:-;1910:13;;1902:36;1910:13;1898:73;;1825:2185;:::o;1898:73::-;2015:13;;:34;;;;;1981:31;;2015:13;;;:27;;:34;;2043:5;;2015:34;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2083:13;;;;:20;2140:17;;1981:68;;-1:-1:-1;2083:20:46;2059:21;2294:32;2140:17;2083:20;2294:32;:::i;:::-;2276:51;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;2276:51:46;;;;;;;;;;;;;;;2242:85;;2343:9;2338:101;2362:13;2358:1;:17;2338:101;;;2412:5;:13;;;2426:1;2412:16;;;;;;;;:::i;:::-;;;;;;;2396:10;2407:1;2396:13;;;;;;;;:::i;:::-;;;;;;;;;;:32;2377:3;;2338:101;;;;2449:19;2486:18;2527:9;2522:1445;2546:16;2542:1;:20;2522:1445;;;2583:28;2614:10;2625:1;2614:13;;;;;;;;:::i;:::-;;;;;;;2583:44;;2682:9;2677:191;2701:1;2697;:5;2677:191;;;2750:10;2761:1;2750:13;;;;;;;;:::i;:::-;;;;;;;:19;;;2731:38;;:9;:15;;;:38;;;2727:127;;2819:15;;2800:35;;;;;2288:42:90;2276:55;;;2800:35:46;;;2258:74:90;2231:18;;2800:35:46;2094:244:90;2727:127:46;2704:3;;2677:191;;;-1:-1:-1;2933:18:46;;2965:354;2989:13;2985:1;:17;2965:354;;;3027:25;3055:5;:13;;;3069:1;3055:16;;;;;;;;:::i;:::-;;;;;;;3027:44;;3109:9;:15;;;3093:31;;:6;:12;;;:31;;;3089:216;;3152:13;3148:46;;;3174:20;;;;;;;;;;;;;;3148:46;3230:13;;;;3216:27;;;;:::i;:::-;;;3282:4;3265:21;;3089:216;-1:-1:-1;3004:3:46;;2965:354;;;-1:-1:-1;3415:15:46;;3393:11;;;;:17;3385:45;;;;;;;3381:219;;3454:14;3450:47;;;3477:20;;;;;;;;;;;;;;3450:47;3529:11;;;;;:18;;3515:32;;;;:::i;:::-;;;3581:4;3565:20;;3381:219;3618:10;3632:1;3618:15;3614:60;;3658:15;;3642:32;;;;;2288:42:90;2276:55;;;3642:32:46;;;2258:74:90;2231:18;;3642:32:46;2094:244:90;3614:60:46;3712:39;:10;1424:1;1373:6;3712:21;:39::i;:::-;3693:9;:16;;;:58;3689:171;;;3790:15;;3807:16;;;;3825:19;;;;;3778:67;;;;;29735:42:90;29804:15;;;3778:67:46;;;29786:34:90;29836:18;;;29829:34;;;;29899:15;;;;29879:18;;;29872:43;29698:18;;3778:67:46;29523:398:90;3689:171:46;3933:9;3901:10;3928:1;3912:13;:17;3901:29;;;;;;;;:::i;:::-;;;;;;;;;;:41;-1:-1:-1;;2564:3:46;;2522:1445;;;-1:-1:-1;;;3977:13:46;;;;:26;;;;-1:-1:-1;;;1825:2185:46:o;429:396:66:-;552:18;;:26;527:52;;535:4;527:52;523:106;;602:16;;;;;;;;;;;;;;523:106;651:18;;:47;;;643:70;;;639:180;;729:18;;:47;;;:79;;;;;:56;;;;;;;:79;;786:6;;729:13;;:79;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;429:396;;:::o;3277:344:71:-;3375:7;:33;;;3422:16;:5;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;509:303:64;;;572:149;;;;;641:11;;;;;;:17;572:149;;509:303;;;;572:149;;;685:11;;:21;;;572:149;;;;509:303;;742:10;;:16;;;509:303;;;;;;;782:10;;:19;;;;509:303;;;;;349:470;3422:16:71;-1:-1:-1;;;;;;;;;;;;;;;;;1071:90:64;;;;;;;;;;;;;1141:11;;;;:18;;;1071:90;;;;3491:5:71;:10;;;:18;;;3523:5;:10;;;4123:96:68;;;;;;22461:22:90;22449:35;;22514:25;22509:2;22500:12;;22493:47;22570:27;22565:2;22556:12;;22549:49;22623:2;22614:12;;22045:587;4123:96:68;;;;;;;;;;;4873:28;;;;;;;;;;4123:96;;;4873:28;4123:96;4873:28;;;4915:36;;;;;;;;;;;;;;;;;3263:218;;;;;;;:::i;:::-;;;;;;;;;;;;;;21717:15:90;3263:218:68;2997:214;;21705:28:90;21763:17;21749:12;;;21742:39;21811:19;21797:12;;;21790:41;21861:26;21847:12;;;21840:48;21918:25;21904:12;;;21897:47;21974:30;21960:12;;;21953:52;2997:214:68;;;;;;;;;22021:13:90;;;2997:214:68;;;3263:218;3672:249;;;;;:::i;:::-;;;;;;;;;;;;;;;4771:290;;;;;;;3672:249;4771:290;;:::i;:::-;;;;;;;;;;;;;;;3595:9:71;;;;3375:239;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1478:434:55;2501:18;;;1572:334;;1695:33;1710:9;1721:6;1695:14;:33::i;1572:334::-;1832:63;:32;;;1865:10;1877:9;1888:6;1832:32;:63::i;2084:189::-;2163:12;2180:9;:14;;2202:6;2180:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2162:51;;;2228:7;2223:43;;2244:22;;;;;;;;;;;;;;574:416:63;634:7;461:15;;;;;;;;;;;;;;;;;451:26;;;;;;;749:12;;779;;;;809:10;;;;;837:13;;;;868:33;;;;929:29;;;;919:40;;;;;;683:290;;;;809:10;;837:13;;868:33;;919:40;683:290;33720:25:90;;;33764:42;33842:15;;;33837:2;33822:18;;33815:43;33894:15;;;33889:2;33874:18;;33867:43;33941:2;33926:18;;33919:34;;;;33984:3;33969:19;;33962:35;34034:15;;;34028:3;34013:19;;34006:44;34081:3;34066:19;;34059:35;33707:3;33692:19;;33358:742;5474:376:68;5538:7;3263:218;;;;;;;:::i;:::-;;;;;;;;;;;;;;22461:22:90;3263:218:68;4123:96;;22449:35:90;22514:25;22500:12;;;22493:47;22570:27;22556:12;;;22549:49;4123:96:68;;;;;;;;;22614:12:90;;;4123:96:68;;;3558:60;;3263:218;;4123:96;3558:60;;;:::i;:::-;;;;;;;;;;;;;3548:71;;;;;;5657:5;:11;;;5686:5;:17;;;5721;5726:5;:11;;;5721:4;:17::i;:::-;5756:15;;;;;5789:30;;;;;5587:246;;;;;;34904:25:90;;;;34977:42;34965:55;;;34945:18;;;34938:83;;;;35037:18;;;35030:34;;;;35080:18;;35073:34;35123:19;;;35116:35;35167:19;;;35160:35;34876:19;;5587:246:68;34602:599:90;6522:539:68;6591:7;6634:25;6677:7;:14;6672:2;:19;6662:30;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6662:30:68;-1:-1:-1;6730:14:68;;6634:58;;-1:-1:-1;6706:21:68;6758:242;6782:13;6778:1;:17;6758:242;;;6820:18;6841:16;6846:7;6854:1;6846:10;;;;;;;;:::i;:::-;;;;;;;6841:4;:16::i;:::-;6949:4;6942:12;;;6913:42;;;6906:62;-1:-1:-1;6797:3:68;;6758:242;;;-1:-1:-1;;7021:23:68;;;;;;;;6522:539;-1:-1:-1;;6522:539:68:o;7698:196::-;7791:7;7844:9;7866:5;:18;;;7855:30;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;7827:59;;;7855:30;7827:59;;:::i;:::-;;;;;;;;;;;;;7817:70;;;;;;7810:77;;7698:196;;;;;:::o;532:351:54:-;631:9;642;666:11;655:43;;;;;;;;;;;;:::i;:::-;630:68;;;;708:7;724:11;736:2;724:15;;;;;;;;:::i;:::-;;;;;;;767:24;;;750:14;767:24;;;;;;;;;37082:25:90;;;724:15:54;;;;;37123:18:90;;;37116:45;;;37177:18;;;37170:34;;;37220:18;;;37213:34;;;724:15:54;-1:-1:-1;767:24:54;;37054:19:90;;767:24:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;750:41;;817:6;805:18;;:8;:18;;;;:42;;;-1:-1:-1;827:20:54;;;;805:42;801:75;;;856:20;;;;;;;;;;;;;;801:75;620:263;;;;532:351;;;:::o;2785:215:61:-;2843:6;2869:1;2865;:5;2861:133;;;2897:24;2915:5;2919:1;2915;:5;:::i;:::-;2897:17;:24::i;:::-;2893:28;;:1;:28;:::i;:::-;2886:35;;;;2861:133;2959:24;2977:5;2981:1;2977;:5;:::i;1203:152::-;1293:9;1318:30;1329:1;1332:5;1336:1;1293:9;1332:5;:::i;:::-;1339:3;1344;1318:10;:30::i;:::-;1314:34;1203:152;-1:-1:-1;;;;;1203:152:61:o;1857:629::-;1947:9;1976:1;1972;:5;1968:480;;;2054:12;2077:2;2078:1;2077:2;:::i;:::-;2054:26;-1:-1:-1;2155:1:61;2128:24;2054:26;2128:17;:24;:::i;:::-;:28;2124:77;;;2183:3;2176:10;;;;;2124:77;2218:8;2222:4;2218:1;:8;:::i;:::-;2214:12;;1979:258;1968:480;;;2325:1;2313;:14;2309:96;;;-1:-1:-1;2387:3:61;2380:10;;2309:96;2423:14;2435:1;2423;:14;:::i;:::-;2419:18;;1968:480;2461:18;2467:1;2470:3;2475;2461:5;:18::i;1857:629::-;;;;;;;:::o;1275:1056:62:-;1477:21;1603:2;1572:5;:21;;;:28;:33;1568:90;;;1628:19;;;;;;;;;;;;;;1568:90;1748:12;1729:15;:31;;:68;;;-1:-1:-1;1764:21:62;;;;:28;:33;1729:68;1725:145;;;1820:39;:11;1838:9;1849;1820:17;:39::i;:::-;1813:46;;;;1725:145;1880:17;1907:30;1922:15;1907:12;:30;:::i;:::-;1880:58;;1949:17;1968:15;1985:21;2008:19;2043:38;2063:5;2070:10;2043:19;:38::i;:::-;1948:133;;;;;;;;2141:17;2161:89;2187:10;2161:89;;2199:8;2161:89;;2209:10;2161:89;;2221:14;2237:12;2161:25;:89::i;:::-;2141:109;-1:-1:-1;2268:56:62;:11;2141:109;2303:9;2314;2268:22;:56::i;:::-;2261:63;1275:1056;-1:-1:-1;;;;;;;;;;;;1275:1056:62:o;4682:370::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;4839:21:62;4875:93;4881:6;:12;;;4895:6;:18;;;4915:15;4932:6;:16;;;4950:17;4875:5;:93::i;:::-;4839:129;;4987:58;;;;;;;;4999:6;:12;;;4987:58;;;;;;5013:13;4987:58;;;;5028:6;:16;;;4987:58;;;;;4978:67;;4829:223;4682:370;;;;:::o;2441:970:59:-;2750:60;2767:9;2778:14;2794:15;2750:16;:60::i;:::-;2826:7;2746:97;2947:22;2943:103;;3014:21;;;;;;;;;;;;;;2943:103;3131:13;;;;3100:28;3154:251;3178:7;:14;3174:1;:18;3154:251;;;3209:25;3237:7;3245:1;3237:10;;;;;;;;:::i;:::-;;;;;;;3209:38;;3277:57;3306:22;743:6;3300:28;;;;:::i;:::-;3277:13;;;;;743:6;3277:22;:57::i;:::-;3261:13;;;;:73;3377:3;;3154:251;;2441:970;;;;;;:::o;1564:526:43:-;1680:9;1928:1;1915:11;1911:19;1908:1;1905:26;1902:1;1898:34;1891:42;1878:11;1874:60;1864:116;;1964:1;1961;1954:12;1864:116;-1:-1:-1;2051:9:43;;2047:27;;1564:526::o;1328:1782:44:-;1466:12;1636:4;1630:11;1778:66;1759:17;1752:93;1902:42;1896:4;1892:53;1888:1;1869:17;1865:25;1858:88;2042:42;2038:2;2034:51;2029:2;2010:17;2006:26;1999:87;2172:6;2167:2;2148:17;2144:26;2137:42;3026:2;3023:1;3018:3;2999:17;2996:1;2989:5;2982;2977:52;2545:16;2538:24;2532:2;2514:16;2511:24;2507:1;2503;2497:8;2494:15;2490:46;2487:76;2287:756;2276:767;;;3071:7;3063:40;;;;;;;37994:2:90;3063:40:44;;;37976:21:90;38033:2;38013:18;;;38006:30;38072:22;38052:18;;;38045:50;38112:18;;3063:40:44;37792:344:90;5074:279:68;4123:96;;22461:22:90;4123:96:68;;;22449:35:90;22514:25;22500:12;;;22493:47;22570:27;22556:12;;;22549:49;5145:7:68;;22614:12:90;;4123:96:68;;;;;;;;;;;;4280:32;;;;;;5250:5;:20;;;5299:5;:21;;;5282:39;;;;;;;;:::i;:::-;;;;;;;;;;;;;;5272:50;;5282:39;5272:50;;;;5194:142;;;38891:25:90;;;;38932:18;;38925:34;;;;38975:18;;;38968:34;;;;38864:18;;5194:142:68;38689:319:90;5975:418:68;6041:7;3672:249;;;;;;;:::i;:::-;;;;;;;;;;;;;;22461:22:90;3672:249:68;4123:96;;22449:35:90;22514:25;22500:12;;;22493:47;22570:27;22556:12;;;22549:49;4123:96:68;;;;;;;;;22614:12:90;;;4123:96:68;;;3999:61;;3672:249;;4123:96;3999:61;;;:::i;:::-;;;;;;;;;;;;;3989:72;;;;;;6161:6;:12;;;6191:6;:18;;;6227;6232:6;:12;;;6227:4;:18::i;:::-;6263:16;;;;;6297;;;;;6331:31;;;;;6090:286;;;;;;39328:25:90;;;;39372:42;39450:15;;;39430:18;;;39423:43;39482:18;;;39475:34;;;;39525:18;;;39518:34;;;;39589:15;;;;39568:19;;;39561:44;;;;39621:19;;;39614:35;39665:19;;;39658:35;39300:19;;6090:286:68;39013:686:90;34781:297:34;34837:6;34979:16;34962:5;:34;;34954:87;;;;;;;39906:2:90;34954:87:34;;;39888:21:90;39945:2;39925:18;;;39918:30;39984:34;39964:18;;;39957:62;40055:10;40035:18;;;40028:38;40083:19;;34954:87:34;39704:404:90;34954:87:34;-1:-1:-1;35065:5:34;34781:297::o;3252:147:61:-;3331:7;3357:35;3366:20;3375:5;3382:3;3366:8;:20::i;:::-;3388:3;3357:8;:35::i;3235:1221:62:-;3374:17;3393:15;3410:18;3430:16;3462:26;3491:36;3506:5;:20;;;452:5:72;356:105;3491:36:62;3462:65;-1:-1:-1;3594:52:62;;;:28;3462:65;3620:1;3594:25;:28::i;:::-;:52;;;3590:152;;3670:1;3673:28;:14;3670:1;3673:25;:28::i;:::-;3703:1;3706:5;:21;;;3728:1;3706:24;;;;;;;;:::i;:::-;;;;;;;3662:69;;;;;;;;;;;3590:152;3751:21;3814:1;3782:5;:21;;;:28;3775:40;;;;:::i;:::-;3751:64;-1:-1:-1;3841:1:62;3825:385;3849:14;3844:19;;:1;:19;;;3825:385;;3920:20;3888:52;;:28;3914:1;3888:28;;:14;:25;;:28;;;;:::i;:::-;:52;;;3884:316;;3989:32;4015:5;4019:1;4015;:5;:::i;:::-;3989:14;;:32;;:25;:32::i;:::-;4043:28;:14;:28;;;:25;:28::i;:::-;4093:21;;;;4115:5;4119:1;4115;:5;:::i;:::-;4093:28;;;;;;;;;;:::i;:::-;;;;;;;4143:5;:21;;;4165:1;4143:24;;;;;;;;;;:::i;:::-;;;;;;;3960:225;;;;;;;;;;;;;3884:316;3865:3;;;;:::i;:::-;;;;3825:385;;;-1:-1:-1;4241:41:62;:14;:41;;;:25;:41::i;:::-;4296;:14;:41;;;:25;:41::i;:::-;4351:5;:21;;;4373:14;4351:37;;;;;;;;;;:::i;:::-;;;;;;;4402:5;:21;;;4424:14;4402:37;;;;;;;;;;:::i;:::-;;;;;;;4220:229;;;;;;;;;;3235:1221;;;;;;;;:::o;2928:695:56:-;3116:6;3154:8;3138:12;:24;3134:71;;-1:-1:-1;3185:9:56;3178:16;;3134:71;3214:15;3232:25;3247:10;3232:12;:25;:::i;:::-;3214:43;-1:-1:-1;3267:16:56;3286:21;3297:10;3286:8;:21;:::i;:::-;3267:40;;3317:12;3355:11;3343:9;:23;3339:242;;;3398:62;3442:7;3451:8;3406:23;3420:9;3406:11;:23;:::i;:::-;3398:43;:62;:43;:62::i;:::-;3390:71;;;:::i;:::-;3382:79;;3339:242;;;3507:62;3551:7;3560:8;3515:23;3527:11;3515:9;:23;:::i;3507:62::-;3492:78;;3339:242;3597:19;3611:5;3597:11;:19;:::i;:::-;3590:26;2928:695;-1:-1:-1;;;;;;;;;2928:695:56:o;3998:261:59:-;4139:4;4166:23;;;;;:59;;;4211:14;4193:15;:32;4166:59;:86;;;-1:-1:-1;4229:23:59;;;4242:10;4229:23;4159:93;;3998:261;;;;;:::o;2096:672:43:-;2210:9;2458:1;2445:11;2441:19;2438:1;2435:26;2432:1;2428:34;2421:42;2408:11;2404:60;2394:116;;2494:1;2491;2484:12;2394:116;-1:-1:-1;2728:9:43;;2691:27;;;2688:34;;2724:27;;;2684:68;;2096:672::o;413:104:33:-;471:7;501:1;497;:5;:13;;509:1;497:13;;;505:1;497:13;490:20;413:104;-1:-1:-1;;;413:104:33:o;588:::-;646:7;676:1;672;:5;:13;;684:1;672:13;;981:347:72;1059:6;1086:2;1081:1;:7;1077:63;;1111:18;;;;;;;;;;;;;;1077:63;-1:-1:-1;1199:2:72;1195:6;1238:45;;981:347::o;14:159:90:-;78:5;123:2;114:6;109:3;105:16;101:25;98:45;;;139:1;136;129:12;98:45;-1:-1:-1;161:6:90;14:159;-1:-1:-1;14:159:90:o;178:347::-;229:8;239:6;293:3;286:4;278:6;274:17;270:27;260:55;;311:1;308;301:12;260:55;-1:-1:-1;334:20:90;;377:18;366:30;;363:50;;;409:1;406;399:12;363:50;446:4;438:6;434:17;422:29;;498:3;491:4;482:6;474;470:19;466:30;463:39;460:59;;;515:1;512;505:12;460:59;178:347;;;;;:::o;530:673::-;641:6;649;657;710:2;698:9;689:7;685:23;681:32;678:52;;;726:1;723;716:12;678:52;766:9;753:23;795:18;836:2;828:6;825:14;822:34;;;852:1;849;842:12;822:34;875:71;938:7;929:6;918:9;914:22;875:71;:::i;:::-;865:81;;999:2;988:9;984:18;971:32;955:48;;1028:2;1018:8;1015:16;1012:36;;;1044:1;1041;1034:12;1012:36;;1083:60;1135:7;1124:8;1113:9;1109:24;1083:60;:::i;:::-;530:673;;1162:8;;-1:-1:-1;1057:86:90;;-1:-1:-1;;;;530:673:90:o;1208:387::-;1291:8;1301:6;1355:3;1348:4;1340:6;1336:17;1332:27;1322:55;;1373:1;1370;1363:12;1322:55;-1:-1:-1;1396:20:90;;1439:18;1428:30;;1425:50;;;1471:1;1468;1461:12;1425:50;1508:4;1500:6;1496:17;1484:29;;1568:3;1561:4;1551:6;1548:1;1544:14;1536:6;1532:27;1528:38;1525:47;1522:67;;;1585:1;1582;1575:12;1600:489;1718:6;1726;1779:2;1767:9;1758:7;1754:23;1750:32;1747:52;;;1795:1;1792;1785:12;1747:52;1835:9;1822:23;1868:18;1860:6;1857:30;1854:50;;;1900:1;1897;1890:12;1854:50;1939:90;2021:7;2012:6;2001:9;1997:22;1939:90;:::i;:::-;2048:8;;1913:116;;-1:-1:-1;1600:489:90;-1:-1:-1;;;;1600:489:90:o;2343:797::-;2481:6;2489;2497;2505;2558:2;2546:9;2537:7;2533:23;2529:32;2526:52;;;2574:1;2571;2564:12;2526:52;2614:9;2601:23;2643:18;2684:2;2676:6;2673:14;2670:34;;;2700:1;2697;2690:12;2670:34;2739:90;2821:7;2812:6;2801:9;2797:22;2739:90;:::i;:::-;2848:8;;-1:-1:-1;2713:116:90;-1:-1:-1;2936:2:90;2921:18;;2908:32;;-1:-1:-1;2952:16:90;;;2949:36;;;2981:1;2978;2971:12;2949:36;;3020:60;3072:7;3061:8;3050:9;3046:24;3020:60;:::i;:::-;2343:797;;;;-1:-1:-1;3099:8:90;-1:-1:-1;;;;2343:797:90:o;3145:154::-;3231:42;3224:5;3220:54;3213:5;3210:65;3200:93;;3289:1;3286;3279:12;3304:134;3372:20;;3401:31;3372:20;3401:31;:::i;:::-;3304:134;;;:::o;3443:247::-;3502:6;3555:2;3543:9;3534:7;3530:23;3526:32;3523:52;;;3571:1;3568;3561:12;3523:52;3610:9;3597:23;3629:31;3654:5;3629:31;:::i;3695:365::-;3786:6;3839:2;3827:9;3818:7;3814:23;3810:32;3807:52;;;3855:1;3852;3845:12;3807:52;3895:9;3882:23;3928:18;3920:6;3917:30;3914:50;;;3960:1;3957;3950:12;3914:50;3983:71;4046:7;4037:6;4026:9;4022:22;3983:71;:::i;4559:184::-;4611:77;4608:1;4601:88;4708:4;4705:1;4698:15;4732:4;4729:1;4722:15;4748:184;4800:77;4797:1;4790:88;4897:4;4894:1;4887:15;4921:4;4918:1;4911:15;4937:250;5022:1;5032:113;5046:6;5043:1;5040:13;5032:113;;;5122:11;;;5116:18;5103:11;;;5096:39;5068:2;5061:10;5032:113;;;-1:-1:-1;;5179:1:90;5161:16;;5154:27;4937:250::o;5192:329::-;5233:3;5271:5;5265:12;5298:6;5293:3;5286:19;5314:76;5383:6;5376:4;5371:3;5367:14;5360:4;5353:5;5349:16;5314:76;:::i;:::-;5435:2;5423:15;5440:66;5419:88;5410:98;;;;5510:4;5406:109;;5192:329;-1:-1:-1;;5192:329:90:o;5787:700::-;5851:3;5889:5;5883:12;5916:6;5911:3;5904:19;5942:4;5971;5966:3;5962:14;5955:21;;6010:4;6003:5;5999:16;6033:1;6043:419;6057:6;6054:1;6051:13;6043:419;;;6116:13;;6223:9;;6152:42;6219:18;;;6207:31;;6278:11;;;6272:18;6258:12;;;6251:40;6314:4;6362:11;;;6356:18;6352:27;6338:12;;;6331:49;6409:4;6400:14;;;;6437:15;;;;6079:1;6072:9;6043:419;;;-1:-1:-1;6478:3:90;;5787:700;-1:-1:-1;;;;;5787:700:90:o;6492:1240::-;6548:3;6592:5;6586:12;6619:4;6614:3;6607:17;6643:42;6742:2;6727:12;6721:19;6717:28;6710:4;6705:3;6701:14;6694:52;6813:2;6805:4;6791:12;6787:23;6781:30;6777:39;6771:3;6766;6762:13;6755:62;6872:4;6858:12;6854:23;6848:30;6842:3;6837;6833:13;6826:53;6934:4;6920:12;6916:23;6910:30;6904:3;6899;6895:13;6888:53;7008:2;7000:4;6986:12;6982:23;6976:30;6972:39;6966:3;6961;6957:13;6950:62;;7067:4;7053:12;7049:23;7043:30;7021:52;;7104:4;7098:3;7093;7089:13;7082:27;7131:47;7173:3;7168;7164:13;7148:14;7131:47;:::i;:::-;7118:60;;7226:4;7219:5;7215:16;7209:23;7241:60;7295:4;7290:3;7286:14;7270;5606:12;;5620:42;5602:61;5590:74;;5713:4;5702:16;;;5696:23;5680:14;;;5673:47;5769:4;5758:16;;;5752:23;5736:14;;5729:47;5526:256;7241:60;;7349:4;7342:5;7338:16;7332:23;7398:3;7391:5;7387:15;7380:4;7375:3;7371:14;7364:39;7424:62;7480:5;7464:14;7424:62;:::i;:::-;7412:74;;;7534:4;7527:5;7523:16;7517:23;7582:3;7576:4;7572:14;7565:4;7560:3;7556:14;7549:38;7610;7643:4;7627:14;7610:38;:::i;:::-;7596:52;;;7697:4;7690:5;7686:16;7680:23;7673:4;7668:3;7664:14;7657:47;7720:6;7713:13;;;6492:1240;;;;:::o;7737:1274::-;7999:4;8047:2;8036:9;8032:18;8077:2;8066:9;8059:21;8100:6;8135;8129:13;8166:6;8158;8151:22;8204:2;8193:9;8189:18;8182:25;;8266:2;8256:6;8253:1;8249:14;8238:9;8234:30;8230:39;8216:53;;8288:4;8327:2;8319:6;8315:15;8348:1;8358:328;8372:6;8369:1;8366:13;8358:328;;;8461:66;8449:9;8441:6;8437:22;8433:95;8428:3;8421:108;8552:54;8599:6;8590;8584:13;8552:54;:::i;:::-;8542:64;-1:-1:-1;8664:12:90;;;;8629:15;;;;8394:1;8387:9;8358:328;;;8362:3;;8734:9;8726:6;8722:22;8717:2;8706:9;8702:18;8695:50;8769:6;8761;8754:22;8823:6;8815;8810:2;8802:6;8798:15;8785:45;8876:1;8850:19;;;8846:28;;8839:39;8927:2;8915:15;;;8932:66;8911:88;8899:101;;;8895:110;;;;7737:1274;-1:-1:-1;;;;;;7737:1274:90:o;9016:388::-;9114:4;9172:11;9159:25;9262:66;9251:8;9235:14;9231:29;9227:102;9207:18;9203:127;9193:155;;9344:1;9341;9334:12;9193:155;9365:33;;;;;9016:388;-1:-1:-1;;9016:388:90:o;10442:580::-;10519:4;10525:6;10585:11;10572:25;10675:66;10664:8;10648:14;10644:29;10640:102;10620:18;10616:127;10606:155;;10757:1;10754;10747:12;10606:155;10784:33;;10836:20;;;-1:-1:-1;10879:18:90;10868:30;;10865:50;;;10911:1;10908;10901:12;10865:50;10944:4;10932:17;;-1:-1:-1;10975:14:90;10971:27;;;10961:38;;10958:58;;;11012:1;11009;11002:12;11027:253;11099:2;11093:9;11141:4;11129:17;;11176:18;11161:34;;11197:22;;;11158:62;11155:88;;;11223:18;;:::i;:::-;11259:2;11252:22;11027:253;:::o;11285:257::-;11357:4;11351:11;;;11389:17;;11436:18;11421:34;;11457:22;;;11418:62;11415:88;;;11483:18;;:::i;11547:253::-;11619:2;11613:9;11661:4;11649:17;;11696:18;11681:34;;11717:22;;;11678:62;11675:88;;;11743:18;;:::i;11805:253::-;11877:2;11871:9;11919:4;11907:17;;11954:18;11939:34;;11975:22;;;11936:62;11933:88;;;12001:18;;:::i;12063:253::-;12135:2;12129:9;12177:4;12165:17;;12212:18;12197:34;;12233:22;;;12194:62;12191:88;;;12259:18;;:::i;12321:334::-;12392:2;12386:9;12448:2;12438:13;;12453:66;12434:86;12422:99;;12551:18;12536:34;;12572:22;;;12533:62;12530:88;;;12598:18;;:::i;:::-;12634:2;12627:22;12321:334;;-1:-1:-1;12321:334:90:o;12660:589::-;12702:5;12755:3;12748:4;12740:6;12736:17;12732:27;12722:55;;12773:1;12770;12763:12;12722:55;12809:6;12796:20;12835:18;12831:2;12828:26;12825:52;;;12857:18;;:::i;:::-;12901:114;13009:4;12940:66;12933:4;12929:2;12925:13;12921:86;12917:97;12901:114;:::i;:::-;13040:2;13031:7;13024:19;13086:3;13079:4;13074:2;13066:6;13062:15;13058:26;13055:35;13052:55;;;13103:1;13100;13093:12;13052:55;13168:2;13161:4;13153:6;13149:17;13142:4;13133:7;13129:18;13116:55;13216:1;13191:16;;;13209:4;13187:27;13180:38;;;;13195:7;12660:589;-1:-1:-1;;;12660:589:90:o;13254:894::-;13310:5;13358:4;13346:9;13341:3;13337:19;13333:30;13330:50;;;13376:1;13373;13366:12;13330:50;13398:22;;:::i;:::-;13389:31;;13457:9;13444:23;13476:33;13501:7;13476:33;:::i;:::-;13518:22;;13592:2;13577:18;;13564:32;13605:33;13564:32;13605:33;:::i;:::-;13670:7;13665:2;13658:5;13654:14;13647:31;;13738:2;13727:9;13723:18;13710:32;13705:2;13698:5;13694:14;13687:56;13803:2;13792:9;13788:18;13775:32;13770:2;13763:5;13759:14;13752:56;13860:3;13849:9;13845:19;13832:33;13874;13899:7;13874:33;:::i;:::-;13934:3;13923:15;;13916:32;13999:3;13984:19;;13971:33;14027:18;14016:30;;14013:50;;;14059:1;14056;14049:12;14013:50;14096:45;14137:3;14128:6;14117:9;14113:22;14096:45;:::i;:::-;14090:3;14083:5;14079:15;14072:70;;13254:894;;;;:::o;14153:182::-;14212:4;14245:18;14237:6;14234:30;14231:56;;;14267:18;;:::i;:::-;-1:-1:-1;14312:1:90;14308:14;14324:4;14304:25;;14153:182::o;14340:971::-;14406:5;14454:4;14442:9;14437:3;14433:19;14429:30;14426:50;;;14472:1;14469;14462:12;14426:50;14494:22;;:::i;:::-;14485:31;;14552:9;14539:23;14532:5;14525:38;14582:2;14635;14624:9;14620:18;14607:32;14662:18;14654:6;14651:30;14648:50;;;14694:1;14691;14684:12;14648:50;14717:22;;14770:4;14762:13;;14758:23;-1:-1:-1;14748:51:90;;14795:1;14792;14785:12;14748:51;14831:2;14818:16;14854:59;14870:42;14909:2;14870:42;:::i;:::-;14854:59;:::i;:::-;14947:15;;;15029:1;15025:10;;;;15017:19;;15013:28;;;14978:12;;;;15053:15;;;15050:35;;;15081:1;15078;15071:12;15050:35;15105:11;;;;15125:142;15141:6;15136:3;15133:15;15125:142;;;15207:17;;15195:30;;15158:12;;;;15245;;;;15125:142;;;15299:5;15294:2;15287:5;15283:14;15276:29;;;;;;14340:971;;;;:::o;15316:705::-;15375:5;15423:4;15411:9;15406:3;15402:19;15398:30;15395:50;;;15441:1;15438;15431:12;15395:50;15463:22;;:::i;:::-;15454:31;;15522:9;15509:23;15541:33;15566:7;15541:33;:::i;:::-;15583:22;;15665:2;15650:18;;;15637:32;15621:14;;;15614:56;15721:2;15706:18;;15693:32;15748:18;15737:30;;15734:50;;;15780:1;15777;15770:12;15734:50;15816:66;15878:3;15869:6;15858:9;15854:22;15816:66;:::i;:::-;15811:2;15804:5;15800:14;15793:90;;15943:2;15932:9;15928:18;15915:32;15910:2;15903:5;15899:14;15892:56;16009:3;15998:9;15994:19;15981:33;15975:3;15968:5;15964:15;15957:58;15316:705;;;;:::o;16026:2047::-;16093:5;16146:3;16139:4;16131:6;16127:17;16123:27;16113:55;;16164:1;16161;16154:12;16113:55;16200:6;16187:20;16226:4;16250:59;16266:42;16305:2;16266:42;:::i;16250:59::-;16343:15;;;16429:1;16425:10;;;;16413:23;;16409:32;;;16374:12;;;;16453:15;;;16450:35;;;16481:1;16478;16471:12;16450:35;16517:2;16509:6;16505:15;16529:1515;16545:6;16540:3;16537:15;16529:1515;;;16631:3;16618:17;16658:18;16708:2;16695:11;16692:19;16689:109;;;16752:1;16781:2;16777;16770:14;16689:109;16833:11;16825:6;16821:24;16811:34;;16868:4;16979:2;16910:66;16905:2;16900:3;16896:12;16892:85;16888:94;16885:184;;;17023:1;17052:2;17048;17041:14;16885:184;17095:22;;:::i;:::-;17166:2;17162;17158:11;17145:25;17183:33;17208:7;17183:33;:::i;:::-;17229:22;;17274:2;17325:11;;;17312:25;17296:14;;;17289:49;17361:2;17405:11;;;17392:25;17433:16;;;17430:109;;;17491:1;17521:3;17516;17509:16;17430:109;17575:70;17641:3;17636:2;17625:8;17621:2;17617:17;17613:26;17575:70;:::i;:::-;17570:2;17563:5;17559:14;17552:94;;17670:3;17659:14;;17722:3;17718:2;17714:12;17701:26;17686:41;;17740:33;17765:7;17740:33;:::i;:::-;17793:14;;17786:31;17841:3;17894:12;;;17881:26;17864:15;;;17857:51;;;;17958:11;;17945:25;17928:15;;;17921:50;17984:18;;18022:12;;;;16562;;16529:1515;;;-1:-1:-1;18062:5:90;16026:2047;-1:-1:-1;;;;;;16026:2047:90:o;18078:1234::-;18137:5;18185:4;18173:9;18168:3;18164:19;18160:30;18157:50;;;18203:1;18200;18193:12;18157:50;18225:22;;:::i;:::-;18216:31;;18283:9;18270:23;18263:5;18256:38;18313:2;18367;18356:9;18352:18;18339:32;18380:33;18405:7;18380:33;:::i;:::-;18445:7;18440:2;18433:5;18429:14;18422:31;;18513:2;18502:9;18498:18;18485:32;18480:2;18473:5;18469:14;18462:56;18578:2;18567:9;18563:18;18550:32;18545:2;18538:5;18534:14;18527:56;18634:3;18623:9;18619:19;18606:33;18662:18;18654:6;18651:30;18648:50;;;18694:1;18691;18684:12;18648:50;18717:22;;18770:4;18762:13;;18758:23;-1:-1:-1;18748:51:90;;18795:1;18792;18785:12;18748:51;18831:2;18818:16;18854:59;18870:42;18909:2;18870:42;:::i;18854:59::-;18947:15;;;19029:1;19025:10;;;;19017:19;;19013:28;;;18978:12;;;;19053:15;;;19050:35;;;19081:1;19078;19071:12;19050:35;19105:11;;;;19125:142;19141:6;19136:3;19133:15;19125:142;;;19207:17;;19195:30;;19158:12;;;;19245;;;;19125:142;;;19294:3;19283:15;;19276:30;-1:-1:-1;19287:5:90;;18078:1234;-1:-1:-1;;;;;18078:1234:90:o;19317:1494::-;19407:6;19460:2;19448:9;19439:7;19435:23;19431:32;19428:52;;;19476:1;19473;19466:12;19428:52;19516:9;19503:23;19545:18;19586:2;19578:6;19575:14;19572:34;;;19602:1;19599;19592:12;19572:34;19625:22;;;;19681:4;19663:16;;;19659:27;19656:47;;;19699:1;19696;19689:12;19656:47;19725:22;;:::i;:::-;19785:2;19772:16;19813:2;19803:8;19800:16;19797:36;;;19829:1;19826;19819:12;19797:36;19856:55;19903:7;19892:8;19888:2;19884:17;19856:55;:::i;:::-;19849:5;19842:70;;19944:31;19971:2;19967;19963:11;19944:31;:::i;:::-;19939:2;19932:5;19928:14;19921:55;20029:2;20025;20021:11;20008:25;20003:2;19996:5;19992:14;19985:49;20080:2;20076;20072:11;20059:25;20109:2;20099:8;20096:16;20093:36;;;20125:1;20122;20115:12;20093:36;20161:58;20211:7;20200:8;20196:2;20192:17;20161:58;:::i;:::-;20156:2;20149:5;20145:14;20138:82;;20266:3;20262:2;20258:12;20245:26;20296:2;20286:8;20283:16;20280:36;;;20312:1;20309;20302:12;20280:36;20349:69;20410:7;20399:8;20395:2;20391:17;20349:69;:::i;:::-;20343:3;20336:5;20332:15;20325:94;;20465:3;20461:2;20457:12;20444:26;20495:2;20485:8;20482:16;20479:36;;;20511:1;20508;20501:12;20479:36;20548:58;20598:7;20587:8;20583:2;20579:17;20548:58;:::i;:::-;20542:3;20535:5;20531:15;20524:83;;20653:3;20649:2;20645:12;20632:26;20683:2;20673:8;20670:16;20667:36;;;20699:1;20696;20689:12;20667:36;20736:44;20772:7;20761:8;20757:2;20753:17;20736:44;:::i;:::-;20730:3;20719:15;;20712:69;-1:-1:-1;20723:5:90;19317:1494;-1:-1:-1;;;;;19317:1494:90:o;22822:1010::-;23541:15;23529:28;;23587:16;23582:2;23573:12;;23566:38;23634:22;23629:2;23620:12;;23613:44;23687:28;23682:2;23673:12;;23666:50;23746:20;23741:2;23732:12;;23725:42;22714:34;23822:2;23813:12;;22702:47;22779:3;22765:12;;;22758:25;-1:-1:-1;22799:12:90;;;23783:43;22637:180;23837:1164;24657:16;24645:29;;24704:16;24699:2;24690:12;;24683:38;24751:22;24746:2;24737:12;;24730:44;24804:28;24799:2;24790:12;;24783:50;24863:20;24858:2;24849:12;;24842:42;24914:20;24909:2;24900:12;;24893:42;22714:34;24990:3;24981:13;;22702:47;22779:3;22765:12;;;22758:25;-1:-1:-1;22799:12:90;;;24951:44;22637:180;25006:1107;25319:3;25357:6;25351:13;25373:66;25432:6;25427:3;25420:4;25412:6;25408:17;25373:66;:::i;:::-;25502:13;;25461:16;;;;25524:70;25502:13;25461:16;25571:4;25559:17;;25524:70;:::i;:::-;25661:13;;25616:20;;;25683:70;25661:13;25616:20;25730:4;25718:17;;25683:70;:::i;:::-;25820:13;;25775:20;;;25842:70;25820:13;25775:20;25889:4;25877:17;;25842:70;:::i;:::-;25979:13;;25934:20;;;26001:70;25979:13;25934:20;26048:4;26036:17;;26001:70;:::i;:::-;26087:20;;25006:1107;-1:-1:-1;;;;;;;25006:1107:90:o;26707:184::-;26759:77;26756:1;26749:88;26856:4;26853:1;26846:15;26880:4;26877:1;26870:15;26896:292;26968:9;;;26935:7;26993:9;;27010:66;27004:73;;26989:89;26986:115;;;27081:18;;:::i;:::-;27154:1;27145:7;27140:16;27137:1;27134:23;27130:1;27123:9;27120:38;27110:72;;27162:18;;:::i;27193:462::-;27232:1;27258;27248:189;;27293:77;27290:1;27283:88;27394:4;27391:1;27384:15;27422:4;27419:1;27412:15;27248:189;27534:66;27531:1;27528:73;27459:66;27456:1;27453:73;27449:153;27446:179;;;27605:18;;:::i;:::-;-1:-1:-1;27639:10:90;;27193:462::o;27660:278::-;27853:2;27842:9;27835:21;27816:4;27873:59;27928:2;27917:9;27913:18;27905:6;27873:59;:::i;27943:1445::-;28068:6;28099:2;28142;28130:9;28121:7;28117:23;28113:32;28110:52;;;28158:1;28155;28148:12;28110:52;28191:9;28185:16;28224:18;28216:6;28213:30;28210:50;;;28256:1;28253;28246:12;28210:50;28279:22;;28332:4;28324:13;;28320:27;-1:-1:-1;28310:55:90;;28361:1;28358;28351:12;28310:55;28390:2;28384:9;28413:59;28429:42;28468:2;28429:42;:::i;28413:59::-;28506:15;;;28568:4;28607:13;;;28599:22;;28595:31;;;28537:12;;;;28494:3;28638:19;;;28635:39;;;28670:1;28667;28660:12;28635:39;28694:11;;;;28714:644;28730:6;28725:3;28722:15;28714:644;;;28810:2;28804:3;28795:7;28791:17;28787:26;28784:116;;;28854:1;28883:2;28879;28872:14;28784:116;28926:22;;:::i;:::-;28982:3;28976:10;28999:33;29024:7;28999:33;:::i;:::-;29045:22;;29109:12;;;29103:19;29087:14;;;29080:43;29146:2;29182:12;;;29176:19;29208:33;29176:19;29208:33;:::i;:::-;29261:14;;;29254:31;29298:18;;28747:12;;;;29336;;;;28714:644;;;-1:-1:-1;29377:5:90;27943:1445;-1:-1:-1;;;;;;;27943:1445:90:o;29393:125::-;29458:9;;;29479:10;;;29476:36;;;29492:18;;:::i;29926:398::-;30159:42;30151:6;30147:55;30136:9;30129:74;30239:2;30234;30223:9;30219:18;30212:30;30110:4;30259:59;30314:2;30303:9;30299:18;30291:6;30259:59;:::i;30329:1510::-;30821:23;30816:3;30809:36;30791:3;30864:2;30895:6;30889:13;30921:4;30934:73;31000:6;30995:2;30990:3;30986:12;30981:2;30973:6;30969:15;30934:73;:::i;:::-;31067:13;;31026:16;;;;31089:74;31067:13;31141:11;;;31124:15;;;31089:74;:::i;:::-;31224:13;;31182:17;;;31246:74;31224:13;31298:11;;;31281:15;;;31246:74;:::i;:::-;31381:13;;31339:17;;;31403:74;31381:13;31455:11;;;31438:15;;;31403:74;:::i;:::-;31538:13;;31496:17;;;31560:74;31538:13;31612:11;;;31595:15;;;31560:74;:::i;:::-;31695:13;;31653:17;;;31717:74;31695:13;31769:11;;;31752:15;;;31717:74;:::i;:::-;31811:17;;;;31807:26;;;;30329:1510;-1:-1:-1;;;;;;;;;30329:1510:90:o;32055:1088::-;32485:4;32514:3;32526:60;32576:9;32567:6;32561:13;31930:12;;31944:42;31926:61;31914:74;;32037:4;32026:16;;;32020:23;32004:14;;31997:47;31844:206;32526:60;32642:4;32634:6;32630:17;32624:24;32617:4;32606:9;32602:20;32595:54;32705:4;32697:6;32693:17;32687:24;32680:4;32669:9;32665:20;32658:54;32721:63;32779:3;32768:9;32764:19;32756:6;31930:12;;31944:42;31926:61;31914:74;;32037:4;32026:16;;;32020:23;32004:14;;31997:47;31844:206;32721:63;32833:42;32825:6;32821:55;32815:3;32804:9;32800:19;32793:84;32914:6;32908:3;32897:9;32893:19;32886:35;32958:2;32952:3;32941:9;32937:19;32930:31;32984:44;33024:2;33013:9;33009:18;33001:6;32984:44;:::i;:::-;32970:58;;33077:9;33069:6;33065:22;33059:3;33048:9;33044:19;33037:51;33105:32;33130:6;33122;33105:32;:::i;34105:492::-;34280:3;34318:6;34312:13;34334:66;34393:6;34388:3;34381:4;34373:6;34369:17;34334:66;:::i;:::-;34463:13;;34422:16;;;;34485:70;34463:13;34422:16;34532:4;34520:17;;34485:70;:::i;:::-;34571:20;;34105:492;-1:-1:-1;;;;34105:492:90:o;35206:1030::-;35360:4;35389:2;35418;35407:9;35400:21;35459:3;35448:9;35444:19;35505:6;35499:13;35494:2;35483:9;35479:18;35472:41;35577:42;35571:2;35563:6;35559:15;35553:22;35549:71;35544:2;35533:9;35529:18;35522:99;35675:2;35667:6;35663:15;35657:22;35652:2;35641:9;35637:18;35630:50;35735:2;35727:6;35723:15;35717:22;35711:3;35700:9;35696:19;35689:51;35787:3;35779:6;35775:16;35769:23;35830:4;35823;35812:9;35808:20;35801:34;35855:6;35890:12;35884:19;35927:6;35919;35912:22;35965:3;35954:9;35950:19;35943:26;;36010:2;35996:12;35992:21;35978:35;;36031:1;36022:10;;36041:169;36055:6;36052:1;36049:13;36041:169;;;36116:13;;36104:26;;36185:15;;;;36077:1;36070:9;;;;;36150:12;;;;36041:169;;36241:359;36428:6;36423:3;36416:19;36398:3;36464:6;36458:13;36480:73;36546:6;36541:2;36536:3;36532:12;36527:2;36519:6;36515:15;36480:73;:::i;:::-;36573:16;;;;36591:2;36569:25;;36241:359;-1:-1:-1;;;36241:359:90:o;36605:245::-;36684:6;36692;36745:2;36733:9;36724:7;36720:23;36716:32;36713:52;;;36761:1;36758;36751:12;36713:52;-1:-1:-1;;36784:16:90;;36840:2;36825:18;;;36819:25;36784:16;;36819:25;;-1:-1:-1;36605:245:90:o;37258:128::-;37325:9;;;37346:11;;;37343:37;;;37360:18;;:::i;37391:200::-;37457:9;;;37430:4;37485:9;;37513:10;;37525:12;;;37509:29;37548:12;;;37540:21;;37506:56;37503:82;;;37565:18;;:::i;:::-;37503:82;37391:200;;;;:::o;37596:191::-;37631:3;37662:66;37655:5;37652:77;37649:103;;37732:18;;:::i;:::-;-1:-1:-1;37772:1:90;37768:13;;37596:191::o;38141:543::-;38357:13;;38300:3;;38331;;38410:4;38437:17;;;38300:3;38482:175;38496:6;38493:1;38490:13;38482:175;;;38559:13;;38545:28;;38595:14;;;;38632:15;;;;38518:1;38511:9;38482:175;;;-1:-1:-1;38673:5:90;;38141:543;-1:-1:-1;;;;;;38141:543:90:o;40113:171::-;40181:6;40220:10;;;40208;;;40204:27;;40243:12;;;40240:38;;;40258:18;;:::i;40289:197::-;40327:3;40355:6;40396:2;40389:5;40385:14;40423:2;40414:7;40411:15;40408:41;;40429:18;;:::i;:::-;40478:1;40465:15;;40289:197;-1:-1:-1;;;40289:197:90:o;40491:216::-;40555:9;;;40583:11;;;40530:3;40613:9;;40641:10;;40637:19;;40666:10;;40658:19;;40634:44;40631:70;;;40681:18;;:::i","linkReferences":{},"immutableReferences":{"55632":[{"start":224,"length":32},{"start":6745,"length":32}]}},"methodIdentifiers":{"execute((bytes,bytes))":"3f62192e","executeBatch((bytes,bytes)[])":"0d7a16c3","executeBatchWithCallback((bytes,bytes)[],bytes)":"13fb72c7","executeWithCallback((bytes,bytes),bytes)":"0d335884","feeController()":"6999b377","owner()":"8da5cb5b","permit2()":"12261ee7","setProtocolFeeController(address)":"2d771389","transferOwnership(address)":"f2fde38b"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IPermit2\",\"name\":\"_permit2\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_protocolFeeOwner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"DeadlineReached\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"duplicateToken\",\"type\":\"address\"}],\"name\":\"DuplicateFeeOutput\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"FeeTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfBounds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InputAndOutputFees\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCosignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCosignerInput\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCosignerOutput\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDecayCurve\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"}],\"name\":\"InvalidFeeToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReactor\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoExclusiveOverride\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"orderHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"filler\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"swapper\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"Fill\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldFeeController\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeController\",\"type\":\"address\"}],\"name\":\"ProtocolFeeControllerSet\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"order\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"struct SignedOrder\",\"name\":\"order\",\"type\":\"tuple\"}],\"name\":\"execute\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"order\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"struct SignedOrder[]\",\"name\":\"orders\",\"type\":\"tuple[]\"}],\"name\":\"executeBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"order\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"struct SignedOrder[]\",\"name\":\"orders\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"callbackData\",\"type\":\"bytes\"}],\"name\":\"executeBatchWithCallback\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"order\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"struct SignedOrder\",\"name\":\"order\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"callbackData\",\"type\":\"bytes\"}],\"name\":\"executeWithCallback\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeController\",\"outputs\":[{\"internalType\":\"contract IProtocolFeeController\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permit2\",\"outputs\":[{\"internalType\":\"contract IPermit2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newFeeController\",\"type\":\"address\"}],\"name\":\"setProtocolFeeController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"V3 orders must be cosigned by the specified cosigner to set the starting block and override the valueresolution behavior: - If cosignature is invalid or not from specified cosigner, revert - If inputAmount is 0, then use baseInput - If inputAmount is nonzero, then ensure it is less than specified baseInput and replace startAmount - For each outputAmount: - If amount is 0, then use baseOutput - If amount is nonzero, then ensure it is greater than specified baseOutput and replace startAmount\",\"events\":{\"Fill(bytes32,address,address,uint256)\":{\"params\":{\"filler\":\"The address which executed the fill\",\"nonce\":\"The nonce of the filled order\",\"orderHash\":\"The hash of the order that was filled\",\"swapper\":\"The swapper of the filled order\"}}},\"kind\":\"dev\",\"methods\":{\"execute((bytes,bytes))\":{\"params\":{\"order\":\"The order definition and valid signature to execute\"}},\"executeBatch((bytes,bytes)[])\":{\"params\":{\"orders\":\"The order definitions and valid signatures to execute\"}},\"executeBatchWithCallback((bytes,bytes)[],bytes)\":{\"params\":{\"callbackData\":\"The callbackData to pass to the callback\",\"orders\":\"The order definitions and valid signatures to execute\"}},\"executeWithCallback((bytes,bytes),bytes)\":{\"params\":{\"callbackData\":\"The callbackData to pass to the callback\",\"order\":\"The order definition and valid signature to execute\"}},\"setProtocolFeeController(address)\":{\"details\":\"only callable by the owner\",\"params\":{\"_newFeeController\":\"the new fee controller\"}}},\"version\":1},\"userdoc\":{\"errors\":{\"DeadlineReached()\":[{\"notice\":\"thrown when an order's deadline is passed\"}],\"DuplicateFeeOutput(address)\":[{\"notice\":\"thrown if two fee outputs have the same token\"}],\"FeeTooLarge(address,uint256,address)\":[{\"notice\":\"thrown if a given fee output is greater than MAX_FEE_BPS of the order outputs\"}],\"InputAndOutputFees()\":[{\"notice\":\"thrown if fees are taken on both inputs and outputs\"}],\"InvalidCosignature()\":[{\"notice\":\"thrown when an order's cosignature does not match the expected cosigner\"}],\"InvalidCosignerInput()\":[{\"notice\":\"thrown when an order's cosigner input is greater than the specified\"}],\"InvalidCosignerOutput()\":[{\"notice\":\"thrown when an order's cosigner output is less than the specified\"}],\"InvalidDecayCurve()\":[{\"notice\":\"thrown when the decay curve is invalid\"}],\"InvalidFeeToken(address)\":[{\"notice\":\"thrown if a fee output token does not have a corresponding non-fee output\"}],\"InvalidReactor()\":[{\"notice\":\"thrown when the order targets a different reactor\"}],\"NativeTransferFailed()\":[{\"notice\":\"Thrown when a native transfer fails\"}],\"NoExclusiveOverride()\":[{\"notice\":\"thrown when an order has strict exclusivity and the filler does not have it\"}]},\"events\":{\"Fill(bytes32,address,address,uint256)\":{\"notice\":\"emitted when an order is filled\"}},\"kind\":\"user\",\"methods\":{\"execute((bytes,bytes))\":{\"notice\":\"Execute a single order\"},\"executeBatch((bytes,bytes)[])\":{\"notice\":\"Execute the given orders at once\"},\"executeBatchWithCallback((bytes,bytes)[],bytes)\":{\"notice\":\"Execute the given orders at once using a callback with the given callback data\"},\"executeWithCallback((bytes,bytes),bytes)\":{\"notice\":\"Execute a single order using the given callback data\"},\"permit2()\":{\"notice\":\"permit2 address used for token transfers and signature verification\"},\"setProtocolFeeController(address)\":{\"notice\":\"sets the protocol fee controller\"}},\"notice\":\"Reactor for V3 dutch orders\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/reactors/V3DutchOrderReactor.sol\":\"V3DutchOrderReactor\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-gas-snapshot/=lib/forge-gas-snapshot/src/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/\",\":openzeppelin/=lib/openzeppelin-contracts/contracts/\",\":permit2/=lib/permit2/\",\":solarray/=lib/solarray/src/\",\":solmate/=lib/solmate/\"]},\"sources\":{\"lib/openzeppelin-contracts/contracts/security/ReentrancyGuard.sol\":{\"keccak256\":\"0xa535a5df777d44e945dd24aa43a11e44b024140fc340ad0dfe42acf4002aade1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://41319e7f621f2dc3733511332c4fd032f8e32ad2aa7fd6f665c19741d9941a34\",\"dweb:/ipfs/QmcYR3bd862GD1Bc7jwrU9bGxrhUu5na1oP964bDCu2id1\"]},\"lib/openzeppelin-contracts/contracts/utils/math/Math.sol\":{\"keccak256\":\"0xe4455ac1eb7fc497bb7402579e7b4d64d928b846fce7d2b6fde06d366f21c2b3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cc8841b3cd48ad125e2f46323c8bad3aa0e88e399ec62acb9e57efa7e7c8058c\",\"dweb:/ipfs/QmSqE4mXHA2BXW58deDbXE8MTcsL5JSKNDbm23sVQxRLPS\"]},\"lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol\":{\"keccak256\":\"0x52a8cfb0f5239d11b457dcdd1b326992ef672714ca8da71a157255bddd13f3ad\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://495145362c7ff1c9ca88c58bbbbcb412e3c2004406647412394486552ff6c278\",\"dweb:/ipfs/QmNNCeng6d5eRPDn6tkWSQhjE39XWfQEfjA63rRwHmr1iH\"]},\"lib/permit2/src/interfaces/IAllowanceTransfer.sol\":{\"keccak256\":\"0x78931704a7f1d89ef24244b155863abb751cc3b3818f64303ccb47a396d48dcb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b8d6e198ee29d809564f1c1d7caa11a2c329bb5d051f61210548e546493444d2\",\"dweb:/ipfs/QmVxWftbgETjudymgLdwF77S54DWrp6qB5ooauKXW81cm7\"]},\"lib/permit2/src/interfaces/IEIP712.sol\":{\"keccak256\":\"0xea70db68ce450ad38dfbd490058595441144808eb95272ae9b89e3fbe6456954\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://e8fad9ff319665acdc2f1295bb82db3e5b4d52babc0b58f147dbdbb9f322c6e5\",\"dweb:/ipfs/QmTbYJPcux8eJ3qGVYQh6TiwCA2FPu6HXTUg6QFTnX91Ks\"]},\"lib/permit2/src/interfaces/IPermit2.sol\":{\"keccak256\":\"0xaa631cc9f53e699301d94233007110a345e6779011def484e8dd97b8fe0af771\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://fc0502cf19c9c18f320a3001201e89e350393b75837f6b7971de18b2de06f30d\",\"dweb:/ipfs/QmT9SfhdJ7VJNNrf94g4H5usyi7ShqWGx7Cqsz9jZTjX96\"]},\"lib/permit2/src/interfaces/ISignatureTransfer.sol\":{\"keccak256\":\"0x6805563eaad92471fa1b3591a71d7020a93e59f1a4ac95398daf74927f5bd033\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://48cd13806cb8e82dcc38eb93423a372fbdd3b05364ecebb8bfd9cd29078dd90c\",\"dweb:/ipfs/QmeLyFVrzKRHcm6aaFFBCG5mFESCqWLp1KYT41H8XhzMCp\"]},\"lib/solmate/src/auth/Owned.sol\":{\"keccak256\":\"0xfedb27d14c508342c33eb067c9a02eabcdb0f9dcf93b04ded1001f580d12d0ea\",\"license\":\"AGPL-3.0-only\",\"urls\":[\"bzz-raw://1ff52bbee698b9cf9e4574615e6550be0887ccf355f6571e23d6f25b332e79b4\",\"dweb:/ipfs/QmVorA2apojVRStzS7h8aFccR3Uv32G6HVtBtFHZrE7YXx\"]},\"lib/solmate/src/tokens/ERC20.sol\":{\"keccak256\":\"0xcdfd8db76b2a3415620e4d18cc5545f3d50de792dbf2c3dd5adb40cbe6f94b10\",\"license\":\"AGPL-3.0-only\",\"urls\":[\"bzz-raw://57b3ab70cde374af1cf2c9888636e8de6cf660f087b1c9abd805e9271e19fa35\",\"dweb:/ipfs/QmNrLDBAHYFjpjSd12jerm1AdBkDqEYUUaXgnT854BUZ97\"]},\"lib/solmate/src/utils/FixedPointMathLib.sol\":{\"keccak256\":\"0x1b62af9baf5b8e991ed7531bc87f45550ba9d61e8dbff5caf237ccaf3a3fd843\",\"license\":\"AGPL-3.0-only\",\"urls\":[\"bzz-raw://b7b38b977c5305b18ceefbeed4c9ceaaaefa419b520de62de6604ea661f8c0a9\",\"dweb:/ipfs/QmecMRzgfMyDVa2pvBqMMDLYBappaj7Aa3qcMoQYEQrhWi\"]},\"lib/solmate/src/utils/SafeTransferLib.sol\":{\"keccak256\":\"0x6ab948013c2c7ca6351e593600425b0ec6df9035320280c678e735bce16e996b\",\"license\":\"AGPL-3.0-only\",\"urls\":[\"bzz-raw://2ab977d0eeb2bf458f9798250215c646d2f3b1f90b5a7e2b506fdf3335c0f060\",\"dweb:/ipfs/QmYPRoPhNtBAmCSq7imN1scMVpKNQvMTpoqab3tXUx5Tnv\"]},\"src/base/ProtocolFees.sol\":{\"keccak256\":\"0x1152eee4ac698694bcdbf90b016411112d679812ca0abc1cacd7e6b465e6729a\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://c1be6b94c6268b68362111e728598e7c1517b20998fdf6752d08e32d55c210f8\",\"dweb:/ipfs/QmStQC274cQqnQSo3QDBcT5BdqEkpwZwFaWwxaYXMZidvw\"]},\"src/base/ReactorEvents.sol\":{\"keccak256\":\"0x61df7aa3ef970f1305c5a6d8c68b0d7ab8bebb9b7518e191c8d2fda532859f61\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://93db11be28b3394485b57a7b120ca224fdb93b471db8468738406f77ebaa13fc\",\"dweb:/ipfs/Qmci4TSUH81C3WDV7TMv56VmiUFZ9MDxZcGTRKhhEPS6gC\"]},\"src/base/ReactorStructs.sol\":{\"keccak256\":\"0x78e6db322ca69aaf552e59d5e74a00fd465a802388c2d03f9bf4b711f5704588\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://12d8fc82c3543bfe0d2cd44cdbc524bed1f074abafe086f7e58573cbaff2a74e\",\"dweb:/ipfs/QmREbamTn3nz89nEjv2uWHNHKSF6Yga2gQ688Cde89xcNT\"]},\"src/interfaces/IProtocolFeeController.sol\":{\"keccak256\":\"0x21a895ff5b778abf95753001a20b4004adfadd1bba622eaec18eb81836ede86c\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://67f9eae1da9f238f6630247882e382458dcc0135c0a4837b99a44a2360a3845c\",\"dweb:/ipfs/QmdJyKhVyD6nAtgdTofaU2xaoWrPGM1Q6Sd7FiN2LxXZQx\"]},\"src/interfaces/IReactor.sol\":{\"keccak256\":\"0x23714e546bbeeaa7fe35665d7241319c964421a9fe6d81aead4b85027cabf1e1\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://3b94402a2e90f75d6238d4460c0b1125bf67b98523803156b104ce57cafdd05b\",\"dweb:/ipfs/QmbY3Mr44MPEMAe9bh9tUSqpPg3AAKfkVfydwJCEzFA14a\"]},\"src/interfaces/IReactorCallback.sol\":{\"keccak256\":\"0xf3ee1fe09545fc5be000c33bb6779e897b4e5013bd9de3e7c3107bf466b4dfa1\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://12d7fd1ac3dca76614796f0d012ea4de79bf09cf124cc74efffdf25a56756344\",\"dweb:/ipfs/QmXyeSrG7caihgzUZdPdPbbRj6v1w65gBnfn9a7HhbVJX9\"]},\"src/interfaces/IValidationCallback.sol\":{\"keccak256\":\"0xc31e3a60e210e9a4089f48ba4fae06dec6f4d33da4fbe415cfb8cdc202003bae\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://ee145d5fc0e0806dc9db57825142d5d7c3eafc248a27ee301ffd13592f2cda34\",\"dweb:/ipfs/QmQr2HBHZKiUu88a3M1Hs4QSjFemsZmPEd115QG6GKjsC1\"]},\"src/lib/CosignerLib.sol\":{\"keccak256\":\"0x59681b68b61d78f47c91de5405464916ad44de721a5cedbbd4fe9691264cda63\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://f5dc4fbd2ab2820f649fb2c2c8d6393671950143b2a5a4f35095fab1919f6deb\",\"dweb:/ipfs/QmPVT2St7twYfUiVocsvTNCCaq24MBBtPwrB4TtCcXgywo\"]},\"src/lib/CurrencyLibrary.sol\":{\"keccak256\":\"0x73688c07cd36b5040e0deca3dd1f21a8b19585d6cdfefb816fae98af92a545ea\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://750375d6f0e59f7977b9cfc2cf05fef7b356cea7875fbb71b0ca359d091b8479\",\"dweb:/ipfs/QmZbdTSS1BxWqAHjmtwoJsggbRVkwnxynJuaxzKkkakm4Y\"]},\"src/lib/DutchDecayLib.sol\":{\"keccak256\":\"0x49ab5aadfe6d06c84d6d71b5fef5ec99b9f50fe52eadc7ab87c9c5b0b3b00238\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://6375205d2ae6423989724fcfc9a3aa432ca0a85bc21b896e12317b00eb5c2056\",\"dweb:/ipfs/QmefpYkPvmuVYm2wbr7HSNQASVSU2nJwoi2XocD7xzXcBz\"]},\"src/lib/DutchOrderLib.sol\":{\"keccak256\":\"0xdd6b9bffcc044899fac52e1e9cbe4becc7a40b56d912695e80600224367235e6\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://78c08ec074bc21ce610f2e0c3594b383e0cd2301c32239146a771e2e5d2cb975\",\"dweb:/ipfs/QmbMQwT9k3RWyTdihqqnu3RDiRCz1XmpMUVwxeyWzChKB5\"]},\"src/lib/ExclusivityLib.sol\":{\"keccak256\":\"0x6e153b0d2cdb9615bbd933e9e48d88e3be85940325f8607a2b3dffdf2b960add\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://293d6d98bc9b1e002e1d64802081c1ee75927a0ad12c4cc1cc2158c0a3d00273\",\"dweb:/ipfs/QmdF3QjvU6yVcgNEFMgzdSwf9tzdBtFZbWFFcZRf1mcVQ6\"]},\"src/lib/MathExt.sol\":{\"keccak256\":\"0xd1f217948a7206684f486e2069d761a145151deaea567855b3d3307ae0807ec5\",\"urls\":[\"bzz-raw://e87cbf2fbdf00a48127b0c6c1412c7ac7dc1c43b3415d3b4c5259c62a853ecee\",\"dweb:/ipfs/QmZagjsb6ZWgiY1HpoRgK8dvFpDK1pVD2q4ukjgPxRXkbx\"]},\"src/lib/NonlinearDutchDecayLib.sol\":{\"keccak256\":\"0x8bcf7ca61510ad5aecae26fc27d8110fa737d51bbfb12fa0fbbd2440ed075396\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://bdceca3310d953fd19d104614a06f1f5daa2a9f940f4324a38023c5378fcd5dd\",\"dweb:/ipfs/QmcUTc16h6nEdtAUt38QY8VCyNr4u6h66xwf3J4jCiM12Z\"]},\"src/lib/OrderInfoLib.sol\":{\"keccak256\":\"0x38672b528e63dc53f36ed82d0037110a9f5893ad0a3957e24f19fa3fdbd80015\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://147172dbebf4bb579bc392f25666645719264c0b47378f7fc4f3a95c79bdf5a4\",\"dweb:/ipfs/Qmd5wVnQ8rKHHQgUQzEDcAPiqrVzmNr9t2D7d1SqUg9hTo\"]},\"src/lib/Permit2Lib.sol\":{\"keccak256\":\"0xcb5e1e204f4ac6ea3fa164b8be1b1d31cbad0dff981072ea2c33abd720369e78\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://cfa162286525ef8684112639c7b981c0472b06ce799f2440c626a70c273bb533\",\"dweb:/ipfs/QmV1Uy4oodhg4SbCajv9xhiWFuwtU1YcTTvca1cDYCkND9\"]},\"src/lib/ResolvedOrderLib.sol\":{\"keccak256\":\"0xc56a31e72001e3e6ee0baf193423a7563cc61ba4869133e1cae5cf998bfe4d96\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://4bddef26f26939f48923b11674495515d792cffbb2dc04f092212ff0b9971636\",\"dweb:/ipfs/QmS1YAzhYLCi9oDtZN33mwBf5iExdwMhPNcnzh5nA8fPKX\"]},\"src/lib/V3DutchOrderLib.sol\":{\"keccak256\":\"0x713ae2f89d1a469ac2c613cd231f77e699bd6555d329ad225e5f7bdbd71ea67d\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://389c6acfec88119181a5787421fb9cbbb572f59bcdeda20a52198a4c2dec09a0\",\"dweb:/ipfs/QmUhq15JNgmxCeaGws1Lyzq4FsY2qd8rtnTBPkEjZDw7X5\"]},\"src/reactors/BaseReactor.sol\":{\"keccak256\":\"0xd31b25dd7209a704fb17865e8112bc83a72e1816bc1d636c89366b2f1e3c4210\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://f10c83e80f01d728f48aa06905e272eef776159ea83b53885c182da15597e3ca\",\"dweb:/ipfs/Qmf2nx9abWsTMCVBV1At66HS3FVTXHreUVCpwVDKjkYadY\"]},\"src/reactors/V3DutchOrderReactor.sol\":{\"keccak256\":\"0x69980e4ef7afcb20be21988e1281ec1096a00a5b4c01c3ef22a19ad2af48c0eb\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://eee7f50c10014fc4d2e2cf59af2666ba3b5b34d8c15075aa32e5c8e444a1d15d\",\"dweb:/ipfs/QmViBF66mrv8C6V2V6Hk7d6XsYyBJVVaFimvsAeKEiSQmp\"]},\"src/types/Uint16Array.sol\":{\"keccak256\":\"0xeed5434a013ce5e4a232785716b7a06b3c9f7f6b489aab0bcb760cf4765214c1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7fa32450b920ce9fcf6fab0cbd85c5c84ac863ae0c09c4f647597edbae0e358d\",\"dweb:/ipfs/QmYdRsgwNrMXDJidDL6CnahHGjHmzL2z1dQEBqb61AqKhh\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.24+commit.e11b9ed9"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"contract IPermit2","name":"_permit2","type":"address"},{"internalType":"address","name":"_protocolFeeOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"type":"error","name":"DeadlineReached"},{"inputs":[{"internalType":"address","name":"duplicateToken","type":"address"}],"type":"error","name":"DuplicateFeeOutput"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"type":"error","name":"FeeTooLarge"},{"inputs":[],"type":"error","name":"IndexOutOfBounds"},{"inputs":[],"type":"error","name":"InputAndOutputFees"},{"inputs":[],"type":"error","name":"InvalidCosignature"},{"inputs":[],"type":"error","name":"InvalidCosignerInput"},{"inputs":[],"type":"error","name":"InvalidCosignerOutput"},{"inputs":[],"type":"error","name":"InvalidDecayCurve"},{"inputs":[{"internalType":"address","name":"feeToken","type":"address"}],"type":"error","name":"InvalidFeeToken"},{"inputs":[],"type":"error","name":"InvalidReactor"},{"inputs":[],"type":"error","name":"NativeTransferFailed"},{"inputs":[],"type":"error","name":"NoExclusiveOverride"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32","indexed":true},{"internalType":"address","name":"filler","type":"address","indexed":true},{"internalType":"address","name":"swapper","type":"address","indexed":true},{"internalType":"uint256","name":"nonce","type":"uint256","indexed":false}],"type":"event","name":"Fill","anonymous":false},{"inputs":[{"internalType":"address","name":"user","type":"address","indexed":true},{"internalType":"address","name":"newOwner","type":"address","indexed":true}],"type":"event","name":"OwnershipTransferred","anonymous":false},{"inputs":[{"internalType":"address","name":"oldFeeController","type":"address","indexed":false},{"internalType":"address","name":"newFeeController","type":"address","indexed":false}],"type":"event","name":"ProtocolFeeControllerSet","anonymous":false},{"inputs":[{"internalType":"struct SignedOrder","name":"order","type":"tuple","components":[{"internalType":"bytes","name":"order","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}]}],"stateMutability":"payable","type":"function","name":"execute"},{"inputs":[{"internalType":"struct SignedOrder[]","name":"orders","type":"tuple[]","components":[{"internalType":"bytes","name":"order","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}]}],"stateMutability":"payable","type":"function","name":"executeBatch"},{"inputs":[{"internalType":"struct SignedOrder[]","name":"orders","type":"tuple[]","components":[{"internalType":"bytes","name":"order","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}]},{"internalType":"bytes","name":"callbackData","type":"bytes"}],"stateMutability":"payable","type":"function","name":"executeBatchWithCallback"},{"inputs":[{"internalType":"struct SignedOrder","name":"order","type":"tuple","components":[{"internalType":"bytes","name":"order","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}]},{"internalType":"bytes","name":"callbackData","type":"bytes"}],"stateMutability":"payable","type":"function","name":"executeWithCallback"},{"inputs":[],"stateMutability":"view","type":"function","name":"feeController","outputs":[{"internalType":"contract IProtocolFeeController","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"permit2","outputs":[{"internalType":"contract IPermit2","name":"","type":"address"}]},{"inputs":[{"internalType":"address","name":"_newFeeController","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"setProtocolFeeController"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"transferOwnership"},{"inputs":[],"stateMutability":"payable","type":"receive"}],"devdoc":{"kind":"dev","methods":{"execute((bytes,bytes))":{"params":{"order":"The order definition and valid signature to execute"}},"executeBatch((bytes,bytes)[])":{"params":{"orders":"The order definitions and valid signatures to execute"}},"executeBatchWithCallback((bytes,bytes)[],bytes)":{"params":{"callbackData":"The callbackData to pass to the callback","orders":"The order definitions and valid signatures to execute"}},"executeWithCallback((bytes,bytes),bytes)":{"params":{"callbackData":"The callbackData to pass to the callback","order":"The order definition and valid signature to execute"}},"setProtocolFeeController(address)":{"details":"only callable by the owner","params":{"_newFeeController":"the new fee controller"}}},"version":1},"userdoc":{"kind":"user","methods":{"execute((bytes,bytes))":{"notice":"Execute a single order"},"executeBatch((bytes,bytes)[])":{"notice":"Execute the given orders at once"},"executeBatchWithCallback((bytes,bytes)[],bytes)":{"notice":"Execute the given orders at once using a callback with the given callback data"},"executeWithCallback((bytes,bytes),bytes)":{"notice":"Execute a single order using the given callback data"},"permit2()":{"notice":"permit2 address used for token transfers and signature verification"},"setProtocolFeeController(address)":{"notice":"sets the protocol fee controller"}},"version":1}},"settings":{"remappings":["ds-test/=lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-gas-snapshot/=lib/forge-gas-snapshot/src/","forge-std/=lib/forge-std/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/","openzeppelin/=lib/openzeppelin-contracts/contracts/","permit2/=lib/permit2/","solarray/=lib/solarray/src/","solmate/=lib/solmate/"],"optimizer":{"enabled":true,"runs":1000000},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/reactors/V3DutchOrderReactor.sol":"V3DutchOrderReactor"},"evmVersion":"paris","libraries":{}},"sources":{"lib/openzeppelin-contracts/contracts/security/ReentrancyGuard.sol":{"keccak256":"0xa535a5df777d44e945dd24aa43a11e44b024140fc340ad0dfe42acf4002aade1","urls":["bzz-raw://41319e7f621f2dc3733511332c4fd032f8e32ad2aa7fd6f665c19741d9941a34","dweb:/ipfs/QmcYR3bd862GD1Bc7jwrU9bGxrhUu5na1oP964bDCu2id1"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/math/Math.sol":{"keccak256":"0xe4455ac1eb7fc497bb7402579e7b4d64d928b846fce7d2b6fde06d366f21c2b3","urls":["bzz-raw://cc8841b3cd48ad125e2f46323c8bad3aa0e88e399ec62acb9e57efa7e7c8058c","dweb:/ipfs/QmSqE4mXHA2BXW58deDbXE8MTcsL5JSKNDbm23sVQxRLPS"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol":{"keccak256":"0x52a8cfb0f5239d11b457dcdd1b326992ef672714ca8da71a157255bddd13f3ad","urls":["bzz-raw://495145362c7ff1c9ca88c58bbbbcb412e3c2004406647412394486552ff6c278","dweb:/ipfs/QmNNCeng6d5eRPDn6tkWSQhjE39XWfQEfjA63rRwHmr1iH"],"license":"MIT"},"lib/permit2/src/interfaces/IAllowanceTransfer.sol":{"keccak256":"0x78931704a7f1d89ef24244b155863abb751cc3b3818f64303ccb47a396d48dcb","urls":["bzz-raw://b8d6e198ee29d809564f1c1d7caa11a2c329bb5d051f61210548e546493444d2","dweb:/ipfs/QmVxWftbgETjudymgLdwF77S54DWrp6qB5ooauKXW81cm7"],"license":"MIT"},"lib/permit2/src/interfaces/IEIP712.sol":{"keccak256":"0xea70db68ce450ad38dfbd490058595441144808eb95272ae9b89e3fbe6456954","urls":["bzz-raw://e8fad9ff319665acdc2f1295bb82db3e5b4d52babc0b58f147dbdbb9f322c6e5","dweb:/ipfs/QmTbYJPcux8eJ3qGVYQh6TiwCA2FPu6HXTUg6QFTnX91Ks"],"license":"MIT"},"lib/permit2/src/interfaces/IPermit2.sol":{"keccak256":"0xaa631cc9f53e699301d94233007110a345e6779011def484e8dd97b8fe0af771","urls":["bzz-raw://fc0502cf19c9c18f320a3001201e89e350393b75837f6b7971de18b2de06f30d","dweb:/ipfs/QmT9SfhdJ7VJNNrf94g4H5usyi7ShqWGx7Cqsz9jZTjX96"],"license":"MIT"},"lib/permit2/src/interfaces/ISignatureTransfer.sol":{"keccak256":"0x6805563eaad92471fa1b3591a71d7020a93e59f1a4ac95398daf74927f5bd033","urls":["bzz-raw://48cd13806cb8e82dcc38eb93423a372fbdd3b05364ecebb8bfd9cd29078dd90c","dweb:/ipfs/QmeLyFVrzKRHcm6aaFFBCG5mFESCqWLp1KYT41H8XhzMCp"],"license":"MIT"},"lib/solmate/src/auth/Owned.sol":{"keccak256":"0xfedb27d14c508342c33eb067c9a02eabcdb0f9dcf93b04ded1001f580d12d0ea","urls":["bzz-raw://1ff52bbee698b9cf9e4574615e6550be0887ccf355f6571e23d6f25b332e79b4","dweb:/ipfs/QmVorA2apojVRStzS7h8aFccR3Uv32G6HVtBtFHZrE7YXx"],"license":"AGPL-3.0-only"},"lib/solmate/src/tokens/ERC20.sol":{"keccak256":"0xcdfd8db76b2a3415620e4d18cc5545f3d50de792dbf2c3dd5adb40cbe6f94b10","urls":["bzz-raw://57b3ab70cde374af1cf2c9888636e8de6cf660f087b1c9abd805e9271e19fa35","dweb:/ipfs/QmNrLDBAHYFjpjSd12jerm1AdBkDqEYUUaXgnT854BUZ97"],"license":"AGPL-3.0-only"},"lib/solmate/src/utils/FixedPointMathLib.sol":{"keccak256":"0x1b62af9baf5b8e991ed7531bc87f45550ba9d61e8dbff5caf237ccaf3a3fd843","urls":["bzz-raw://b7b38b977c5305b18ceefbeed4c9ceaaaefa419b520de62de6604ea661f8c0a9","dweb:/ipfs/QmecMRzgfMyDVa2pvBqMMDLYBappaj7Aa3qcMoQYEQrhWi"],"license":"AGPL-3.0-only"},"lib/solmate/src/utils/SafeTransferLib.sol":{"keccak256":"0x6ab948013c2c7ca6351e593600425b0ec6df9035320280c678e735bce16e996b","urls":["bzz-raw://2ab977d0eeb2bf458f9798250215c646d2f3b1f90b5a7e2b506fdf3335c0f060","dweb:/ipfs/QmYPRoPhNtBAmCSq7imN1scMVpKNQvMTpoqab3tXUx5Tnv"],"license":"AGPL-3.0-only"},"src/base/ProtocolFees.sol":{"keccak256":"0x1152eee4ac698694bcdbf90b016411112d679812ca0abc1cacd7e6b465e6729a","urls":["bzz-raw://c1be6b94c6268b68362111e728598e7c1517b20998fdf6752d08e32d55c210f8","dweb:/ipfs/QmStQC274cQqnQSo3QDBcT5BdqEkpwZwFaWwxaYXMZidvw"],"license":"GPL-2.0-or-later"},"src/base/ReactorEvents.sol":{"keccak256":"0x61df7aa3ef970f1305c5a6d8c68b0d7ab8bebb9b7518e191c8d2fda532859f61","urls":["bzz-raw://93db11be28b3394485b57a7b120ca224fdb93b471db8468738406f77ebaa13fc","dweb:/ipfs/Qmci4TSUH81C3WDV7TMv56VmiUFZ9MDxZcGTRKhhEPS6gC"],"license":"GPL-2.0-or-later"},"src/base/ReactorStructs.sol":{"keccak256":"0x78e6db322ca69aaf552e59d5e74a00fd465a802388c2d03f9bf4b711f5704588","urls":["bzz-raw://12d8fc82c3543bfe0d2cd44cdbc524bed1f074abafe086f7e58573cbaff2a74e","dweb:/ipfs/QmREbamTn3nz89nEjv2uWHNHKSF6Yga2gQ688Cde89xcNT"],"license":"GPL-2.0-or-later"},"src/interfaces/IProtocolFeeController.sol":{"keccak256":"0x21a895ff5b778abf95753001a20b4004adfadd1bba622eaec18eb81836ede86c","urls":["bzz-raw://67f9eae1da9f238f6630247882e382458dcc0135c0a4837b99a44a2360a3845c","dweb:/ipfs/QmdJyKhVyD6nAtgdTofaU2xaoWrPGM1Q6Sd7FiN2LxXZQx"],"license":"GPL-2.0-or-later"},"src/interfaces/IReactor.sol":{"keccak256":"0x23714e546bbeeaa7fe35665d7241319c964421a9fe6d81aead4b85027cabf1e1","urls":["bzz-raw://3b94402a2e90f75d6238d4460c0b1125bf67b98523803156b104ce57cafdd05b","dweb:/ipfs/QmbY3Mr44MPEMAe9bh9tUSqpPg3AAKfkVfydwJCEzFA14a"],"license":"GPL-2.0-or-later"},"src/interfaces/IReactorCallback.sol":{"keccak256":"0xf3ee1fe09545fc5be000c33bb6779e897b4e5013bd9de3e7c3107bf466b4dfa1","urls":["bzz-raw://12d7fd1ac3dca76614796f0d012ea4de79bf09cf124cc74efffdf25a56756344","dweb:/ipfs/QmXyeSrG7caihgzUZdPdPbbRj6v1w65gBnfn9a7HhbVJX9"],"license":"GPL-2.0-or-later"},"src/interfaces/IValidationCallback.sol":{"keccak256":"0xc31e3a60e210e9a4089f48ba4fae06dec6f4d33da4fbe415cfb8cdc202003bae","urls":["bzz-raw://ee145d5fc0e0806dc9db57825142d5d7c3eafc248a27ee301ffd13592f2cda34","dweb:/ipfs/QmQr2HBHZKiUu88a3M1Hs4QSjFemsZmPEd115QG6GKjsC1"],"license":"GPL-2.0-or-later"},"src/lib/CosignerLib.sol":{"keccak256":"0x59681b68b61d78f47c91de5405464916ad44de721a5cedbbd4fe9691264cda63","urls":["bzz-raw://f5dc4fbd2ab2820f649fb2c2c8d6393671950143b2a5a4f35095fab1919f6deb","dweb:/ipfs/QmPVT2St7twYfUiVocsvTNCCaq24MBBtPwrB4TtCcXgywo"],"license":"GPL-2.0-or-later"},"src/lib/CurrencyLibrary.sol":{"keccak256":"0x73688c07cd36b5040e0deca3dd1f21a8b19585d6cdfefb816fae98af92a545ea","urls":["bzz-raw://750375d6f0e59f7977b9cfc2cf05fef7b356cea7875fbb71b0ca359d091b8479","dweb:/ipfs/QmZbdTSS1BxWqAHjmtwoJsggbRVkwnxynJuaxzKkkakm4Y"],"license":"GPL-2.0-or-later"},"src/lib/DutchDecayLib.sol":{"keccak256":"0x49ab5aadfe6d06c84d6d71b5fef5ec99b9f50fe52eadc7ab87c9c5b0b3b00238","urls":["bzz-raw://6375205d2ae6423989724fcfc9a3aa432ca0a85bc21b896e12317b00eb5c2056","dweb:/ipfs/QmefpYkPvmuVYm2wbr7HSNQASVSU2nJwoi2XocD7xzXcBz"],"license":"GPL-2.0-or-later"},"src/lib/DutchOrderLib.sol":{"keccak256":"0xdd6b9bffcc044899fac52e1e9cbe4becc7a40b56d912695e80600224367235e6","urls":["bzz-raw://78c08ec074bc21ce610f2e0c3594b383e0cd2301c32239146a771e2e5d2cb975","dweb:/ipfs/QmbMQwT9k3RWyTdihqqnu3RDiRCz1XmpMUVwxeyWzChKB5"],"license":"GPL-2.0-or-later"},"src/lib/ExclusivityLib.sol":{"keccak256":"0x6e153b0d2cdb9615bbd933e9e48d88e3be85940325f8607a2b3dffdf2b960add","urls":["bzz-raw://293d6d98bc9b1e002e1d64802081c1ee75927a0ad12c4cc1cc2158c0a3d00273","dweb:/ipfs/QmdF3QjvU6yVcgNEFMgzdSwf9tzdBtFZbWFFcZRf1mcVQ6"],"license":"GPL-2.0-or-later"},"src/lib/MathExt.sol":{"keccak256":"0xd1f217948a7206684f486e2069d761a145151deaea567855b3d3307ae0807ec5","urls":["bzz-raw://e87cbf2fbdf00a48127b0c6c1412c7ac7dc1c43b3415d3b4c5259c62a853ecee","dweb:/ipfs/QmZagjsb6ZWgiY1HpoRgK8dvFpDK1pVD2q4ukjgPxRXkbx"],"license":null},"src/lib/NonlinearDutchDecayLib.sol":{"keccak256":"0x8bcf7ca61510ad5aecae26fc27d8110fa737d51bbfb12fa0fbbd2440ed075396","urls":["bzz-raw://bdceca3310d953fd19d104614a06f1f5daa2a9f940f4324a38023c5378fcd5dd","dweb:/ipfs/QmcUTc16h6nEdtAUt38QY8VCyNr4u6h66xwf3J4jCiM12Z"],"license":"GPL-2.0-or-later"},"src/lib/OrderInfoLib.sol":{"keccak256":"0x38672b528e63dc53f36ed82d0037110a9f5893ad0a3957e24f19fa3fdbd80015","urls":["bzz-raw://147172dbebf4bb579bc392f25666645719264c0b47378f7fc4f3a95c79bdf5a4","dweb:/ipfs/Qmd5wVnQ8rKHHQgUQzEDcAPiqrVzmNr9t2D7d1SqUg9hTo"],"license":"GPL-2.0-or-later"},"src/lib/Permit2Lib.sol":{"keccak256":"0xcb5e1e204f4ac6ea3fa164b8be1b1d31cbad0dff981072ea2c33abd720369e78","urls":["bzz-raw://cfa162286525ef8684112639c7b981c0472b06ce799f2440c626a70c273bb533","dweb:/ipfs/QmV1Uy4oodhg4SbCajv9xhiWFuwtU1YcTTvca1cDYCkND9"],"license":"GPL-2.0-or-later"},"src/lib/ResolvedOrderLib.sol":{"keccak256":"0xc56a31e72001e3e6ee0baf193423a7563cc61ba4869133e1cae5cf998bfe4d96","urls":["bzz-raw://4bddef26f26939f48923b11674495515d792cffbb2dc04f092212ff0b9971636","dweb:/ipfs/QmS1YAzhYLCi9oDtZN33mwBf5iExdwMhPNcnzh5nA8fPKX"],"license":"GPL-2.0-or-later"},"src/lib/V3DutchOrderLib.sol":{"keccak256":"0x713ae2f89d1a469ac2c613cd231f77e699bd6555d329ad225e5f7bdbd71ea67d","urls":["bzz-raw://389c6acfec88119181a5787421fb9cbbb572f59bcdeda20a52198a4c2dec09a0","dweb:/ipfs/QmUhq15JNgmxCeaGws1Lyzq4FsY2qd8rtnTBPkEjZDw7X5"],"license":"GPL-2.0-or-later"},"src/reactors/BaseReactor.sol":{"keccak256":"0xd31b25dd7209a704fb17865e8112bc83a72e1816bc1d636c89366b2f1e3c4210","urls":["bzz-raw://f10c83e80f01d728f48aa06905e272eef776159ea83b53885c182da15597e3ca","dweb:/ipfs/Qmf2nx9abWsTMCVBV1At66HS3FVTXHreUVCpwVDKjkYadY"],"license":"GPL-2.0-or-later"},"src/reactors/V3DutchOrderReactor.sol":{"keccak256":"0x69980e4ef7afcb20be21988e1281ec1096a00a5b4c01c3ef22a19ad2af48c0eb","urls":["bzz-raw://eee7f50c10014fc4d2e2cf59af2666ba3b5b34d8c15075aa32e5c8e444a1d15d","dweb:/ipfs/QmViBF66mrv8C6V2V6Hk7d6XsYyBJVVaFimvsAeKEiSQmp"],"license":"GPL-2.0-or-later"},"src/types/Uint16Array.sol":{"keccak256":"0xeed5434a013ce5e4a232785716b7a06b3c9f7f6b489aab0bcb760cf4765214c1","urls":["bzz-raw://7fa32450b920ce9fcf6fab0cbd85c5c84ac863ae0c09c4f647597edbae0e358d","dweb:/ipfs/QmYdRsgwNrMXDJidDL6CnahHGjHmzL2z1dQEBqb61AqKhh"],"license":"MIT"}},"version":1},"id":71} \ No newline at end of file diff --git a/sdks/uniswapx-sdk/integration/test/V3DutchOrder.spec.ts b/sdks/uniswapx-sdk/integration/test/V3DutchOrder.spec.ts new file mode 100644 index 000000000..580c83d8d --- /dev/null +++ b/sdks/uniswapx-sdk/integration/test/V3DutchOrder.spec.ts @@ -0,0 +1,833 @@ +import { BigNumber, Signer, Wallet } from "ethers"; +import hre, { ethers } from "hardhat"; +import Permit2Abi from "../../abis/Permit2.json" +import V3DutchOrderReactorAbi from "../../abis/V3DutchOrderReactor.json" +import MockERC20Abi from "../../abis/MockERC20.json" +import { Permit2, V3DutchOrderReactor } from "../../src/contracts" +import { MockERC20 } from "../../dist/src/contracts"; +import { BlockchainTime } from "./utils/time"; +import { V3DutchOrderBuilder } from "../../src/builder/V3DutchOrderBuilder" +import { expect } from "chai"; +import { UnsignedV3DutchOrder, V3CosignerData } from "../../src/order/V3DutchOrder"; + +describe("DutchV3Order", () => { + const FEE_RECIPIENT = "0x1111111111111111111111111111111111111111"; + const AMOUNT = BigNumber.from(10).pow(18); + const SMALL_AMOUNT = BigNumber.from(10).pow(10); + let NONCE = BigNumber.from(100); + let futureDeadline : number; + let bot : Signer; + let admin: Signer; + let filler: Signer; + let permit2 : Permit2; + let reactor : V3DutchOrderReactor; + const chainId = hre.network.config.chainId || 42161; + let swapper: Wallet; + let cosigner: Wallet; + let tokenIn: MockERC20; + let tokenOut: MockERC20; + let swapperAddress: string; + let fillerAddress: string; + let cosignerAddress : string; + let botAddress : string; + let validPartialOrder : UnsignedV3DutchOrder; + + before(async () => { + futureDeadline = await new BlockchainTime().secondsFromNow(1000); + [ admin, filler, bot ] = await ethers.getSigners(); + const permit2Factory = await ethers.getContractFactory( + Permit2Abi.abi, + Permit2Abi.bytecode + ); + permit2 = (await permit2Factory.deploy()) as Permit2; + + const reactorFactory = await ethers.getContractFactory( + V3DutchOrderReactorAbi.abi, + V3DutchOrderReactorAbi.bytecode + ); + reactor = (await reactorFactory.deploy( + permit2.address, + ethers.constants.AddressZero + )) as V3DutchOrderReactor; + + swapper = ethers.Wallet.createRandom().connect(ethers.provider); + cosigner = ethers.Wallet.createRandom().connect(ethers.provider); + swapperAddress = await swapper.getAddress(); + cosignerAddress = await cosigner.getAddress(); + fillerAddress = await filler.getAddress(); + botAddress = await bot.getAddress(); + const tx = await admin.sendTransaction({ + to: swapperAddress, + value: AMOUNT.mul(10), + }); + const tx1 = await bot.sendTransaction({ + to: fillerAddress, + value: AMOUNT, + }); + + const tokenFactory = await ethers.getContractFactory( + MockERC20Abi.abi, + MockERC20Abi.bytecode + ); + + tokenIn = (await tokenFactory.deploy("Token A", "A", 18)) as MockERC20; + tokenOut = (await tokenFactory.deploy("Token B", "B", 18)) as MockERC20; + + await tokenIn.mint( + swapperAddress, + AMOUNT, + ); + await tokenIn + .connect(swapper) + .approve(permit2.address, ethers.constants.MaxUint256); + + await tokenOut.mint( + fillerAddress, + AMOUNT, + ); + await tokenOut.mint( + botAddress, + AMOUNT, + ) + await tokenOut + .connect(filler) + .approve(reactor.address, ethers.constants.MaxUint256); + await tokenOut + .connect(bot) + .approve(reactor.address, ethers.constants.MaxUint256); + + validPartialOrder = new V3DutchOrderBuilder( + chainId, + reactor.address, + permit2.address + ) + .cosigner(cosignerAddress) + .deadline(futureDeadline) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: tokenIn.address, + startAmount: AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: tokenOut.address, + startAmount: AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: swapperAddress, + minAmount: AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .swapper(swapperAddress) + .nonce(NONCE) + .buildPartial(); + }); + + afterEach(() => { + NONCE = NONCE.add(1); + }); + + it("Partial V3 Order", async () => { + const preBuildOrder = validPartialOrder; + expect(preBuildOrder.info.deadline).to.eq(futureDeadline); + + expect(preBuildOrder.info.swapper).to.eq(swapperAddress); + expect(preBuildOrder.info.cosigner).to.eq(cosignerAddress); + expect(preBuildOrder.info.nonce.toNumber()).to.eq(100); + + expect(preBuildOrder.info.input.token).to.eq(tokenIn.address); + expect(preBuildOrder.info.input.startAmount).to.eq(AMOUNT); + + const builtOutput = preBuildOrder.info.outputs[0]; + + expect(builtOutput.token).to.eq(tokenOut.address); + expect(builtOutput.startAmount).to.eq(AMOUNT); + }); + + it("Cosigned V3 Order", async () => { + const deadline = await new BlockchainTime().secondsFromNow(1000); + const orderbuilder = new V3DutchOrderBuilder( + chainId, + reactor.address, + permit2.address + ) + .startingBaseFee(BigNumber.from(0)) + .cosigner(cosignerAddress) + .deadline(deadline) + .swapper(swapperAddress) + .nonce(NONCE) + .input({ + token: tokenIn.address, + startAmount: AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: tokenOut.address, + startAmount: AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: swapperAddress, + minAmount: AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + const partialOrder = orderbuilder.buildPartial(); + const cosignerData = await getCosignerData(); + const cosignature = await cosigner.signMessage( + partialOrder.cosignatureHash(cosignerData) + ); + const cosignedOrder = orderbuilder + .cosignature(cosignature) + .cosignerData(cosignerData) + .build(); + + expect(cosignedOrder.info.deadline).to.eq(deadline); + expect(cosignedOrder.info.swapper).to.eq(swapperAddress); + expect(cosignedOrder.info.cosigner).to.eq(cosignerAddress); + expect(cosignedOrder.info.cosignature).to.eq(cosignature); + expect(cosignedOrder.info.nonce.toNumber()).to.eq(NONCE); + + expect(cosignedOrder.info.input.token).to.eq(tokenIn.address); + expect(cosignedOrder.info.input.startAmount).to.eq(AMOUNT); + const builtOutput = cosignedOrder.info.outputs[0]; + + expect(builtOutput.token).to.eq(tokenOut.address); + expect(builtOutput.startAmount).to.eq(AMOUNT); + expect(builtOutput.recipient).to.eq(swapperAddress); + }); + + it("reverts if cosignature is invalid", async () => { + const order = validPartialOrder; + const { domain, types, values } = order.permitData(); + const signature = await swapper._signTypedData(domain, types, values); + const cosignerData = await getCosignerData(); + const cosignerHash = order.cosignatureHash(cosignerData); + let cosignature = ethers.utils.joinSignature( + cosigner._signingKey().signDigest(cosignerHash) + ); + const fullOrder = V3DutchOrderBuilder.fromOrder(order) + //use the cosignature of the other one that doesn't match this sub(1) order + .cosignerData({ ...cosignerData, inputOverride: AMOUNT.sub(1) }) + .cosignature(cosignature) + .build(); + + await expect( + reactor + .connect(filler) + .execute({ order: fullOrder.serialize(), sig: signature }) + ).to.be.revertedWithCustomError(reactor, "InvalidCosignature"); + }); + + it("executes a serialized order with no decay", async () => { + const deadline = await new BlockchainTime().secondsFromNow(1000); + const cosignerData = await getCosignerData(); + const order = new V3DutchOrderBuilder( + chainId, + reactor.address, + permit2.address + ) + .cosigner(cosigner.address) + .deadline(deadline) + .swapper(swapper.address) + .nonce(NONCE) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: tokenIn.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: SMALL_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: tokenOut.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + recipient: swapperAddress, + minAmount: SMALL_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .buildPartial() + + const { domain, types, values } = order.permitData(); + const signature = await swapper._signTypedData(domain, types, values); + + const cosignerHash = order.cosignatureHash(cosignerData); + const cosignature = ethers.utils.joinSignature( + cosigner._signingKey().signDigest(cosignerHash) + ); + + const fullOrder = V3DutchOrderBuilder.fromOrder(order) + .cosignerData(cosignerData) + .cosignature(cosignature) + .build(); + + const swapperTokenInBalanceBefore = await tokenIn.balanceOf(swapperAddress); + const fillerTokenInBalanceBefore = await tokenIn.balanceOf(fillerAddress); + const swapperTokenOutBalanceBefore = await tokenOut.balanceOf(swapperAddress); + const fillerTokenOutBalanceBefore = await tokenOut.balanceOf(fillerAddress); + + const res = await reactor + .connect(filler) + .execute( + { + order: fullOrder.serialize(), + sig: signature + } + ); + const receipt = await res.wait(); + expect(receipt.status).to.equal(1); + expect((await tokenIn.balanceOf(swapperAddress)).toString()).to.equal( + swapperTokenInBalanceBefore.sub(SMALL_AMOUNT).toString() + ); + expect((await tokenIn.balanceOf(fillerAddress)).toString()).to.equal( + fillerTokenInBalanceBefore.add(SMALL_AMOUNT).toString() + ); + //We can take the startAmount because this happens before the decay begins + const amountOut = order.info.outputs[0].startAmount; + expect((await tokenOut.balanceOf(swapperAddress)).toString()).to.equal( + swapperTokenOutBalanceBefore.add(amountOut) + ); + expect((await tokenOut.balanceOf(fillerAddress)).toString()).to.equal( + fillerTokenOutBalanceBefore.sub(amountOut) + ); + }); + + it("executes a serialized order with no decay, override of double original output amount", async () => { + const deadline = await new BlockchainTime().secondsFromNow(1000); + const order = new V3DutchOrderBuilder( + chainId, + reactor.address, + permit2.address + ) + .cosigner(cosigner.address) + .deadline(deadline) + .swapper(swapper.address) + .nonce(NONCE) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: tokenIn.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: SMALL_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: tokenOut.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + recipient: swapperAddress, + minAmount: SMALL_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .buildPartial() + + const { domain, types, values } = order.permitData(); + const signature = await swapper._signTypedData(domain, types, values); + const cosignerData = await getCosignerData({ + outputOverrides: [SMALL_AMOUNT.mul(2)], + }); + + const cosignerHash = order.cosignatureHash(cosignerData); + const cosignature = ethers.utils.joinSignature( + cosigner._signingKey().signDigest(cosignerHash) + ); + + const fullOrder = V3DutchOrderBuilder.fromOrder(order) + .cosignerData(cosignerData) + .cosignature(cosignature) + .build(); + + const swapperTokenInBalanceBefore = await tokenIn.balanceOf(swapperAddress); + const fillerTokenInBalanceBefore = await tokenIn.balanceOf(fillerAddress); + const swapperTokenOutBalanceBefore = await tokenOut.balanceOf(swapperAddress); + const fillerTokenOutBalanceBefore = await tokenOut.balanceOf(fillerAddress); + + const res = await reactor + .connect(filler) + .execute( + { + order: fullOrder.serialize(), + sig: signature + } + ); + const receipt = await res.wait(); + expect(receipt.status).to.equal(1); + expect((await tokenIn.balanceOf(swapperAddress)).toString()).to.equal( + swapperTokenInBalanceBefore.sub(SMALL_AMOUNT).toString() + ); + expect((await tokenIn.balanceOf(fillerAddress)).toString()).to.equal( + fillerTokenInBalanceBefore.add(SMALL_AMOUNT).toString() + ); + + const amountOut = SMALL_AMOUNT.mul(2); + expect((await tokenOut.balanceOf(swapperAddress)).toString()).to.equal( + swapperTokenOutBalanceBefore.add(amountOut) + ); + expect((await tokenOut.balanceOf(fillerAddress)).toString()).to.equal( + fillerTokenOutBalanceBefore.sub(amountOut) + ); + }); + + it("executes a serialized order with no decay, override of half original input amount", async () => { + const deadline = await new BlockchainTime().secondsFromNow(1000); + const order = new V3DutchOrderBuilder( + chainId, + reactor.address, + permit2.address + ) + .cosigner(cosigner.address) + .deadline(deadline) + .swapper(swapper.address) + .nonce(NONCE) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: tokenIn.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: SMALL_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: tokenOut.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + recipient: swapperAddress, + minAmount: SMALL_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .buildPartial() + + const { domain, types, values } = order.permitData(); + const signature = await swapper._signTypedData(domain, types, values); + const cosignerData = await getCosignerData({ + inputOverride: SMALL_AMOUNT.div(2) + }); + + const cosignerHash = order.cosignatureHash(cosignerData); + const cosignature = ethers.utils.joinSignature( + cosigner._signingKey().signDigest(cosignerHash) + ); + + const fullOrder = V3DutchOrderBuilder.fromOrder(order) + .cosignerData(cosignerData) + .cosignature(cosignature) + .build(); + + const swapperTokenInBalanceBefore = await tokenIn.balanceOf(swapperAddress); + const fillerTokenInBalanceBefore = await tokenIn.balanceOf(fillerAddress); + const swapperTokenOutBalanceBefore = await tokenOut.balanceOf(swapperAddress); + const fillerTokenOutBalanceBefore = await tokenOut.balanceOf(fillerAddress); + + const res = await reactor + .connect(filler) + .execute( + { + order: fullOrder.serialize(), + sig: signature + } + ); + const receipt = await res.wait(); + expect(receipt.status).to.equal(1); + + const amountIn = SMALL_AMOUNT.div(2); + expect((await tokenIn.balanceOf(swapperAddress)).toString()).to.equal( + swapperTokenInBalanceBefore.sub(amountIn).toString() + ); + expect((await tokenIn.balanceOf(fillerAddress)).toString()).to.equal( + fillerTokenInBalanceBefore.add(amountIn).toString() + ); + + expect((await tokenOut.balanceOf(swapperAddress)).toString()).to.equal( + swapperTokenOutBalanceBefore.add(SMALL_AMOUNT) + ); + expect((await tokenOut.balanceOf(fillerAddress)).toString()).to.equal( + fillerTokenOutBalanceBefore.sub(SMALL_AMOUNT) + ); + }); + + it("executes a serialized order with decay", async () => { + const deadline = await new BlockchainTime().secondsFromNow(1000); + const order = new V3DutchOrderBuilder( + chainId, + reactor.address, + permit2.address + ) + .cosigner(cosigner.address) + .deadline(deadline) + .swapper(swapper.address) + .nonce(NONCE) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: tokenIn.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: SMALL_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: tokenOut.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: swapperAddress, + minAmount: SMALL_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .buildPartial() + + const { domain, types, values } = order.permitData(); + const signature = await swapper._signTypedData(domain, types, values); + const cosignerData = await getCosignerData({ + decayStartBlock: await new BlockchainTime().blocksFromNow(-1), + }); + + const cosignerHash = order.cosignatureHash(cosignerData); + const cosignature = ethers.utils.joinSignature( + cosigner._signingKey().signDigest(cosignerHash) + ); + + const fullOrder = V3DutchOrderBuilder.fromOrder(order) + .cosignerData(cosignerData) + .cosignature(cosignature) + .build(); + + const swapperTokenInBalanceBefore = await tokenIn.balanceOf(swapperAddress); + const fillerTokenInBalanceBefore = await tokenIn.balanceOf(fillerAddress); + const swapperTokenOutBalanceBefore = await tokenOut.balanceOf(swapperAddress); + const fillerTokenOutBalanceBefore = await tokenOut.balanceOf(fillerAddress); + const res = await reactor + .connect(filler) + .execute( + { + order: fullOrder.serialize(), + sig: signature + } + ); + const receipt = await res.wait(); + expect(receipt.status).to.equal(1); + + // We can take the startAmount because we aren't decaying input + const amountIn = fullOrder.info.input.startAmount; + expect((await tokenIn.balanceOf(swapperAddress)).toString()).to.equal( + swapperTokenInBalanceBefore.sub(amountIn).toString() + ); + expect((await tokenIn.balanceOf(fillerAddress)).toString()).to.equal( + fillerTokenInBalanceBefore.add(amountIn).toString() + ); + + const currentBlock = await ethers.provider.getBlockNumber(); + const decayAmount = currentBlock - cosignerData.decayStartBlock; + // Decay with a curve of 4 over 4 blocks + expect((await tokenOut.balanceOf(swapperAddress)).toString()).to.equal( + swapperTokenOutBalanceBefore.add(SMALL_AMOUNT.sub(decayAmount)) + ); + expect((await tokenOut.balanceOf(fillerAddress)).toString()).to.equal( + fillerTokenOutBalanceBefore.sub(SMALL_AMOUNT.sub(decayAmount)) + ); + }); + + it("executes a serialized order with multi-point decay", async () => { + const deadline = await new BlockchainTime().secondsFromNow(1000); + const order = new V3DutchOrderBuilder( + chainId, + reactor.address, + permit2.address + ) + .cosigner(cosigner.address) + .deadline(deadline) + .swapper(swapper.address) + .nonce(NONCE) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: tokenIn.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: SMALL_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: tokenOut.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [4, 8], + relativeAmounts: [BigInt(4), BigInt(24)], + }, + recipient: swapperAddress, + minAmount: SMALL_AMOUNT.sub(24), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .buildPartial() + + const { domain, types, values } = order.permitData(); + const signature = await swapper._signTypedData(domain, types, values); + const cosignerData = await getCosignerData({ + // Construct this order at time t with a decayStartBlock of t-5 + decayStartBlock: await new BlockchainTime().blocksFromNow(-5), + }); + const cosignerHash = order.cosignatureHash(cosignerData); + const cosignature = ethers.utils.joinSignature( + cosigner._signingKey().signDigest(cosignerHash) + ); + + const fullOrder = V3DutchOrderBuilder.fromOrder(order) + .cosignerData(cosignerData) + .cosignature(cosignature) + .build(); + + const swapperTokenInBalanceBefore = await tokenIn.balanceOf(swapperAddress); + const fillerTokenInBalanceBefore = await tokenIn.balanceOf(fillerAddress); + const swapperTokenOutBalanceBefore = await tokenOut.balanceOf(swapperAddress); + const fillerTokenOutBalanceBefore = await tokenOut.balanceOf(fillerAddress); + const res = await reactor + .connect(filler) + .execute( + { + order: fullOrder.serialize(), + sig: signature + } + ); + const receipt = await res.wait(); + expect(receipt.status).to.equal(1); + // This transaction should be at block t+1 + // So the relative block is t+1 - (t-5) = 6 + // The relative amount decayed is 4 + 2(5) = 14 + const decayAmount = 14; + + // We can take the startAmount because we aren't decaying input + const amountIn = fullOrder.info.input.startAmount; + expect((await tokenIn.balanceOf(swapperAddress)).toString()).to.equal( + swapperTokenInBalanceBefore.sub(amountIn).toString() + ); + expect((await tokenIn.balanceOf(fillerAddress)).toString()).to.equal( + fillerTokenInBalanceBefore.add(amountIn).toString() + ); + + expect((await tokenOut.balanceOf(swapperAddress)).toString()).to.equal( + swapperTokenOutBalanceBefore.add(SMALL_AMOUNT.sub(decayAmount)) + ); + expect((await tokenOut.balanceOf(fillerAddress)).toString()).to.equal( + fillerTokenOutBalanceBefore.sub(SMALL_AMOUNT.sub(decayAmount)) + ); + }); + + it("open filler executes an open order past exclusivity", async () => { + const deadline = await new BlockchainTime().secondsFromNow(1000); + const order = new V3DutchOrderBuilder( + chainId, + reactor.address, + permit2.address + ) + .cosigner(cosigner.address) + .deadline(deadline) + .swapper(swapper.address) + .nonce(NONCE) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: tokenIn.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: SMALL_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: tokenOut.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: swapperAddress, + minAmount: SMALL_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .buildPartial() + + const { domain, types, values } = order.permitData(); + const signature = await swapper._signTypedData(domain, types, values); + const cosignerData = await getCosignerData({ + decayStartBlock: await new BlockchainTime().blocksFromNow(0), + exclusiveFiller: fillerAddress, + }); + + const cosignerHash = order.cosignatureHash(cosignerData); + const cosignature = ethers.utils.joinSignature( + cosigner._signingKey().signDigest(cosignerHash) + ); + + const fullOrder = V3DutchOrderBuilder.fromOrder(order) + .cosignerData(cosignerData) + .cosignature(cosignature) + .build(); + + const swapperTokenInBalanceBefore = await tokenIn.balanceOf( + swapperAddress + ); + const fillerTokenInBalanceBefore = await tokenIn.balanceOf(fillerAddress); + const botTokenInBalanceBefore = await tokenIn.balanceOf( + botAddress + ); + const swapperTokenOutBalanceBefore = await tokenOut.balanceOf( + swapperAddress + ); + const fillerTokenOutBalanceBefore = await tokenOut.balanceOf( + fillerAddress + ); + const botTokenOutBalanceBefore = await tokenOut.balanceOf( + botAddress + ); + + const res = await reactor + .connect(bot) + .execute( + { + order: fullOrder.serialize(), + sig: signature + } + ); + const receipt = await res.wait(); + expect(receipt.status).to.equal(1); + + // We can take the startAmount because we aren't decaying input + const amountIn = fullOrder.info.input.startAmount; + expect((await tokenIn.balanceOf(swapperAddress)).toString()).to.equal( + swapperTokenInBalanceBefore.sub(amountIn).toString() + ); + // Exclusive filler did not fill + expect((await tokenIn.balanceOf(fillerAddress)).toString()).to.equal( + fillerTokenInBalanceBefore.toString() + ); + expect((await tokenOut.balanceOf(fillerAddress)).toString()).to.equal( + fillerTokenOutBalanceBefore.toString() + ); + // Bot (non-exclusive) filled + expect((await tokenIn.balanceOf(botAddress)).toString()).to.equal( + botTokenInBalanceBefore.add(amountIn).toString() + ); + expect((await tokenOut.balanceOf(swapperAddress)).toString()).to.equal( + swapperTokenOutBalanceBefore.add(SMALL_AMOUNT.sub(1)).toString() + ); + expect((await tokenOut.balanceOf(botAddress)).toString()).to.equal( + botTokenOutBalanceBefore.sub(SMALL_AMOUNT.sub(1)).toString() + ); + }); + + it("Open filler fails to execute order before exclusivity", async () => { + const deadline = await new BlockchainTime().secondsFromNow(1000); + const order = new V3DutchOrderBuilder( + chainId, + reactor.address, + permit2.address + ) + .cosigner(cosigner.address) + .deadline(deadline) + .swapper(swapper.address) + .nonce(NONCE) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: tokenIn.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: SMALL_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: tokenOut.address, + startAmount: SMALL_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: swapperAddress, + minAmount: SMALL_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .buildPartial() + + const { domain, types, values } = order.permitData(); + const signature = await swapper._signTypedData(domain, types, values); + const cosignerData = await getCosignerData({ + decayStartBlock: await new BlockchainTime().blocksFromNow(5), + exclusiveFiller: fillerAddress, + }); + + const cosignerHash = order.cosignatureHash(cosignerData); + const cosignature = ethers.utils.joinSignature( + cosigner._signingKey().signDigest(cosignerHash) + ); + + const fullOrder = V3DutchOrderBuilder.fromOrder(order) + .cosignerData(cosignerData) + .cosignature(cosignature) + .build(); + + await expect( + reactor + .connect(bot) + .execute( + { + order: fullOrder.serialize(), + sig: signature + } + ) + ).to.be.revertedWithCustomError(reactor, "NoExclusiveOverride"); + }); +}); + +const getCosignerData = async ( + overrides: Partial = {} + ): Promise => { + const defaultData: V3CosignerData = { + decayStartBlock: 29000000, + exclusiveFiller: ethers.constants.AddressZero, + exclusivityOverrideBps: BigNumber.from(0), + // overrides of 0 will not affect the values + inputOverride: BigNumber.from(0), + outputOverrides: [BigNumber.from(0)], + }; + return Object.assign(defaultData, overrides); +}; \ No newline at end of file diff --git a/sdks/uniswapx-sdk/integration/test/utils/time.ts b/sdks/uniswapx-sdk/integration/test/utils/time.ts index 9dd9e2ff7..26ef6e971 100644 --- a/sdks/uniswapx-sdk/integration/test/utils/time.ts +++ b/sdks/uniswapx-sdk/integration/test/utils/time.ts @@ -10,6 +10,15 @@ export class BlockchainTime { return timestamp + secondsFromNow; } + async blocksFromNow(blocksFromNow: number): Promise { + const res = await hre.network.provider.send('eth_getBlockByNumber', [ + 'latest', + false, + ]); + const blockNum = parseInt(res.number, 16); + return blockNum + blocksFromNow; + } + async increaseTime(seconds: number): Promise { await hre.network.provider.send('evm_increaseTime', [seconds]); await hre.network.provider.send('evm_mine'); diff --git a/sdks/uniswapx-sdk/src/builder/V2DutchOrderBuilder.test.ts b/sdks/uniswapx-sdk/src/builder/V2DutchOrderBuilder.test.ts index d5d54af39..6ea58401f 100644 --- a/sdks/uniswapx-sdk/src/builder/V2DutchOrderBuilder.test.ts +++ b/sdks/uniswapx-sdk/src/builder/V2DutchOrderBuilder.test.ts @@ -349,7 +349,7 @@ describe("V2DutchOrderBuilder", () => { .outputOverrides([OUTPUT_START_AMOUNT.mul(102).div(100)]) .build() ).toThrow( - "Invariant failed: inputOverride not set or larger than original input" + "Invariant failed: inputOverride larger than original input" ); }); @@ -574,7 +574,7 @@ describe("V2DutchOrderBuilder", () => { }); describe("partial order tests", () => { - it("builds an unsigned partial order with default cosignerData values", () => { + it("builds an unsigned partial order with default cosignerData values", () => { //TODO: partial orders don't have cosignerData... const deadline = Math.floor(Date.now() / 1000) + 1000; const order = builder .cosigner(constants.AddressZero) diff --git a/sdks/uniswapx-sdk/src/builder/V2DutchOrderBuilder.ts b/sdks/uniswapx-sdk/src/builder/V2DutchOrderBuilder.ts index d8a9c8dfa..79e396a2b 100644 --- a/sdks/uniswapx-sdk/src/builder/V2DutchOrderBuilder.ts +++ b/sdks/uniswapx-sdk/src/builder/V2DutchOrderBuilder.ts @@ -40,7 +40,7 @@ export class V2DutchOrderBuilder extends OrderBuilder { builder.output(output); } - if (isCosigned(order)) { + if (order instanceof CosignedV2DutchOrder) { builder.cosignature(order.info.cosignature); builder.decayEndTime(order.info.cosignerData.decayEndTime); builder.decayStartTime(order.info.cosignerData.decayStartTime); @@ -287,9 +287,8 @@ export class V2DutchOrderBuilder extends OrderBuilder { "exclusivityOverrideBps not set" ); invariant( - this.info.cosignerData.inputOverride !== undefined && this.info.cosignerData.inputOverride.lte(this.info.input.startAmount), - "inputOverride not set or larger than original input" + "inputOverride larger than original input" ); invariant( this.info.cosignerData.outputOverrides.length > 0, @@ -339,9 +338,3 @@ export class V2DutchOrderBuilder extends OrderBuilder { }; } } - -function isCosigned( - order: UnsignedV2DutchOrder | CosignedV2DutchOrder -): order is CosignedV2DutchOrder { - return (order as CosignedV2DutchOrder).info.cosignature !== undefined; -} diff --git a/sdks/uniswapx-sdk/src/builder/V3DutchOrderBuilder.test.ts b/sdks/uniswapx-sdk/src/builder/V3DutchOrderBuilder.test.ts new file mode 100644 index 000000000..3f6898ab2 --- /dev/null +++ b/sdks/uniswapx-sdk/src/builder/V3DutchOrderBuilder.test.ts @@ -0,0 +1,957 @@ +import { BigNumber, constants } from "ethers"; + +import { CosignedV3DutchOrder, UnsignedV3DutchOrder } from "../order/V3DutchOrder"; +import { encodeExclusiveFillerData } from "../order/validation"; + +import { V3DutchOrderBuilder } from "./V3DutchOrderBuilder"; + +const INPUT_TOKEN = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"; +const OUTPUT_TOKEN = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; + +const INPUT_START_AMOUNT = BigNumber.from("1000000"); +const OUTPUT_START_AMOUNT = BigNumber.from("1000000000000000000"); + +describe("V3DutchOrderBuilder", () => { + let builder: V3DutchOrderBuilder; + + beforeEach(() => { + builder = new V3DutchOrderBuilder(1, constants.AddressZero); + }); + + it("Build a valid order", () => { + const deadline = Date.now() + 1000; + const order = builder + .cosigner(constants.AddressZero) + .cosignature("0x") + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build(); + + expect(order.info.cosignerData.decayStartBlock).toEqual(212121); + expect(order.info.outputs.length).toEqual(1); + }); + //TODO: Add tests that uses the validation contract once it is implemented + + it("Build a valid order with multiple outputs", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + const order = builder + .cosigner(constants.AddressZero) + .cosignature("0x") + .deadline(deadline) + .decayStartBlock(212121) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [17], + relativeAmounts: [BigInt(17)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(17), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT.mul(101).div(100), OUTPUT_START_AMOUNT]) + .build(); + expect(order.info.outputs.length).toEqual(2); + expect(order.info.cosignerData.decayStartBlock).toEqual(212121); + }); + + it("Throw if cosigner is not set", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder + .cosignature("0x") + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build() + ).toThrow("Invariant failed: cosigner not set"); + }); + + it("Throw if relativeBlocks and relativeAmounts length mismatch in output", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder + .cosignature("0x") + .cosigner(constants.AddressZero) + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [1], + relativeAmounts: [BigInt(1)], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4,5], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build() + ).toThrow("Invariant failed: relativeBlocks and relativeAmounts length mismatch"); + }); + + it("Throw if relativeBlocks and relativeAmounts length mismatch in input", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder + .cosignature("0x") + .cosigner(constants.AddressZero) + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [1], + relativeAmounts: [BigInt(0), BigInt(1)], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(BigNumber.from(0)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build() + ).toThrow("Invariant failed: relativeBlocks and relativeAmounts length mismatch"); + }); + + it("Throw if relativeBlocks is not strictly increasing in input", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder + .cosignature("0x") + .cosigner(constants.AddressZero) + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [1, 2, 1], + relativeAmounts: [BigInt(1), BigInt(2), BigInt(3)], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(BigNumber.from(0)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .nonce(BigNumber.from(100)) + .swapper(constants.AddressZero) + .build() + ).toThrow("Invariant failed: relativeBlocks not strictly increasing"); + }); + + it("Throw if relativeBlocks is not strictly increasing in output", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder + .cosignature("0x") + .cosigner(constants.AddressZero) + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [5, 5], + relativeAmounts: [BigInt(4), BigInt(22)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(5), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .nonce(BigNumber.from(100)) + .swapper(constants.AddressZero) + .build() + ).toThrow("Invariant failed: relativeBlocks not strictly increasing"); + }); + + it("Throw if swapper is not set", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder + .cosignature("0x") + .cosigner(constants.AddressZero) + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .nonce(BigNumber.from(100)) + .build() + ).toThrow("Invariant failed: swapper not set"); + }); + + it("Deadline not set", () => { + expect(() => builder + .cosigner(constants.AddressZero) + .cosignature("0x") + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build() + ).toThrow("Invariant failed: deadline not set"); + }); + + it("Nonce not set", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder + .cosignature("0x") + .cosigner(constants.AddressZero) + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + // omitting nonce + .build() + ).toThrow("Invariant failed: nonce not set"); + }); + + it("Throw if startingBaseFee not set", () => { + const deadline = Date.now() + 1000; + expect(() => + builder + .cosigner(constants.AddressZero) + .cosignature("0x") + .decayStartBlock(212121) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build() + ).toThrow("Invariant failed: startingBaseFee not set"); + }); + + it("Throw if input is not set", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder + .cosignature("0x") + .cosigner(constants.AddressZero) + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + // omitting input + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build() + ).toThrow("Invariant failed: input not set"); + }); + + it("Throw if output is not set", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder + .cosignature("0x") + .cosigner(constants.AddressZero) + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + // omitting output + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build() + ).toThrow("Invariant failed: outputs not set"); + }); + + it("Throw if inputOverride larger than input", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder + .cosignature("0x") + .cosigner(constants.AddressZero) + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.add(1)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build() + ).toThrow("Invariant failed: inputOverride larger than original input"); + }); + + it("Throw if outputOverride smaller than output", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder + .cosignature("0x") + .cosigner(constants.AddressZero) + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT.sub(2121)]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build() + ).toThrow("Invariant failed: outputOverride smaller than original output"); + }); + + it("Do not enforce endAmount < startAmount for V3", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder + .cosignature("0x") + .cosigner(constants.AddressZero) + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(-4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.add(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .deadline(deadline) + .outputOverrides([OUTPUT_START_AMOUNT]) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build() + ).not.toThrow(); + }); + + it("Throw if deadline already passed", () => { + const deadline = 2121; + expect(() => + builder + .cosignature("0x") + .cosigner(constants.AddressZero) + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build() + ).toThrow("Invariant failed: Deadline must be in the future: 2121"); + }); + + it("Does not throw before an order has not been finished building", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + expect(() => + builder.deadline(deadline).decayStartBlock(21212121212121) + ).not.toThrowError(); + }); + + it("Unknown chainId", () => { + const chainId = 99999999; + expect(() => new V3DutchOrderBuilder(chainId)).toThrow( + `Missing configuration for reactor: ${chainId}` + ); + }); + + it("Regenerate builder from order JSON", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + const fillerAddress = "0x1111111111111111111111111111111111111111"; + const additionalValidationContract = + "0x2222222222222222222222222222222222222222"; + const timestamp = Math.floor(Date.now() / 1000) + 100; + const validationInfo = encodeExclusiveFillerData( + fillerAddress, + timestamp, + 1, + additionalValidationContract + ); + const order = builder + .cosigner(constants.AddressZero) + .cosignature("0x") + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .validation(validationInfo) + .build(); + + const json = order.toJSON(); + const jsonToOrder = CosignedV3DutchOrder.fromJSON(json, 1); + const regeneratedBuilder = V3DutchOrderBuilder.fromOrder(jsonToOrder); + const regeneratedOrder = regeneratedBuilder.build(); + expect(regeneratedOrder.toJSON()).toMatchObject(order.toJSON()); + }); + + it("Regenerate builder and modify", () => { + const deadline = Math.floor(Date.now() / 1000) + 1000; + const fillerAddress = "0x1111111111111111111111111111111111111111"; + const additionalValidationContract = + "0x2222222222222222222222222222222222222222"; + const timestamp = Math.floor(Date.now() / 1000) + 100; + const validationInfo = encodeExclusiveFillerData( + fillerAddress, + timestamp, + 1, + additionalValidationContract + ); + const order = builder + .cosigner(constants.AddressZero) + .cosignature("0x") + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .validation(validationInfo) + .build(); + + const regeneratedBuilder = V3DutchOrderBuilder.fromOrder(order); + regeneratedBuilder.decayStartBlock(214221422142); + const regeneratedOrder = regeneratedBuilder.build(); + expect(regeneratedOrder.info.cosignerData.decayStartBlock).toEqual(214221422142); + }); + + describe("Partial order tests", () => { + it("Test valid order with buildPartial", () => { + const order = builder + .cosigner(constants.AddressZero) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .deadline(Math.floor(Date.now() / 1000) + 1000) + .buildPartial(); + expect(order.info.outputs.length).toEqual(1); + expect(order.chainId).toBeDefined(); + expect(order.info.reactor).toBeDefined(); + }); + + it("Test invalid order with buildPartial", () => { + expect(() => + builder + .cosigner(constants.AddressZero) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + // omitting swapper + .deadline(Math.floor(Date.now() / 1000) + 1000) + .nonce(BigNumber.from(100)) + .buildPartial() + ).toThrow("Invariant failed: swapper not set"); + }); + + it("Test maxAmountOut", () => { + const startAmount = INPUT_START_AMOUNT; + const relativeAmounts = [BigInt(0), BigInt(3), BigInt(-2), BigInt(-4), BigInt(-3)]; + const maxout = V3DutchOrderBuilder.getMaxAmountOut(startAmount, relativeAmounts); + expect(maxout).toEqual(startAmount.add(4)); + }); + + it("Test maxAmountOut with empty curve", () => { + const startAmount = INPUT_START_AMOUNT; + const relativeAmounts : bigint[] = []; + const maxout = V3DutchOrderBuilder.getMaxAmountOut(startAmount, relativeAmounts); + expect(maxout).toEqual(startAmount); + }); + + it("Test maxAmountOut with negative relativeAmounts", () => { + const startAmount = INPUT_START_AMOUNT; + const relativeAmounts = [BigInt(-1), BigInt(-2), BigInt(-3)]; + const maxout = V3DutchOrderBuilder.getMaxAmountOut(startAmount, relativeAmounts); + expect(maxout).toEqual(startAmount.add(3)); + }); + + it("Test maxAmountOut with entirely positive relativeAmounts", () => { + const startAmount = INPUT_START_AMOUNT; + const relativeAmounts = [BigInt(1), BigInt(2), BigInt(3)]; + const maxout = V3DutchOrderBuilder.getMaxAmountOut(startAmount, relativeAmounts); + expect(maxout).toEqual(startAmount); + }); + }); + + describe("fromOrder", () => { + let builder: V3DutchOrderBuilder; + + beforeEach(() => { + builder = new V3DutchOrderBuilder(1, constants.AddressZero); + }); + + it("should create a V3DutchOrderBuilder from an UnsignedV3DutchOrder", () => { + const order: UnsignedV3DutchOrder = builder + .cosigner(constants.AddressZero) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .deadline(Math.floor(Date.now() / 1000) + 1000) + .buildPartial(); + + const created_builder = V3DutchOrderBuilder.fromOrder(order); + const created_order = created_builder.buildPartial(); + + expect(created_order.chainId).toEqual(1); + expect(created_order.info.input.token).toEqual(INPUT_TOKEN); + expect(created_order.info.outputs.length).toEqual(1); + }); + + it("should create a V3DutchOrderBuilder from a CosignedV3DutchOrder", () => { + const deadline = Date.now() + 1000; + const order: CosignedV3DutchOrder = builder + .cosigner(constants.AddressZero) + .cosignature("0x") + .decayStartBlock(212121) + .startingBaseFee(BigNumber.from(0)) + .input({ + token: INPUT_TOKEN, + startAmount: INPUT_START_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: INPUT_START_AMOUNT.add(1), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .output({ + token: OUTPUT_TOKEN, + startAmount: OUTPUT_START_AMOUNT, + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(4)], + }, + recipient: constants.AddressZero, + minAmount: OUTPUT_START_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }) + .inputOverride(INPUT_START_AMOUNT.mul(99).div(100)) + .outputOverrides([OUTPUT_START_AMOUNT]) + .deadline(deadline) + .swapper(constants.AddressZero) + .nonce(BigNumber.from(100)) + .build(); + const created_builder = V3DutchOrderBuilder.fromOrder(order); + const created_order = created_builder.build(); + expect(created_order.chainId).toEqual(1); + expect(created_order.info.input.token).toEqual(INPUT_TOKEN); + expect(created_order.info.outputs.length).toEqual(1); + expect(created_order.info.cosignerData.decayStartBlock).toEqual(212121); + }); + }); +}); \ No newline at end of file diff --git a/sdks/uniswapx-sdk/src/builder/V3DutchOrderBuilder.ts b/sdks/uniswapx-sdk/src/builder/V3DutchOrderBuilder.ts new file mode 100644 index 000000000..d6f676917 --- /dev/null +++ b/sdks/uniswapx-sdk/src/builder/V3DutchOrderBuilder.ts @@ -0,0 +1,341 @@ +import { BigNumber, ethers } from "ethers"; +import invariant from "tiny-invariant"; + +import { OrderType } from "../constants"; +import { + CosignedV3DutchOrder, + CosignedV3DutchOrderInfo, + UnsignedV3DutchOrder, + UnsignedV3DutchOrderInfo, + V3CosignerData, +} from "../order/V3DutchOrder"; +import { V3DutchInput, V3DutchOutput } from "../order/types"; +import { ValidationInfo } from "../order/validation"; +import { getPermit2, getReactor } from "../utils"; + +import { OrderBuilder } from "./OrderBuilder"; + +export class V3DutchOrderBuilder extends OrderBuilder { + static fromOrder( + order: T + ): V3DutchOrderBuilder { + const builder = new V3DutchOrderBuilder(order.chainId, order.info.reactor); + builder + .cosigner(order.info.cosigner) + .startingBaseFee(order.info.startingBaseFee) + .input(order.info.input) + .deadline(order.info.deadline) + .nonce(order.info.nonce) + .swapper(order.info.swapper) + .validation({ + additionalValidationContract: order.info.additionalValidationContract, + additionalValidationData: order.info.additionalValidationData, + }); + + order.info.outputs.forEach((output) => { + builder.output(output); + }); + + if (order instanceof CosignedV3DutchOrder) { + builder.cosignature(order.info.cosignature); + builder.decayStartBlock(order.info.cosignerData.decayStartBlock); + builder.exclusiveFiller(order.info.cosignerData.exclusiveFiller); + builder.inputOverride(order.info.cosignerData.inputOverride); + builder.exclusivityOverrideBps( + order.info.cosignerData.exclusivityOverrideBps + ); + builder.outputOverrides(order.info.cosignerData.outputOverrides); + } + return builder; + } + + build(): CosignedV3DutchOrder { + invariant(this.info.cosignature !== undefined, "cosignature not set"); + this.checkUnsignedInvariants(this.info); + this.checkCosignedInvariants(this.info); + return new CosignedV3DutchOrder( + Object.assign(this.getOrderInfo(), { + cosignerData: this.info.cosignerData, + startingBaseFee: this.info.startingBaseFee, + input: this.info.input, + outputs: this.info.outputs, + cosigner: this.info.cosigner, + cosignature: this.info.cosignature, + }), + this.chainId, + this.permit2Address + ); + } + private permit2Address: string; + private info: Partial; + + constructor( + private chainId: number, + reactorAddress?: string, + _permit2Address?: string + ) { + super(); + + this.reactor(getReactor(chainId, OrderType.Dutch_V3, reactorAddress)); + this.permit2Address = getPermit2(chainId, _permit2Address); + this.info = { + outputs: [], + }; + this.initializeCosignerData({}); + } + + cosigner(cosigner: string): this { + this.info.cosigner = cosigner; + return this; + } + + cosignature(cosignature: string | undefined): this { + this.info.cosignature = cosignature; + return this; + } + + decayStartBlock(decayStartBlock: number): this { + if (!this.info.cosignerData) { + this.initializeCosignerData({ decayStartBlock }); + } else { + this.info.cosignerData.decayStartBlock = decayStartBlock; + } + return this; + } + + private initializeCosignerData(data: Partial): void { + this.info.cosignerData = { + decayStartBlock: 0, + exclusiveFiller: ethers.constants.AddressZero, + exclusivityOverrideBps: BigNumber.from(0), + inputOverride: BigNumber.from(0), + outputOverrides: [], + ...data, + }; + } + + private isRelativeBlocksIncreasing(relativeBlocks: number[]): boolean { + let prevBlock = 0; + for (const block of relativeBlocks) { + if (block <= prevBlock) { + return false; + } + prevBlock = block; + } + return true; + } + + private checkUnsignedInvariants( + info: Partial + ): asserts info is UnsignedV3DutchOrderInfo { + invariant(info.cosigner !== undefined, "cosigner not set"); + invariant(info.startingBaseFee !== undefined, "startingBaseFee not set"); + invariant(info.input !== undefined, "input not set"); + invariant(info.outputs && info.outputs.length > 0, "outputs not set"); + // Check if input curve is valid + invariant( + info.input.curve.relativeAmounts.length === + info.input.curve.relativeBlocks.length, + "relativeBlocks and relativeAmounts length mismatch" + ); + invariant( + this.isRelativeBlocksIncreasing(info.input.curve.relativeBlocks), + "relativeBlocks not strictly increasing" + ); + // For each output's curve, we need to make sure relativeBlocks is strictly increasing + info.outputs.forEach((output) => { + invariant( + output.curve.relativeBlocks.length === + output.curve.relativeAmounts.length, + "relativeBlocks and relativeAmounts length mismatch" + ); + // For each output's curve, we need to make sure relativeBlocks is strictly increasing + invariant( + this.isRelativeBlocksIncreasing(output.curve.relativeBlocks), + "relativeBlocks not strictly increasing" + ); + }); + // In V3, we don't have a decayEndTime field and use OrderInfo.deadline field for Permit2 + invariant(this.orderInfo.deadline !== undefined, "deadline not set"); + invariant(this.orderInfo.swapper !== undefined, "swapper not set"); + } + + private checkCosignedInvariants( + info: Partial + ): asserts info is CosignedV3DutchOrderInfo { + // In V3, we are not enforcing that the startAmount is greater than the endAmount + invariant(info.cosignerData !== undefined, "cosignerData not set"); + invariant( + info.cosignerData.decayStartBlock !== undefined, + "decayStartBlock not set" + ); + invariant( + info.cosignerData.exclusiveFiller !== undefined, + "exclusiveFiller not set" + ); + invariant( + info.cosignerData.exclusivityOverrideBps !== undefined, + "exclusivityOverrideBps not set" + ); + invariant( + info.cosignerData.outputOverrides.length > 0, + "outputOverrides not set" + ); + invariant( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + info.cosignerData.inputOverride.lte(this.info.input!.startAmount), + "inputOverride larger than original input" + ); + info.cosignerData.outputOverrides.forEach((override, idx) => { + if (override.toString() != "0") { + invariant( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + override.gte(this.info.outputs![idx].startAmount), + "outputOverride smaller than original output" + ); + } + }); + // We are not checking if the decayStartBlock is before the deadline because it is not enforced in the smart contract + } + + startingBaseFee(startingBaseFee: BigNumber): this { + this.info.startingBaseFee = startingBaseFee; + return this; + } + + input(input: V3DutchInput): this { + this.info.input = input; + return this; + } + + output(output: V3DutchOutput): this { + this.info.outputs?.push(output); + return this; + } + + inputOverride(inputOverride: BigNumber): this { + if (!this.info.cosignerData) { + this.initializeCosignerData({ inputOverride }); + } else { + this.info.cosignerData.inputOverride = inputOverride; + } + return this; + } + + outputOverrides(outputOverrides: BigNumber[]): this { + if (!this.info.cosignerData) { + this.initializeCosignerData({ outputOverrides }); + } else { + this.info.cosignerData.outputOverrides = outputOverrides; + } + return this; + } + + deadline(deadline: number): this { + super.deadline(deadline); + return this; + } + + swapper(swapper: string): this { + super.swapper(swapper); + return this; + } + + nonce(nonce: BigNumber): this { + super.nonce(nonce); + return this; + } + + validation(info: ValidationInfo): this { + super.validation(info); + return this; + } + + cosignerData(cosignerData: V3CosignerData): this { + this.decayStartBlock(cosignerData.decayStartBlock); + this.exclusiveFiller(cosignerData.exclusiveFiller); + this.exclusivityOverrideBps(cosignerData.exclusivityOverrideBps); + this.inputOverride(cosignerData.inputOverride); + this.outputOverrides(cosignerData.outputOverrides); + return this; + } + + exclusiveFiller(exclusiveFiller: string): this { + if (!this.info.cosignerData) { + this.initializeCosignerData({ exclusiveFiller }); + } else { + this.info.cosignerData.exclusiveFiller = exclusiveFiller; + } + return this; + } + + exclusivityOverrideBps(exclusivityOverrideBps: BigNumber): this { + if (!this.info.cosignerData) { + this.initializeCosignerData({ exclusivityOverrideBps }); + } else { + this.info.cosignerData.exclusivityOverrideBps = exclusivityOverrideBps; + } + return this; + } + + // ensures that we only change non fee outputs + nonFeeRecipient(newRecipient: string, feeRecipient?: string): this { + invariant( + newRecipient !== feeRecipient, + `newRecipient must be different from feeRecipient: ${newRecipient}` + ); + if (!this.info.outputs) { + return this; + } + this.info.outputs = this.info.outputs.map((output) => { + // if fee output then pass through + if ( + feeRecipient && + output.recipient.toLowerCase() === feeRecipient.toLowerCase() + ) { + return output; + } + + return { + ...output, + recipient: newRecipient, + }; + }); + return this; + } + + buildPartial(): UnsignedV3DutchOrder { + //build an unsigned order + this.checkUnsignedInvariants(this.info); + return new UnsignedV3DutchOrder( + Object.assign(this.getOrderInfo(), { + input: this.info.input, + outputs: this.info.outputs, + cosigner: this.info.cosigner, + startingBaseFee: this.info.startingBaseFee, + }), + this.chainId, + this.permit2Address + ); + } + + // A helper function for users of the class to easily the value to pass to maxAmount in an input + static getMaxAmountOut( + startAmount: BigNumber, + relativeAmounts: bigint[] + ): BigNumber { + if (relativeAmounts.length == 0) { + return startAmount; + } + + // Find the minimum of the relative amounts + const minRelativeAmount = relativeAmounts.reduce( + (min, amount) => (amount < min ? amount : min), + BigInt(0) + ); + + // Maximum is the start - the min of the relative amounts + const maxOut = startAmount.sub(minRelativeAmount.toString()); + return maxOut; + } +} diff --git a/sdks/uniswapx-sdk/src/builder/index.ts b/sdks/uniswapx-sdk/src/builder/index.ts index 3e374a3a0..e4891dd7b 100644 --- a/sdks/uniswapx-sdk/src/builder/index.ts +++ b/sdks/uniswapx-sdk/src/builder/index.ts @@ -3,3 +3,4 @@ export * from "./RelayOrderBuilder"; export * from "./V2DutchOrderBuilder"; export * from "./PriorityOrderBuilder"; export * from "./OrderBuilder"; +export * from "./V3DutchOrderBuilder"; diff --git a/sdks/uniswapx-sdk/src/constants.test.ts b/sdks/uniswapx-sdk/src/constants.test.ts index 886f83099..9d917906a 100644 --- a/sdks/uniswapx-sdk/src/constants.test.ts +++ b/sdks/uniswapx-sdk/src/constants.test.ts @@ -28,6 +28,7 @@ describe("REACTOR_ADDRESS_MAPPING", () => { "42161": Object { "Dutch": "0x0000000000000000000000000000000000000000", "Dutch_V2": "0x1bd1aAdc9E230626C44a139d7E70d842749351eb", + "Dutch_V3": "0xB274d5F4b833b61B340b654d600A864fB604a87c", "Relay": "0x0000000000000000000000000000000000000000", }, "5": Object { diff --git a/sdks/uniswapx-sdk/src/constants.ts b/sdks/uniswapx-sdk/src/constants.ts index 50f7bc259..5c081c740 100644 --- a/sdks/uniswapx-sdk/src/constants.ts +++ b/sdks/uniswapx-sdk/src/constants.ts @@ -23,10 +23,10 @@ export function constructSameAddressMap( } export const PERMIT2_MAPPING: AddressMap = { - ...constructSameAddressMap("0x000000000022d473030f116ddee9f6b43ac78ba3", [ - 11155111, - 42161, - ]), + ...constructSameAddressMap( + "0x000000000022d473030f116ddee9f6b43ac78ba3", + [11155111, 42161] + ), 12341234: "0x000000000022d473030f116ddee9f6b43ac78ba3", }; @@ -54,6 +54,7 @@ export enum OrderType { Dutch = "Dutch", Relay = "Relay", Dutch_V2 = "Dutch_V2", + Dutch_V3 = "Dutch_V3", Limit = "Limit", Priority = "Priority", } @@ -94,6 +95,7 @@ export const REACTOR_ADDRESS_MAPPING: ReactorMapping = { [OrderType.Dutch_V2]: "0x1bd1aAdc9E230626C44a139d7E70d842749351eb", [OrderType.Dutch]: "0x0000000000000000000000000000000000000000", [OrderType.Relay]: "0x0000000000000000000000000000000000000000", + [OrderType.Dutch_V3]: "0xB274d5F4b833b61B340b654d600A864fB604a87c", }, 8453: { [OrderType.Dutch]: "0x0000000000000000000000000000000000000000", diff --git a/sdks/uniswapx-sdk/src/contracts/V3DutchOrderReactor.ts b/sdks/uniswapx-sdk/src/contracts/V3DutchOrderReactor.ts new file mode 100644 index 000000000..ab1f5baa4 --- /dev/null +++ b/sdks/uniswapx-sdk/src/contracts/V3DutchOrderReactor.ts @@ -0,0 +1,426 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + BaseContract, + BigNumber, + BytesLike, + CallOverrides, + ContractTransaction, + Overrides, + PayableOverrides, + PopulatedTransaction, + Signer, + utils, +} from "ethers"; +import type { + FunctionFragment, + Result, + EventFragment, +} from "@ethersproject/abi"; +import type { Listener, Provider } from "@ethersproject/providers"; +import type { + TypedEventFilter, + TypedEvent, + TypedListener, + OnEvent, + PromiseOrValue, +} from "./common"; + +export type SignedOrderStruct = { + order: PromiseOrValue; + sig: PromiseOrValue; +}; + +export type SignedOrderStructOutput = [string, string] & { + order: string; + sig: string; +}; + +export interface V3DutchOrderReactorInterface extends utils.Interface { + functions: { + "execute((bytes,bytes))": FunctionFragment; + "executeBatch((bytes,bytes)[])": FunctionFragment; + "executeBatchWithCallback((bytes,bytes)[],bytes)": FunctionFragment; + "executeWithCallback((bytes,bytes),bytes)": FunctionFragment; + "feeController()": FunctionFragment; + "owner()": FunctionFragment; + "permit2()": FunctionFragment; + "setProtocolFeeController(address)": FunctionFragment; + "transferOwnership(address)": FunctionFragment; + }; + + getFunction( + nameOrSignatureOrTopic: + | "execute" + | "executeBatch" + | "executeBatchWithCallback" + | "executeWithCallback" + | "feeController" + | "owner" + | "permit2" + | "setProtocolFeeController" + | "transferOwnership" + ): FunctionFragment; + + encodeFunctionData( + functionFragment: "execute", + values: [SignedOrderStruct] + ): string; + encodeFunctionData( + functionFragment: "executeBatch", + values: [SignedOrderStruct[]] + ): string; + encodeFunctionData( + functionFragment: "executeBatchWithCallback", + values: [SignedOrderStruct[], PromiseOrValue] + ): string; + encodeFunctionData( + functionFragment: "executeWithCallback", + values: [SignedOrderStruct, PromiseOrValue] + ): string; + encodeFunctionData( + functionFragment: "feeController", + values?: undefined + ): string; + encodeFunctionData(functionFragment: "owner", values?: undefined): string; + encodeFunctionData(functionFragment: "permit2", values?: undefined): string; + encodeFunctionData( + functionFragment: "setProtocolFeeController", + values: [PromiseOrValue] + ): string; + encodeFunctionData( + functionFragment: "transferOwnership", + values: [PromiseOrValue] + ): string; + + decodeFunctionResult(functionFragment: "execute", data: BytesLike): Result; + decodeFunctionResult( + functionFragment: "executeBatch", + data: BytesLike + ): Result; + decodeFunctionResult( + functionFragment: "executeBatchWithCallback", + data: BytesLike + ): Result; + decodeFunctionResult( + functionFragment: "executeWithCallback", + data: BytesLike + ): Result; + decodeFunctionResult( + functionFragment: "feeController", + data: BytesLike + ): Result; + decodeFunctionResult(functionFragment: "owner", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "permit2", data: BytesLike): Result; + decodeFunctionResult( + functionFragment: "setProtocolFeeController", + data: BytesLike + ): Result; + decodeFunctionResult( + functionFragment: "transferOwnership", + data: BytesLike + ): Result; + + events: { + "Fill(bytes32,address,address,uint256)": EventFragment; + "OwnershipTransferred(address,address)": EventFragment; + "ProtocolFeeControllerSet(address,address)": EventFragment; + }; + + getEvent(nameOrSignatureOrTopic: "Fill"): EventFragment; + getEvent(nameOrSignatureOrTopic: "OwnershipTransferred"): EventFragment; + getEvent(nameOrSignatureOrTopic: "ProtocolFeeControllerSet"): EventFragment; +} + +export interface FillEventObject { + orderHash: string; + filler: string; + swapper: string; + nonce: BigNumber; +} +export type FillEvent = TypedEvent< + [string, string, string, BigNumber], + FillEventObject +>; + +export type FillEventFilter = TypedEventFilter; + +export interface OwnershipTransferredEventObject { + user: string; + newOwner: string; +} +export type OwnershipTransferredEvent = TypedEvent< + [string, string], + OwnershipTransferredEventObject +>; + +export type OwnershipTransferredEventFilter = + TypedEventFilter; + +export interface ProtocolFeeControllerSetEventObject { + oldFeeController: string; + newFeeController: string; +} +export type ProtocolFeeControllerSetEvent = TypedEvent< + [string, string], + ProtocolFeeControllerSetEventObject +>; + +export type ProtocolFeeControllerSetEventFilter = + TypedEventFilter; + +export interface V3DutchOrderReactor extends BaseContract { + connect(signerOrProvider: Signer | Provider | string): this; + attach(addressOrName: string): this; + deployed(): Promise; + + interface: V3DutchOrderReactorInterface; + + queryFilter( + event: TypedEventFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>; + + listeners( + eventFilter?: TypedEventFilter + ): Array>; + listeners(eventName?: string): Array; + removeAllListeners( + eventFilter: TypedEventFilter + ): this; + removeAllListeners(eventName?: string): this; + off: OnEvent; + on: OnEvent; + once: OnEvent; + removeListener: OnEvent; + + functions: { + execute( + order: SignedOrderStruct, + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + executeBatch( + orders: SignedOrderStruct[], + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + executeBatchWithCallback( + orders: SignedOrderStruct[], + callbackData: PromiseOrValue, + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + executeWithCallback( + order: SignedOrderStruct, + callbackData: PromiseOrValue, + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + feeController(overrides?: CallOverrides): Promise<[string]>; + + owner(overrides?: CallOverrides): Promise<[string]>; + + permit2(overrides?: CallOverrides): Promise<[string]>; + + setProtocolFeeController( + _newFeeController: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise; + + transferOwnership( + newOwner: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise; + }; + + execute( + order: SignedOrderStruct, + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + executeBatch( + orders: SignedOrderStruct[], + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + executeBatchWithCallback( + orders: SignedOrderStruct[], + callbackData: PromiseOrValue, + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + executeWithCallback( + order: SignedOrderStruct, + callbackData: PromiseOrValue, + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + feeController(overrides?: CallOverrides): Promise; + + owner(overrides?: CallOverrides): Promise; + + permit2(overrides?: CallOverrides): Promise; + + setProtocolFeeController( + _newFeeController: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise; + + transferOwnership( + newOwner: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise; + + callStatic: { + execute(order: SignedOrderStruct, overrides?: CallOverrides): Promise; + + executeBatch( + orders: SignedOrderStruct[], + overrides?: CallOverrides + ): Promise; + + executeBatchWithCallback( + orders: SignedOrderStruct[], + callbackData: PromiseOrValue, + overrides?: CallOverrides + ): Promise; + + executeWithCallback( + order: SignedOrderStruct, + callbackData: PromiseOrValue, + overrides?: CallOverrides + ): Promise; + + feeController(overrides?: CallOverrides): Promise; + + owner(overrides?: CallOverrides): Promise; + + permit2(overrides?: CallOverrides): Promise; + + setProtocolFeeController( + _newFeeController: PromiseOrValue, + overrides?: CallOverrides + ): Promise; + + transferOwnership( + newOwner: PromiseOrValue, + overrides?: CallOverrides + ): Promise; + }; + + filters: { + "Fill(bytes32,address,address,uint256)"( + orderHash?: PromiseOrValue | null, + filler?: PromiseOrValue | null, + swapper?: PromiseOrValue | null, + nonce?: null + ): FillEventFilter; + Fill( + orderHash?: PromiseOrValue | null, + filler?: PromiseOrValue | null, + swapper?: PromiseOrValue | null, + nonce?: null + ): FillEventFilter; + + "OwnershipTransferred(address,address)"( + user?: PromiseOrValue | null, + newOwner?: PromiseOrValue | null + ): OwnershipTransferredEventFilter; + OwnershipTransferred( + user?: PromiseOrValue | null, + newOwner?: PromiseOrValue | null + ): OwnershipTransferredEventFilter; + + "ProtocolFeeControllerSet(address,address)"( + oldFeeController?: null, + newFeeController?: null + ): ProtocolFeeControllerSetEventFilter; + ProtocolFeeControllerSet( + oldFeeController?: null, + newFeeController?: null + ): ProtocolFeeControllerSetEventFilter; + }; + + estimateGas: { + execute( + order: SignedOrderStruct, + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + executeBatch( + orders: SignedOrderStruct[], + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + executeBatchWithCallback( + orders: SignedOrderStruct[], + callbackData: PromiseOrValue, + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + executeWithCallback( + order: SignedOrderStruct, + callbackData: PromiseOrValue, + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + feeController(overrides?: CallOverrides): Promise; + + owner(overrides?: CallOverrides): Promise; + + permit2(overrides?: CallOverrides): Promise; + + setProtocolFeeController( + _newFeeController: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise; + + transferOwnership( + newOwner: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise; + }; + + populateTransaction: { + execute( + order: SignedOrderStruct, + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + executeBatch( + orders: SignedOrderStruct[], + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + executeBatchWithCallback( + orders: SignedOrderStruct[], + callbackData: PromiseOrValue, + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + executeWithCallback( + order: SignedOrderStruct, + callbackData: PromiseOrValue, + overrides?: PayableOverrides & { from?: PromiseOrValue } + ): Promise; + + feeController(overrides?: CallOverrides): Promise; + + owner(overrides?: CallOverrides): Promise; + + permit2(overrides?: CallOverrides): Promise; + + setProtocolFeeController( + _newFeeController: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise; + + transferOwnership( + newOwner: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise; + }; +} diff --git a/sdks/uniswapx-sdk/src/contracts/factories/V3DutchOrderReactor__factory.ts b/sdks/uniswapx-sdk/src/contracts/factories/V3DutchOrderReactor__factory.ts new file mode 100644 index 000000000..40c8aecd4 --- /dev/null +++ b/sdks/uniswapx-sdk/src/contracts/factories/V3DutchOrderReactor__factory.ts @@ -0,0 +1,432 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import { Signer, utils, Contract, ContractFactory, Overrides } from "ethers"; +import type { Provider, TransactionRequest } from "@ethersproject/providers"; +import type { PromiseOrValue } from "../common"; +import type { + V3DutchOrderReactor, + V3DutchOrderReactorInterface, +} from "../V3DutchOrderReactor"; + +const _abi = [ + { + type: "constructor", + inputs: [ + { + name: "_permit2", + type: "address", + internalType: "contract IPermit2", + }, + { + name: "_protocolFeeOwner", + type: "address", + internalType: "address", + }, + ], + stateMutability: "nonpayable", + }, + { + type: "receive", + stateMutability: "payable", + }, + { + type: "function", + name: "execute", + inputs: [ + { + name: "order", + type: "tuple", + internalType: "struct SignedOrder", + components: [ + { + name: "order", + type: "bytes", + internalType: "bytes", + }, + { + name: "sig", + type: "bytes", + internalType: "bytes", + }, + ], + }, + ], + outputs: [], + stateMutability: "payable", + }, + { + type: "function", + name: "executeBatch", + inputs: [ + { + name: "orders", + type: "tuple[]", + internalType: "struct SignedOrder[]", + components: [ + { + name: "order", + type: "bytes", + internalType: "bytes", + }, + { + name: "sig", + type: "bytes", + internalType: "bytes", + }, + ], + }, + ], + outputs: [], + stateMutability: "payable", + }, + { + type: "function", + name: "executeBatchWithCallback", + inputs: [ + { + name: "orders", + type: "tuple[]", + internalType: "struct SignedOrder[]", + components: [ + { + name: "order", + type: "bytes", + internalType: "bytes", + }, + { + name: "sig", + type: "bytes", + internalType: "bytes", + }, + ], + }, + { + name: "callbackData", + type: "bytes", + internalType: "bytes", + }, + ], + outputs: [], + stateMutability: "payable", + }, + { + type: "function", + name: "executeWithCallback", + inputs: [ + { + name: "order", + type: "tuple", + internalType: "struct SignedOrder", + components: [ + { + name: "order", + type: "bytes", + internalType: "bytes", + }, + { + name: "sig", + type: "bytes", + internalType: "bytes", + }, + ], + }, + { + name: "callbackData", + type: "bytes", + internalType: "bytes", + }, + ], + outputs: [], + stateMutability: "payable", + }, + { + type: "function", + name: "feeController", + inputs: [], + outputs: [ + { + name: "", + type: "address", + internalType: "contract IProtocolFeeController", + }, + ], + stateMutability: "view", + }, + { + type: "function", + name: "owner", + inputs: [], + outputs: [ + { + name: "", + type: "address", + internalType: "address", + }, + ], + stateMutability: "view", + }, + { + type: "function", + name: "permit2", + inputs: [], + outputs: [ + { + name: "", + type: "address", + internalType: "contract IPermit2", + }, + ], + stateMutability: "view", + }, + { + type: "function", + name: "setProtocolFeeController", + inputs: [ + { + name: "_newFeeController", + type: "address", + internalType: "address", + }, + ], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "transferOwnership", + inputs: [ + { + name: "newOwner", + type: "address", + internalType: "address", + }, + ], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "event", + name: "Fill", + inputs: [ + { + name: "orderHash", + type: "bytes32", + indexed: true, + internalType: "bytes32", + }, + { + name: "filler", + type: "address", + indexed: true, + internalType: "address", + }, + { + name: "swapper", + type: "address", + indexed: true, + internalType: "address", + }, + { + name: "nonce", + type: "uint256", + indexed: false, + internalType: "uint256", + }, + ], + anonymous: false, + }, + { + type: "event", + name: "OwnershipTransferred", + inputs: [ + { + name: "user", + type: "address", + indexed: true, + internalType: "address", + }, + { + name: "newOwner", + type: "address", + indexed: true, + internalType: "address", + }, + ], + anonymous: false, + }, + { + type: "event", + name: "ProtocolFeeControllerSet", + inputs: [ + { + name: "oldFeeController", + type: "address", + indexed: false, + internalType: "address", + }, + { + name: "newFeeController", + type: "address", + indexed: false, + internalType: "address", + }, + ], + anonymous: false, + }, + { + type: "error", + name: "DeadlineReached", + inputs: [], + }, + { + type: "error", + name: "DuplicateFeeOutput", + inputs: [ + { + name: "duplicateToken", + type: "address", + internalType: "address", + }, + ], + }, + { + type: "error", + name: "FeeTooLarge", + inputs: [ + { + name: "token", + type: "address", + internalType: "address", + }, + { + name: "amount", + type: "uint256", + internalType: "uint256", + }, + { + name: "recipient", + type: "address", + internalType: "address", + }, + ], + }, + { + type: "error", + name: "IndexOutOfBounds", + inputs: [], + }, + { + type: "error", + name: "InputAndOutputFees", + inputs: [], + }, + { + type: "error", + name: "InvalidCosignature", + inputs: [], + }, + { + type: "error", + name: "InvalidCosignerInput", + inputs: [], + }, + { + type: "error", + name: "InvalidCosignerOutput", + inputs: [], + }, + { + type: "error", + name: "InvalidDecayCurve", + inputs: [], + }, + { + type: "error", + name: "InvalidFeeToken", + inputs: [ + { + name: "feeToken", + type: "address", + internalType: "address", + }, + ], + }, + { + type: "error", + name: "InvalidReactor", + inputs: [], + }, + { + type: "error", + name: "NativeTransferFailed", + inputs: [], + }, + { + type: "error", + name: "NoExclusiveOverride", + inputs: [], + }, +] as const; + +const _bytecode = + "0x60a06040523480156200001157600080fd5b50604051620044c4380380620044c48339810160408190526200003491620000b8565b600080546001600160a01b0319166001600160a01b03831690811782556040518492849283928392907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350506001600255506001600160a01b031660805250620000f79050565b6001600160a01b0381168114620000b557600080fd5b50565b60008060408385031215620000cc57600080fd5b8251620000d9816200009f565b6020840151909250620000ec816200009f565b809150509250929050565b6080516143ab620001196000396000818160e00152611a5901526143ab6000f3fe60806040526004361061009a5760003560e01c80632d771389116100695780636999b3771161004e5780636999b377146101715780638da5cb5b1461019e578063f2fde38b146101cb57600080fd5b80632d7713891461013e5780633f62192e1461015e57600080fd5b80630d335884146100a65780630d7a16c3146100bb57806312261ee7146100ce57806313fb72c71461012b57600080fd5b366100a157005b600080fd5b6100b96100b4366004612e6a565b6101eb565b005b6100b96100c9366004612f18565b610364565b3480156100da57600080fd5b506101027f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100b9610139366004612f5a565b6104c5565b34801561014a57600080fd5b506100b9610159366004612ff8565b610683565b6100b961016c366004613015565b61078f565b34801561017d57600080fd5b506001546101029073ffffffffffffffffffffffffffffffffffffffff1681565b3480156101aa57600080fd5b506000546101029073ffffffffffffffffffffffffffffffffffffffff1681565b3480156101d757600080fd5b506100b96101e6366004612ff8565b610894565b6101f3610985565b604080516001808252818301909252600091816020015b6040805161016081018252600060a0820181815260c0830182905260e0830182905261010083018290526101208301829052606061014084018190529083528351808201855282815260208082018490528186018490528085019190915293830181905280830152608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161020a5790505090506102b2846109f6565b816000815181106102c5576102c5613079565b60200260200101819052506102d981610b67565b6040517f585da628000000000000000000000000000000000000000000000000000000008152339063585da628906103199084908790879060040161327c565b600060405180830381600087803b15801561033357600080fd5b505af1158015610347573d6000803e3d6000fd5b5050505061035481610bb8565b5061035f6001600255565b505050565b61036c610985565b8060008167ffffffffffffffff8111156103885761038861304a565b60405190808252806020026020018201604052801561044357816020015b6040805161016081018252600060a0820181815260c0830182905260e0830182905261010083018290526101208301829052606061014084018190529083528351808201855282815260208082018490528186018490528085019190915293830181905280830152608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816103a65790505b50905060005b828110156104a25761047d85858381811061046657610466613079565b90506020028101906104789190613342565b6109f6565b82828151811061048f5761048f613079565b6020908102919091010152600101610449565b506104ac81610b67565b6104b581610bb8565b50506104c16001600255565b5050565b6104cd610985565b8260008167ffffffffffffffff8111156104e9576104e961304a565b6040519080825280602002602001820160405280156105a457816020015b6040805161016081018252600060a0820181815260c0830182905260e0830182905261010083018290526101208301829052606061014084018190529083528351808201855282815260208082018490528186018490528085019190915293830181905280830152608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816105075790505b50905060005b828110156105ec576105c787878381811061046657610466613079565b8282815181106105d9576105d9613079565b60209081029190910101526001016105aa565b506105f681610b67565b6040517f585da628000000000000000000000000000000000000000000000000000000008152339063585da628906106369084908890889060040161327c565b600060405180830381600087803b15801561065057600080fd5b505af1158015610664573d6000803e3d6000fd5b5050505061067181610bb8565b505061067d6001600255565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610709576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527fb904ae9529e373e48bc82df4326cceaf1b4c472babf37f5b7dec46fecc6b53e0910160405180910390a15050565b610797610985565b604080516001808252818301909252600091816020015b6040805161016081018252600060a0820181815260c0830182905260e0830182905261010083018290526101208301829052606061014084018190529083528351808201855282815260208082018490528186018490528085019190915293830181905280830152608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816107ae579050509050610856826109f6565b8160008151811061086957610869613079565b602002602001018190525061087d81610b67565b61088681610bb8565b506108916001600255565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610700565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b60028054036109f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610700565b60028055565b6040805161016081018252600060a0820181815260c0830182905260e083018290526101008301829052610120830182905260606101408401819052908352835180820185528281526020808201849052818601849052840152928201839052828201929092526080810182905290610a6f8380613380565b810190610a7c919061394e565b90506000610a8982610d0b565b9050610a958183610ff1565b610a9e8261104d565b610aa7826111b1565b6040805160a080820190925283518152908301515160608401516020830191610ad091906112e0565b815260a0840151516080850151602090920191610aec91611374565b8152602001858060200190610b019190613380565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602090810183905260a0840151908101518151604090920151929550610b6092869290611459565b5050919050565b805160005b8181101561035f576000838281518110610b8857610b88613079565b60200260200101519050610b9b81611466565b610ba58133611956565b610baf8133611a57565b50600101610b6c565b805160005b81811015610cfa576000838281518110610bd957610bd9613079565b602002602001015190506000816040015151905060005b81811015610c5a57600083604001518281518110610c1057610c10613079565b60200260200101519050610c5181604001518260200151836000015173ffffffffffffffffffffffffffffffffffffffff16611e599092919063ffffffff16565b50600101610bf0565b5081600001516020015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16868581518110610ca357610ca3613079565b6020026020010151608001517f78ad7ec0e9f89e74012afa58738b6b661c024cb0fd185ee2f616c0a28924bd66856000015160400151604051610ce891815260200190565b60405180910390a45050600101610bbd565b5047156104c1576104c13347611ea0565b6040517f563344757463684f72646572280000000000000000000000000000000000000060208201527f4f72646572496e666f20696e666f2c0000000000000000000000000000000000602d8201527f6164647265737320636f7369676e65722c000000000000000000000000000000603c8201527f75696e74323536207374617274696e67426173654665652c0000000000000000604d8201527f56334475746368496e7075742062617365496e7075742c00000000000000000060658201527f563344757463684f75747075745b5d20626173654f7574707574732900000000607c820152600090609801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f4e6f6e6c696e656172447574636844656361792800000000000000000000000060208301527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060348301527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000604b83015290606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815260c08301909152608d8083529091906142e96020830139604051602001610eee90613a66565b604051602081830303815290604052604051602001610f0c90613b78565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610f4b9594939291602001613cb0565b60405160208183030381529060405280519060200120610f6e8360000151611f3a565b83602001518460400151610f858660600151611fd4565b610f928760800151612125565b60408051602081019790975286019490945273ffffffffffffffffffffffffffffffffffffffff9092166060850152608084015260a083015260c082015260e0015b604051602081830303815290604052805190602001209050919050565b805160600151421115611030576040517fb08ce5b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101516104c19061104383856121c6565b8360c00151612239565b60a081015160600151156110b9578060600151602001518160a001516060015111156110a5576040517fac9143e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a081015160609081015190820151602001525b8060800151518160a00151608001515114611100576040517fa305df8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60808101515160005b8181101561035f5760008360800151828151811061112957611129613079565b6020026020010151905060008460a0015160800151838151811061114f5761114f613079565b60200260200101519050806000146111a757816020015181101561119f576040517fa305df8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602082018190525b5050600101611109565b60006111ca82604001514861236190919063ffffffff16565b9050816060015160800151600014611236576000633b9aca00828460600151608001516111f79190613d4a565b6112019190613d96565b905061122b81600085606001516060015186606001516020015161239c909392919063ffffffff16565b606084015160200152505b60808201515160005b8181101561067d5760008460800151828151811061125f5761125f613079565b602002602001015190508060a001516000146112d7576000633b9aca00858360a0015161128c9190613d4a565b6112969190613d96565b608083015160208401519192506112d0919083907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6123bc565b6020830152505b5060010161123f565b61131a6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b600061133684604001518560200151856000886060015161244e565b6040805160608082018352875173ffffffffffffffffffffffffffffffffffffffff1682526020820193909352959091015190850152509192915050565b81516060908067ffffffffffffffff8111156113925761139261304a565b6040519080825280602002602001820160405280156113fb57816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816113b05790505b50915060005b818110156114515761142c85828151811061141e5761141e613079565b602002602001015185612518565b83828151811061143e5761143e613079565b6020908102919091010152600101611401565b505092915050565b61067d84848484436125ca565b60015473ffffffffffffffffffffffffffffffffffffffff166114865750565b6001546040517f8aa6cf0300000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff1690638aa6cf03906114dd908590600401613e25565b600060405180830381865afa1580156114fa573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115409190810190613e38565b60408301515181519192509060006115588284613f08565b67ffffffffffffffff8111156115705761157061304a565b6040519080825280602002602001820160405280156115d957816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161158e5790505b50905060005b8381101561162a57856040015181815181106115fd576115fd613079565b602002602001015182828151811061161757611617613079565b60209081029190910101526001016115df565b5060008060005b8481101561194557600087828151811061164d5761164d613079565b6020026020010151905060005b8281101561170b5788818151811061167457611674613079565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff16036117035781516040517ffff0830300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610700565b60010161165a565b506000805b888110156117cc5760008b60400151828151811061173057611730613079565b60200260200101519050836000015173ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff16036117c35785156117ad576040517fedc7e2e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101516117bc9084613f08565b9250600196505b50600101611710565b50815160208b01515173ffffffffffffffffffffffffffffffffffffffff91821691160361184557841561182c576040517fedc7e2e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808b0151015161183e9082613f08565b9050600193505b8060000361189a5781516040517feddf07f500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610700565b6118a8816005612710612673565b8260200151111561191b578151602083015160408085015190517f82e7565600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841660048201526024810192909252919091166044820152606401610700565b8186848a018151811061193057611930613079565b60209081029190910101525050600101611631565b505050604090940193909352505050565b81515173ffffffffffffffffffffffffffffffffffffffff1630146119a7576040517f4ddf4a6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81516080015173ffffffffffffffffffffffffffffffffffffffff16156104c1578151608001516040517f6e84ba2b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690636e84ba2b90611a239084908690600401613f1b565b60006040518083038186803b158015611a3b57600080fd5b505afa158015611a4f573d6000803e3d6000fd5b505050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663137c29fe611b17846040805160a0810182526000606082018181526080830182905282526020820181905291810191909152506040805160a081018252602080840180515173ffffffffffffffffffffffffffffffffffffffff1660608085019182529151850151608085015283528451840151918301919091529251909201519082015290565b6040805180820182526000808252602091820152815180830190925273ffffffffffffffffffffffffffffffffffffffff8616825280870151810151908201528560000151602001518660800151604051602001611be4907f4e6f6e6c696e656172447574636844656361792800000000000000000000000081527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060148201527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000602b82015260440190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815260c08301909152608d8083529091906142e960208301396040518060600160405280602e81526020016142bb602e9139604051602001611c4e90613a66565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f563344757463684f72646572280000000000000000000000000000000000000060208401527f4f72646572496e666f20696e666f2c0000000000000000000000000000000000602d8401527f6164647265737320636f7369676e65722c000000000000000000000000000000603c8401527f75696e74323536207374617274696e67426173654665652c0000000000000000604d8401527f56334475746368496e7075742062617365496e7075742c00000000000000000060658401527f563344757463684f75747075745b5d20626173654f7574707574732900000000607c840152815160788185030181526098840190925291611d7e9060b801613b78565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611dbe969594939291602001613f4a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905260608a01517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b168352611e2b9695949392600401613ffd565b600060405180830381600087803b158015611e4557600080fd5b505af1158015611a4f573d6000803e3d6000fd5b73ffffffffffffffffffffffffffffffffffffffff8316611e7e5761035f8282611ea0565b61035f73ffffffffffffffffffffffffffffffffffffffff84163384846126af565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611efa576040519150601f19603f3d011682016040523d82523d6000602084013e611eff565b606091505b505090508061035f576040517ff4b3b1bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060c00160405280608d81526020016142e9608d913980516020918201208351848301516040808701516060880151608089015160a08a01518051908901209351610fd498939492939192910196875273ffffffffffffffffffffffffffffffffffffffff958616602088015293851660408701526060860192909252608085015290911660a083015260c082015260e00190565b6000604051602001611fe590613a66565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f4e6f6e6c696e656172447574636844656361792800000000000000000000000060208401527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060348401527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000604b84015281516044818503018152606484019092526120a5929091906084016140b8565b60405160208183030381529060405280519060200120826000015183602001516120d2856040015161279a565b60608087015160808089015160408051602081019990995273ffffffffffffffffffffffffffffffffffffffff909716968801969096529186019390935284015260a083015260c082015260e001610fd4565b600080825160200267ffffffffffffffff8111156121455761214561304a565b6040519080825280601f01601f19166020018201604052801561216f576020820181803683370190505b50835190915060005b818110156121b65760006121a486838151811061219757612197613079565b6020026020010151612898565b60208381028601015250600101612178565b5050805160209091012092915050565b6000818360a001516040516020016121de91906140e7565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261221a929160200161416c565b6040516020818303038152906040528051906020012090505b92915050565b600080828060200190518101906122509190614192565b9150915060008360408151811061226957612269613079565b0160209081015160408051600080825293810180835289905260f89290921c9082018190526060820186905260808201859052925060019060a0016020604051602081039080840390855afa1580156122c6573d6000803e3d6000fd5b5050506020604051035190508073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16141580612321575073ffffffffffffffffffffffffffffffffffffffff8116155b15612358576040517fd7815be100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60008183101561238f5761237d61237884846141b6565b6129fc565b6123889060006141c9565b9050612233565b61238861237883856141b6565b60006123b3856123ac86846141c9565b85856123bc565b95945050505050565b60008084121561241f5760006123d1856141f0565b9050856123fe827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6141b6565b101561240d5782915050612446565b6124178187613f08565b91505061243b565b8385101561242e575081612446565b61243884866141b6565b90505b6123b3818484612ab2565b949350505050565b600060108660200151511115612490576040517f0e99676600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b43841015806124a25750602086015151155b156124b9576124b2858484612ab2565b90506123b3565b60006124c585436141b6565b90506000806000806124d78b86612ac7565b935093509350935060006124fa8561ffff168561ffff168861ffff168686612c89565b90506125088b828b8b6123bc565b9c9b505050505050505050505050565b60408051606081018252600080825260208201819052918101919091526000612570846040015185602001518587608001517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61244e565b90506040518060600160405280856000015173ffffffffffffffffffffffffffffffffffffffff168152602001828152602001856060015173ffffffffffffffffffffffffffffffffffffffff1681525091505092915050565b6125d5848483612d0e565b61266c5781612610576040517fb9ec1e9600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604085015160005b815181101561235857600082828151811061263557612635613079565b6020026020010151905061265e856127106126509190613f08565b602083015190612710612d5a565b602090910152600101612618565b5050505050565b6000827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04841183021582026126a857600080fd5b5091020490565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff841660248201528260448201526020600060648360008a5af13d15601f3d116001600051141617169150508061266c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401610700565b6040517f4e6f6e6c696e656172447574636844656361792800000000000000000000000060208201527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060348201527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000604b82015260009060640160405160208183030381529060405280519060200120826000015183602001516040516020016128459190614228565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120908301949094528101919091526060810191909152608001610fd4565b60006040516020016128a990613b78565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f4e6f6e6c696e656172447574636844656361792800000000000000000000000060208401527f75696e743235362072656c6174697665426c6f636b732c00000000000000000060348401527f696e743235365b5d2072656c6174697665416d6f756e74732900000000000000604b8401528151604481850301815260648401909252612969929091906084016140b8565b6040516020818303038152906040528051906020012082600001518360200151612996856040015161279a565b60608087015160808089015160a0808b015160408051602081019b909b5273ffffffffffffffffffffffffffffffffffffffff998a16908b01529489019690965290870193909352939093169184019190915260c083015260e082015261010001610fd4565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115612aae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e743235360000000000000000000000000000000000000000000000006064820152608401610700565b5090565b6000612446612ac18585612d9e565b83612db6565b6000806000806000612ada876000015190565b905061ffff8616612aec826000612dc5565b61ffff1610612b30576000612b018282612dc5565b60008960200151600081518110612b1a57612b1a613079565b6020026020010151945094509450945050612c80565b60006001886020015151612b44919061425e565b905060015b8161ffff168161ffff1611612c14578761ffff16612b748261ffff1685612dc590919063ffffffff16565b61ffff1610612c0257612b96612b8b60018361425e565b849061ffff16612dc5565b612ba48461ffff8416612dc5565b60208b0151612bb460018561425e565b61ffff1681518110612bc857612bc8613079565b60200260200101518b602001518461ffff1681518110612bea57612bea613079565b60200260200101519650965096509650505050612c80565b80612c0c81614279565b915050612b49565b50612c238261ffff8316612dc5565b612c318361ffff8416612dc5565b89602001518361ffff1681518110612c4b57612c4b613079565b60200260200101518a602001518461ffff1681518110612c6d57612c6d613079565b6020026020010151955095509550955050505b92959194509250565b6000848410612c995750806123b3565b6000612ca587866141b6565b90506000612cb388886141b6565b9050600085851215612ce557612cd58383612cce888a6141c9565b9190612673565b612cde906141f0565b9050612cf7565b612cf48383612cce89896141c9565b90505b612d01818761429a565b9998505050505050505050565b600073ffffffffffffffffffffffffffffffffffffffff84161580612d3257508282115b80612446575073ffffffffffffffffffffffffffffffffffffffff8416331490509392505050565b6000827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0484118302158202612d8f57600080fd5b50910281810615159190040190565b6000818311612dad5781612daf565b825b9392505050565b6000818310612dad5781612daf565b600060108210612e01576040517f4e23d03500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506010021c90565b600060408284031215612e1b57600080fd5b50919050565b60008083601f840112612e3357600080fd5b50813567ffffffffffffffff811115612e4b57600080fd5b602083019150836020828501011115612e6357600080fd5b9250929050565b600080600060408486031215612e7f57600080fd5b833567ffffffffffffffff80821115612e9757600080fd5b612ea387838801612e09565b94506020860135915080821115612eb957600080fd5b50612ec686828701612e21565b9497909650939450505050565b60008083601f840112612ee557600080fd5b50813567ffffffffffffffff811115612efd57600080fd5b6020830191508360208260051b8501011115612e6357600080fd5b60008060208385031215612f2b57600080fd5b823567ffffffffffffffff811115612f4257600080fd5b612f4e85828601612ed3565b90969095509350505050565b60008060008060408587031215612f7057600080fd5b843567ffffffffffffffff80821115612f8857600080fd5b612f9488838901612ed3565b90965094506020870135915080821115612fad57600080fd5b50612fba87828801612e21565b95989497509550505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461089157600080fd5b8035612ff381612fc6565b919050565b60006020828403121561300a57600080fd5b8135612daf81612fc6565b60006020828403121561302757600080fd5b813567ffffffffffffffff81111561303e57600080fd5b61244684828501612e09565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60005b838110156130c35781810151838201526020016130ab565b50506000910152565b600081518084526130e48160208601602086016130a8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60008151808452602080850194506020840160005b83811015613176578151805173ffffffffffffffffffffffffffffffffffffffff908116895284820151858a015260409182015116908801526060909601959082019060010161312b565b509495945050505050565b6000815160e0845273ffffffffffffffffffffffffffffffffffffffff8082511660e08601528060208301511661010086015260408201516101208601526060820151610140860152806080830151166101608601525060a0810151905060c06101808501526131f56101a08501826130cc565b905060208301516132336020860182805173ffffffffffffffffffffffffffffffffffffffff16825260208082015190830152604090810151910152565b506040830151848203608086015261324b8282613116565b915050606083015184820360a086015261326582826130cc565b915050608083015160c08501528091505092915050565b6000604082016040835280865180835260608501915060608160051b8601019250602080890160005b838110156132f1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526132df868351613181565b955093820193908201906001016132a5565b5050858403818701528684528688828601376000848801820152601f9096017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092019094019695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261337657600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126133b557600080fd5b83018035915067ffffffffffffffff8211156133d057600080fd5b602001915036819003821315612e6357600080fd5b60405160c0810167ffffffffffffffff811182821017156134085761340861304a565b60405290565b6040805190810167ffffffffffffffff811182821017156134085761340861304a565b60405160a0810167ffffffffffffffff811182821017156134085761340861304a565b60405160e0810167ffffffffffffffff811182821017156134085761340861304a565b6040516060810167ffffffffffffffff811182821017156134085761340861304a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156134e1576134e161304a565b604052919050565b600082601f8301126134fa57600080fd5b813567ffffffffffffffff8111156135145761351461304a565b61354560207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161349a565b81815284602083860101111561355a57600080fd5b816020850160208301376000918101602001919091529392505050565b600060c0828403121561358957600080fd5b6135916133e5565b9050813561359e81612fc6565b815260208201356135ae81612fc6565b80602083015250604082013560408201526060820135606082015260808201356135d781612fc6565b608082015260a082013567ffffffffffffffff8111156135f657600080fd5b613602848285016134e9565b60a08301525092915050565b600067ffffffffffffffff8211156136285761362861304a565b5060051b60200190565b60006040828403121561364457600080fd5b61364c61340e565b90508135815260208083013567ffffffffffffffff81111561366d57600080fd5b8301601f8101851361367e57600080fd5b803561369161368c8261360e565b61349a565b81815260059190911b820183019083810190878311156136b057600080fd5b928401925b828410156136ce578335825292840192908401906136b5565b8085870152505050505092915050565b600060a082840312156136f057600080fd5b6136f8613431565b9050813561370581612fc6565b815260208281013590820152604082013567ffffffffffffffff81111561372b57600080fd5b61373784828501613632565b604083015250606082013560608201526080820135608082015292915050565b600082601f83011261376857600080fd5b8135602061377861368c8361360e565b82815260059290921b8401810191818101908684111561379757600080fd5b8286015b8481101561387457803567ffffffffffffffff808211156137bc5760008081fd5b818901915060c0807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848d030112156137f55760008081fd5b6137fd6133e5565b8784013561380a81612fc6565b8152604084810135898301526060808601358581111561382a5760008081fd5b6138388f8c838a0101613632565b83850152506080945084860135915061385082612fc6565b82015260a0848101359382019390935292013590820152835291830191830161379b565b509695505050505050565b600060a0828403121561389157600080fd5b613899613431565b9050813581526020808301356138ae81612fc6565b8082840152506040830135604083015260608301356060830152608083013567ffffffffffffffff8111156138e257600080fd5b8301601f810185136138f357600080fd5b803561390161368c8261360e565b81815260059190911b8201830190838101908783111561392057600080fd5b928401925b8284101561393e57833582529284019290840190613925565b6080860152509295945050505050565b60006020828403121561396057600080fd5b813567ffffffffffffffff8082111561397857600080fd5b9083019060e0828603121561398c57600080fd5b613994613454565b8235828111156139a357600080fd5b6139af87828601613577565b8252506139be60208401612fe8565b6020820152604083013560408201526060830135828111156139df57600080fd5b6139eb878286016136de565b606083015250608083013582811115613a0357600080fd5b613a0f87828601613757565b60808301525060a083013582811115613a2757600080fd5b613a338782860161387f565b60a08301525060c083013582811115613a4b57600080fd5b613a57878286016134e9565b60c08301525095945050505050565b7f56334475746368496e707574280000000000000000000000000000000000000081527f6164647265737320746f6b656e2c000000000000000000000000000000000000600d8201527f75696e74323536207374617274416d6f756e742c000000000000000000000000601b8201527f4e6f6e6c696e656172447574636844656361792063757276652c000000000000602f8201527f75696e74323536206d6178416d6f756e742c000000000000000000000000000060498201527f75696e743235362061646a7573746d656e745065724777656942617365466565605b8201527f2900000000000000000000000000000000000000000000000000000000000000607b8201526000607c8201612233565b7f563344757463684f75747075742800000000000000000000000000000000000081527f6164647265737320746f6b656e2c000000000000000000000000000000000000600e8201527f75696e74323536207374617274416d6f756e742c000000000000000000000000601c8201527f4e6f6e6c696e656172447574636844656361792063757276652c00000000000060308201527f6164647265737320726563697069656e742c0000000000000000000000000000604a8201527f75696e74323536206d696e416d6f756e742c0000000000000000000000000000605c8201527f75696e743235362061646a7573746d656e745065724777656942617365466565606e8201527f2900000000000000000000000000000000000000000000000000000000000000608e8201526000608f8201612233565b60008651613cc2818460208b016130a8565b865190830190613cd6818360208b016130a8565b8651910190613ce9818360208a016130a8565b8551910190613cfc8183602089016130a8565b8451910190613d0f8183602088016130a8565b01979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202600082127f800000000000000000000000000000000000000000000000000000000000000084141615613d8257613d82613d1b565b818105831482151761223357612233613d1b565b600082613dcc577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615613e2057613e20613d1b565b500590565b602081526000612daf6020830184613181565b60006020808385031215613e4b57600080fd5b825167ffffffffffffffff811115613e6257600080fd5b8301601f81018513613e7357600080fd5b8051613e8161368c8261360e565b81815260609182028301840191848201919088841115613ea057600080fd5b938501935b83851015613efc5780858a031215613ebd5760008081fd5b613ec5613477565b8551613ed081612fc6565b81528587015187820152604080870151613ee981612fc6565b9082015283529384019391850191613ea5565b50979650505050505050565b8082018082111561223357612233613d1b565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006124466040830184613181565b7f563344757463684f72646572207769746e65737329000000000000000000000081526000601588516020613f8482848701838e016130a8565b895191850191613f9981858501848e016130a8565b8951920191613fad81858501848d016130a8565b8851920191613fc181858501848c016130a8565b8751920191613fd581858501848b016130a8565b8651920191613fe981858501848a016130a8565b919091019091019998505050505050505050565b600061014061402d838a51805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b602089015160408401526040890151606084015261406e6080840189805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b73ffffffffffffffffffffffffffffffffffffffff871660c08401528560e0840152806101008401526140a3818401866130cc565b9050828103610120840152612d0181856130cc565b600083516140ca8184602088016130a8565b8351908301906140de8183602088016130a8565b01949350505050565b6000602080835260c0830184518285015273ffffffffffffffffffffffffffffffffffffffff828601511660408501526040850151606085015260608501516080850152608085015160a08086015281815180845260e0870191508483019350600092505b80831015613874578351825292840192600192909201919084019061414c565b828152600082516141848160208501602087016130a8565b919091016020019392505050565b600080604083850312156141a557600080fd5b505080516020909101519092909150565b8181038181111561223357612233613d1b565b81810360008312801583831316838312821617156141e9576141e9613d1b565b5092915050565b60007f8000000000000000000000000000000000000000000000000000000000000000820361422157614221613d1b565b5060000390565b815160009082906020808601845b8381101561425257815185529382019390820190600101614236565b50929695505050505050565b61ffff8281168282160390808211156141e9576141e9613d1b565b600061ffff80831681810361429057614290613d1b565b6001019392505050565b808201828112600083128015821682158216171561145157611451613d1b56fe546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e74294f72646572496e666f28616464726573732072656163746f722c6164647265737320737761707065722c75696e74323536206e6f6e63652c75696e7432353620646561646c696e652c61646472657373206164646974696f6e616c56616c69646174696f6e436f6e74726163742c6279746573206164646974696f6e616c56616c69646174696f6e4461746129a2646970667358221220cfaf36c7e3c9798dfd6bc92252ac740ff42fa3a7b113877282829c51de339a4d64736f6c63430008180033"; + +type V3DutchOrderReactorConstructorParams = + | [signer?: Signer] + | ConstructorParameters; + +const isSuperArgs = ( + xs: V3DutchOrderReactorConstructorParams +): xs is ConstructorParameters => xs.length > 1; + +export class V3DutchOrderReactor__factory extends ContractFactory { + constructor(...args: V3DutchOrderReactorConstructorParams) { + if (isSuperArgs(args)) { + super(...args); + } else { + super(_abi, _bytecode, args[0]); + } + } + + override deploy( + _permit2: PromiseOrValue, + _protocolFeeOwner: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise { + return super.deploy( + _permit2, + _protocolFeeOwner, + overrides || {} + ) as Promise; + } + override getDeployTransaction( + _permit2: PromiseOrValue, + _protocolFeeOwner: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): TransactionRequest { + return super.getDeployTransaction( + _permit2, + _protocolFeeOwner, + overrides || {} + ); + } + override attach(address: string): V3DutchOrderReactor { + return super.attach(address) as V3DutchOrderReactor; + } + override connect(signer: Signer): V3DutchOrderReactor__factory { + return super.connect(signer) as V3DutchOrderReactor__factory; + } + + static readonly bytecode = _bytecode; + static readonly abi = _abi; + static createInterface(): V3DutchOrderReactorInterface { + return new utils.Interface(_abi) as V3DutchOrderReactorInterface; + } + static connect( + address: string, + signerOrProvider: Signer | Provider + ): V3DutchOrderReactor { + return new Contract(address, _abi, signerOrProvider) as V3DutchOrderReactor; + } +} diff --git a/sdks/uniswapx-sdk/src/contracts/factories/index.ts b/sdks/uniswapx-sdk/src/contracts/factories/index.ts index 8dbcf994e..9d38bbd7e 100644 --- a/sdks/uniswapx-sdk/src/contracts/factories/index.ts +++ b/sdks/uniswapx-sdk/src/contracts/factories/index.ts @@ -10,5 +10,6 @@ export { PriorityOrderReactor__factory } from "./PriorityOrderReactor__factory"; export { RelayOrderReactor__factory } from "./RelayOrderReactor__factory"; export { SwapRouter02Executor__factory } from "./SwapRouter02Executor__factory"; export { V2DutchOrderReactor__factory } from "./V2DutchOrderReactor__factory"; +export { V3DutchOrderReactor__factory } from "./V3DutchOrderReactor__factory"; export { DeploylessMulticall2__factory } from "./DeploylessMulticall2__factory"; export { Multicall2__factory } from "./Multicall2__factory"; diff --git a/sdks/uniswapx-sdk/src/contracts/index.ts b/sdks/uniswapx-sdk/src/contracts/index.ts index 3306d859b..200ee3c8a 100644 --- a/sdks/uniswapx-sdk/src/contracts/index.ts +++ b/sdks/uniswapx-sdk/src/contracts/index.ts @@ -10,6 +10,7 @@ export type { PriorityOrderReactor } from "./PriorityOrderReactor"; export type { RelayOrderReactor } from "./RelayOrderReactor"; export type { SwapRouter02Executor } from "./SwapRouter02Executor"; export type { V2DutchOrderReactor } from "./V2DutchOrderReactor"; +export type { V3DutchOrderReactor } from "./V3DutchOrderReactor"; export type { DeploylessMulticall2 } from "./DeploylessMulticall2"; export type { Multicall2 } from "./Multicall2"; export * as factories from "./factories"; @@ -22,5 +23,6 @@ export { PriorityOrderReactor__factory } from "./factories/PriorityOrderReactor_ export { RelayOrderReactor__factory } from "./factories/RelayOrderReactor__factory"; export { SwapRouter02Executor__factory } from "./factories/SwapRouter02Executor__factory"; export { V2DutchOrderReactor__factory } from "./factories/V2DutchOrderReactor__factory"; +export { V3DutchOrderReactor__factory } from "./factories/V3DutchOrderReactor__factory"; export { DeploylessMulticall2__factory } from "./factories/DeploylessMulticall2__factory"; export { Multicall2__factory } from "./factories/Multicall2__factory"; diff --git a/sdks/uniswapx-sdk/src/order/V2DutchOrder.test.ts b/sdks/uniswapx-sdk/src/order/V2DutchOrder.test.ts index 738ee711f..ac1589b1a 100644 --- a/sdks/uniswapx-sdk/src/order/V2DutchOrder.test.ts +++ b/sdks/uniswapx-sdk/src/order/V2DutchOrder.test.ts @@ -245,6 +245,7 @@ describe("V2DutchOrder", () => { ); }); + //TODO: The tests below this line are not testing anything it("resolves when filler has exclusivity", () => { const exclusiveFiller = "0x0000000000000000000000000000000000000001"; const order = new CosignedV2DutchOrder( diff --git a/sdks/uniswapx-sdk/src/order/V2DutchOrder.ts b/sdks/uniswapx-sdk/src/order/V2DutchOrder.ts index 105047c2a..ac9be1b27 100644 --- a/sdks/uniswapx-sdk/src/order/V2DutchOrder.ts +++ b/sdks/uniswapx-sdk/src/order/V2DutchOrder.ts @@ -10,9 +10,12 @@ import { BigNumber, ethers } from "ethers"; import { getPermit2 } from "../utils"; import { ResolvedUniswapXOrder } from "../utils/OrderQuoter"; import { getDecayedAmount } from "../utils/dutchDecay"; +import { originalIfZero } from "../utils/order"; import { BlockOverrides, + CosignerData, + CosignerDataJSON, DutchInput, DutchInputJSON, DutchOutput, @@ -23,24 +26,6 @@ import { } from "./types"; import { CustomOrderValidation, parseValidation } from "./validation"; -export type CosignerData = { - decayStartTime: number; - decayEndTime: number; - exclusiveFiller: string; - exclusivityOverrideBps: BigNumber; - inputOverride: BigNumber; - outputOverrides: BigNumber[]; -}; - -export type CosignerDataJSON = { - decayStartTime: number; - decayEndTime: number; - exclusiveFiller: string; - exclusivityOverrideBps: number; - inputOverride: string; - outputOverrides: string[]; -}; - export type UnsignedV2DutchOrderInfo = OrderInfo & { cosigner: string; input: DutchInput; @@ -557,10 +542,6 @@ export class CosignedV2DutchOrder extends UnsignedV2DutchOrder { } } -function originalIfZero(value: BigNumber, original: BigNumber): BigNumber { - return value.isZero() ? original : value; -} - function parseSerializedOrder(serialized: string): CosignedV2DutchOrderInfo { const abiCoder = new ethers.utils.AbiCoder(); const decoded = abiCoder.decode(V2_DUTCH_ORDER_ABI, serialized); diff --git a/sdks/uniswapx-sdk/src/order/V3DutchOrder.test.ts b/sdks/uniswapx-sdk/src/order/V3DutchOrder.test.ts new file mode 100644 index 000000000..5791c7778 --- /dev/null +++ b/sdks/uniswapx-sdk/src/order/V3DutchOrder.test.ts @@ -0,0 +1,274 @@ +import { expect } from "chai"; +import { BigNumber, ethers } from "ethers"; + +import { getEndAmount } from "../utils/dutchBlockDecay"; + +import { CosignedV3DutchOrder, CosignedV3DutchOrderInfo, UnsignedV3DutchOrder, UnsignedV3DutchOrderInfoJSON } from "./V3DutchOrder"; + +const TIME= 1725379823; +const BLOCK_NUMBER = 20671221; +const RAW_AMOUNT = BigNumber.from("2121000"); +const INPUT_TOKEN = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; +const OUTPUT_TOKEN = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; +const CHAIN_ID = 1; + +const COSIGNER_DATA_WITH_OVERRIDES = { + decayStartBlock: BLOCK_NUMBER, + exclusiveFiller: ethers.constants.AddressZero, + exclusivityOverrideBps: BigNumber.from(0), + inputOverride: RAW_AMOUNT, + outputOverrides: [RAW_AMOUNT.mul(102).div(100)], +}; + +const COSIGNER_DATA_WITHOUT_OVERRIDES = { + decayStartBlock: BLOCK_NUMBER, + exclusiveFiller: ethers.constants.AddressZero, + exclusivityOverrideBps: BigNumber.from(0), + inputOverride: BigNumber.from(0), + outputOverrides: [BigNumber.from(0)], +}; + +describe("V3DutchOrder", () => { + const getFullOrderInfo = ( data: Partial): CosignedV3DutchOrderInfo => { + return Object.assign( + { + reactor: ethers.constants.AddressZero, + swapper: ethers.constants.AddressZero, + nonce: BigNumber.from(21), + deadline: TIME + 1000, + additionalValidationContract: ethers.constants.AddressZero, + additionalValidationData: "0x", + cosigner: ethers.constants.AddressZero, + startingBaseFee: BigNumber.from(0), + cosignerData: COSIGNER_DATA_WITH_OVERRIDES, + input: { + token: INPUT_TOKEN, + startAmount: RAW_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: RAW_AMOUNT, //we don't want input to change, we're testing for decaying output + adjustmentPerGweiBaseFee: BigNumber.from(0), + }, + outputs: [ + { + token: OUTPUT_TOKEN, + startAmount: RAW_AMOUNT, + curve: { + relativeBlocks: [1,2,3,4], + relativeAmounts: [BigInt(1), BigInt(2), BigInt(3), BigInt(4)], // 1e-18, 2e-18, 3e-18, 4e-18 + }, + recipient: ethers.constants.AddressZero, + minAmount: RAW_AMOUNT.sub(4), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }, + ], + cosignature: "0x", + }, + data + ); + }; + + const getFullOrderInfoWithoutOverrides: CosignedV3DutchOrderInfo = { + ...getFullOrderInfo({}), + cosignerData: COSIGNER_DATA_WITHOUT_OVERRIDES, + } + + it("Parses a serialized v3 order", () => { + const orderInfo = getFullOrderInfo({}); + const order = new CosignedV3DutchOrder(orderInfo, CHAIN_ID); + const seralized = order.serialize(); + const parsed = CosignedV3DutchOrder.parse(seralized, CHAIN_ID); + expect(parsed.info).to.deep.eq(orderInfo); + }); + + it("Parses a serialized v3 order with negative relativeAmounts", () => { + const orderInfo = getFullOrderInfo({ + outputs: [ + { + token: OUTPUT_TOKEN, + startAmount: RAW_AMOUNT, + curve: { + relativeBlocks: [1,2,3,4], + relativeAmounts: [BigInt(-1), BigInt(-2), BigInt(-3), BigInt(-4)], + }, + recipient: ethers.constants.AddressZero, + minAmount: BigNumber.from(0), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }, + ], + }); + const order = new CosignedV3DutchOrder(orderInfo, CHAIN_ID); + const seralized = order.serialize(); + const parsed = CosignedV3DutchOrder.parse(seralized, CHAIN_ID); + expect(parsed.info).to.deep.eq(orderInfo); + }); + + it("parses inner v3 order with no cosigner overrides, both input and output curves", () => { + const orderInfoJSON : UnsignedV3DutchOrderInfoJSON = { + ...getFullOrderInfo({}), + nonce: "21", + startingBaseFee: "0", + input: { + token: INPUT_TOKEN, + startAmount: "1000000", + curve: { + relativeBlocks: [1,2,3,4], + relativeAmounts: ["1", "2", "3", "4"], + }, + maxAmount: "1000001", + adjustmentPerGweiBaseFee: "0", + }, + outputs: [ + { + token: OUTPUT_TOKEN, + startAmount: "1000000", + curve: { + relativeBlocks: [1,2,3,4], + relativeAmounts: ["1", "2", "3", "4"], + }, + recipient: ethers.constants.AddressZero, + minAmount: "1000000", + adjustmentPerGweiBaseFee: "0", + }, + ], + }; + const order = UnsignedV3DutchOrder.fromJSON(orderInfoJSON, CHAIN_ID); + expect(order.info.input.startAmount.toString()).to.equal("1000000"); + expect(order.info.outputs[0].startAmount.toString()).to.eq("1000000"); + }); + + it("valid signature over inner order", async () => { + const fullOrderInfo = getFullOrderInfo({}); + const order = new UnsignedV3DutchOrder(fullOrderInfo, 1); + const wallet = ethers.Wallet.createRandom(); + + const { domain, types, values } = order.permitData(); + const signature = await wallet._signTypedData(domain, types, values); + expect(order.getSigner(signature)).equal(await wallet.getAddress()); + const fullOrder = CosignedV3DutchOrder.fromUnsignedOrder( + order, + fullOrderInfo.cosignerData, + fullOrderInfo.cosignature + ); + expect(fullOrder.getSigner(signature)).equal(await wallet.getAddress()); + }); + + it("validates cosignature over (hash || cosignerData)", async () => { + const wallet = ethers.Wallet.createRandom(); + const orderInfo = getFullOrderInfo({ + cosigner: await wallet.getAddress(), + }); + const order = new UnsignedV3DutchOrder(orderInfo, 1); + const fullOrderHash = order.cosignatureHash(orderInfo.cosignerData); + const cosignature = ethers.utils.joinSignature( + wallet._signingKey().signDigest(fullOrderHash) + ); + const signedOrder = CosignedV3DutchOrder.fromUnsignedOrder( + order, + COSIGNER_DATA_WITH_OVERRIDES, + cosignature + ); + + expect(signedOrder.recoverCosigner()).equal(await wallet.getAddress()); + }); + + describe("resolve DutchV3 orders", () => { + it("resolves before decayStartBlock", () => { + const order = new CosignedV3DutchOrder(getFullOrderInfo({}), CHAIN_ID); + const resolved = order.resolve({ + currentBlock: BLOCK_NUMBER - 1, //no decay yet + }); + expect(resolved.input.token).eq(order.info.input.token); + expect(resolved.input.amount).eq(order.info.cosignerData.inputOverride); + expect(resolved.outputs[0].token).eq(order.info.outputs[0].token); + expect(resolved.outputs[0].amount).eq( + order.info.cosignerData.outputOverrides[0] + ); + }); + + it("resolves with original value when overrides==0", () => { + const order = new CosignedV3DutchOrder( + getFullOrderInfo({ + cosignerData: COSIGNER_DATA_WITHOUT_OVERRIDES, + }), + CHAIN_ID + ); + const resolved = order.resolve({ + currentBlock: BLOCK_NUMBER - 1, //no decay yet + }); + expect(resolved.input.token).eq(order.info.input.token); + expect(resolved.input.amount).eq(order.info.input.startAmount); + expect(resolved.outputs[0].token).eq(order.info.outputs[0].token); + expect(resolved.outputs[0].amount).eq(order.info.outputs[0].startAmount); + }); + + it("resolves at decayStartBlock", () => { + const order = new CosignedV3DutchOrder(getFullOrderInfo({}), CHAIN_ID); + const resolved = order.resolve({ + currentBlock: BLOCK_NUMBER, + }); + expect(resolved.input.token).eq(order.info.input.token); + expect(resolved.input.amount).eq(order.info.cosignerData.inputOverride); + expect(resolved.outputs.length).eq(1); + expect(resolved.outputs[0].token).eq(order.info.outputs[0].token); + expect(resolved.outputs[0].amount).eq(order.info.cosignerData.outputOverrides[0]); + }); + + it("resolves at last decay block without overrides", () => { + const order = new CosignedV3DutchOrder(getFullOrderInfoWithoutOverrides, CHAIN_ID); + const relativeBlocks = order.info.outputs[0].curve.relativeBlocks; + const resolved = order.resolve({ + currentBlock: BLOCK_NUMBER + relativeBlocks[relativeBlocks.length - 1], + }); + expect(resolved.input.token).eq(order.info.input.token); + expect(resolved.outputs[0].token).eq(order.info.outputs[0].token); + const endAmount = getEndAmount({ + decayStartBlock: BLOCK_NUMBER, + startAmount: order.info.outputs[0].startAmount, + relativeBlocks: order.info.outputs[0].curve.relativeBlocks, + relativeAmounts: order.info.outputs[0].curve.relativeAmounts, + }); + expect(resolved.outputs[0].amount.toNumber()).eq(endAmount.toNumber()); + }); + + it("resolves after last decay without overrides", () => { + const order = new CosignedV3DutchOrder(getFullOrderInfoWithoutOverrides, CHAIN_ID); + const resolved = order.resolve({ + currentBlock: BLOCK_NUMBER + 42, + }); + expect(resolved.input.token).eq(order.info.input.token); + expect(resolved.outputs[0].token).eq(order.info.outputs[0].token); + const endAmount = getEndAmount({ + decayStartBlock: BLOCK_NUMBER, + startAmount: order.info.outputs[0].startAmount, + relativeBlocks: order.info.outputs[0].curve.relativeBlocks, + relativeAmounts: order.info.outputs[0].curve.relativeAmounts, + }); + expect(resolved.outputs[0].amount.toNumber()).eq(endAmount.toNumber()); //deep eq on bignumber failed + }); + //TODO: resolves for overrides + it("resolves when filler has exclusivity: Before Decay Start", () => { + const exclusiveFiller = ethers.Wallet.createRandom().address; + const order = new CosignedV3DutchOrder( + getFullOrderInfo({ + cosignerData: { + ...COSIGNER_DATA_WITH_OVERRIDES, + exclusiveFiller, + }, + }), + CHAIN_ID + ); + const resolved = order.resolve({ + currentBlock: BLOCK_NUMBER - 1, + filler: exclusiveFiller, + }); + expect(resolved.input.token).eq(order.info.input.token); + expect(resolved.input.amount).eq(order.info.cosignerData.inputOverride); + expect(resolved.outputs.length).eq(1); + expect(resolved.outputs[0].token).eq(order.info.outputs[0].token); + expect(resolved.outputs[0].amount).eq(order.info.cosignerData.outputOverrides[0]); + }); + }); +}); diff --git a/sdks/uniswapx-sdk/src/order/V3DutchOrder.ts b/sdks/uniswapx-sdk/src/order/V3DutchOrder.ts new file mode 100644 index 000000000..606e41b47 --- /dev/null +++ b/sdks/uniswapx-sdk/src/order/V3DutchOrder.ts @@ -0,0 +1,732 @@ +import { SignatureLike } from "@ethersproject/bytes"; +import { + PermitTransferFrom, + PermitTransferFromData, + SignatureTransfer, + Witness, +} from "@uniswap/permit2-sdk"; +import { BigNumber, ethers } from "ethers"; + +import { getPermit2, ResolvedUniswapXOrder } from "../utils"; +import { getBlockDecayedAmount } from "../utils/dutchBlockDecay"; +import { originalIfZero } from "../utils/order"; + +import { + BlockOverrides, + CosignerData, + CosignerDataJSON, + EncodedV3DutchInput, + EncodedV3DutchOutput, + OffChainOrder, + OrderInfo, + V3DutchInput, + V3DutchInputJSON, + V3DutchOutput, + V3DutchOutputJSON, + V3OrderResolutionOptions, +} from "./types"; + +export type V3CosignerDataJSON = Omit< + CosignerDataJSON, + "decayStartTime" | "decayEndTime" +> & { + decayStartBlock: number; +}; + +export type V3CosignerData = Omit< + CosignerData, + "decayStartTime" | "decayEndTime" +> & { + decayStartBlock: number; +}; + +export type UnsignedV3DutchOrderInfoJSON = Omit< + UnsignedV3DutchOrderInfo, + "nonce" | "startingBaseFee" | "input" | "outputs" | "cosignerData" +> & { + nonce: string; + startingBaseFee: string; + input: V3DutchInputJSON; + outputs: V3DutchOutputJSON[]; +}; + +export type UnsignedV3DutchOrderInfo = OrderInfo & { + cosigner: string; + startingBaseFee: BigNumber; + input: V3DutchInput; //different from V2DutchOrder + outputs: V3DutchOutput[]; +}; + +export type CosignedV3DutchOrderInfoJSON = UnsignedV3DutchOrderInfoJSON & { + cosignerData: V3CosignerDataJSON; + cosignature: string; +}; + +export type CosignedV3DutchOrderInfo = UnsignedV3DutchOrderInfo & { + cosignerData: V3CosignerData; + cosignature: string; +}; + +type V3WitnessInfo = { + info: OrderInfo; + cosigner: string; + startingBaseFee: BigNumber; + baseInput: EncodedV3DutchInput; + baseOutputs: EncodedV3DutchOutput[]; +}; + +const COSIGNER_DATA_TUPLE_ABI = + "tuple(uint256,address,uint256,uint256,uint256[])"; + +export const V3_DUTCH_ORDER_TYPES = { + V3DutchOrder: [ + { name: "info", type: "OrderInfo" }, + { name: "cosigner", type: "address" }, + { name: "startingBaseFee", type: "uint256" }, + { name: "baseInput", type: "V3DutchInput" }, + { name: "baseOutputs", type: "V3DutchOutput[]" }, + ], + OrderInfo: [ + { name: "reactor", type: "address" }, + { name: "swapper", type: "address" }, + { name: "nonce", type: "uint256" }, + { name: "deadline", type: "uint256" }, + { name: "additionalValidationContract", type: "address" }, + { name: "additionalValidationData", type: "bytes" }, + ], + V3DutchInput: [ + { name: "token", type: "address" }, + { name: "startAmount", type: "uint256" }, + { name: "curve", type: "NonlinearDutchDecay" }, + { name: "maxAmount", type: "uint256" }, + { name: "adjustmentPerGweiBaseFee", type: "uint256" }, + ], + V3DutchOutput: [ + { name: "token", type: "address" }, + { name: "startAmount", type: "uint256" }, + { name: "curve", type: "NonlinearDutchDecay" }, + { name: "recipient", type: "address" }, + { name: "minAmount", type: "uint256" }, + { name: "adjustmentPerGweiBaseFee", type: "uint256" }, + ], + NonlinearDutchDecay: [ + { name: "relativeBlocks", type: "uint256" }, + { name: "relativeAmounts", type: "int256[]" }, + ], +}; + +const V3_DUTCH_ORDER_ABI = [ + "tuple(" + + [ + "tuple(address,address,uint256,uint256,address,bytes)", // OrderInfo + "address", // Cosigner + "uint256", //startingBaseFee + "tuple(address,uint256,tuple(uint256,int256[]),uint256,uint256)", // V3DutchInput + "tuple(address,uint256,tuple(uint256,int256[]),address,uint256,uint256)[]", // V3DutchOutput + COSIGNER_DATA_TUPLE_ABI, + "bytes", // Cosignature + ].join(",") + + ")", +]; + +export class UnsignedV3DutchOrder implements OffChainOrder { + public permit2Address: string; + + constructor( + public readonly info: UnsignedV3DutchOrderInfo, + public readonly chainId: number, + _permit2Address?: string + ) { + this.permit2Address = getPermit2(chainId, _permit2Address); + } + + static fromJSON( + json: UnsignedV3DutchOrderInfoJSON, + chainId: number, + _permit2Address?: string + ): UnsignedV3DutchOrder { + return new UnsignedV3DutchOrder( + { + ...json, + nonce: BigNumber.from(json.nonce), + startingBaseFee: BigNumber.from(json.startingBaseFee), + input: { + ...json.input, + startAmount: BigNumber.from(json.input.startAmount), + curve: { + relativeBlocks: json.input.curve.relativeBlocks, + relativeAmounts: json.input.curve.relativeAmounts.map((amount) => + BigInt(amount) + ), + }, + maxAmount: BigNumber.from(json.input.maxAmount), + adjustmentPerGweiBaseFee: BigNumber.from( + json.input.adjustmentPerGweiBaseFee + ), + }, + outputs: json.outputs.map((output) => ({ + ...output, + startAmount: BigNumber.from(output.startAmount), + curve: { + relativeBlocks: output.curve.relativeBlocks, + relativeAmounts: output.curve.relativeAmounts.map((amount) => + BigInt(amount) + ), + }, + minAmount: BigNumber.from(output.minAmount), + adjustmentPerGweiBaseFee: BigNumber.from( + output.adjustmentPerGweiBaseFee + ), + })), + }, + chainId, + _permit2Address + ); + } + + /** + * @inheritdoc order + */ + get blockOverrides(): BlockOverrides { + return undefined; + } + + /** + * @inheritdoc order + */ + serialize(): string { + const encodedRelativeBlocks = encodeRelativeBlocks( + this.info.input.curve.relativeBlocks + ); + const abiCoder = new ethers.utils.AbiCoder(); + return abiCoder.encode(V3_DUTCH_ORDER_ABI, [ + [ + [ + this.info.reactor, + this.info.swapper, + this.info.nonce, + this.info.deadline, + this.info.additionalValidationContract, + this.info.additionalValidationData, + ], + this.info.cosigner, + this.info.startingBaseFee, + [ + this.info.input.token, + this.info.input.startAmount, + [encodedRelativeBlocks, this.info.input.curve.relativeAmounts], + this.info.input.maxAmount, + this.info.input.adjustmentPerGweiBaseFee, + ], + this.info.outputs.map((output) => [ + output.token, + output.startAmount, + [encodedRelativeBlocks, output.curve.relativeAmounts], + output.recipient, + output.minAmount, + output.adjustmentPerGweiBaseFee, + ]), + [0, ethers.constants.AddressZero, 0, 0, [0]], + "0x", + ], + ]); + } + + /** + * @inheritdoc order + */ + toJSON(): UnsignedV3DutchOrderInfoJSON & { + permit2Address: string; + chainId: number; + } { + return { + reactor: this.info.reactor, + swapper: this.info.swapper, + nonce: this.info.nonce.toString(), + deadline: this.info.deadline, + additionalValidationContract: this.info.additionalValidationContract, + additionalValidationData: this.info.additionalValidationData, + cosigner: this.info.cosigner, + startingBaseFee: this.info.startingBaseFee.toString(), + input: { + token: this.info.input.token, + startAmount: this.info.input.startAmount.toString(), + curve: { + relativeBlocks: this.info.input.curve.relativeBlocks, + relativeAmounts: this.info.input.curve.relativeAmounts.map((amount) => + amount.toString() + ), + }, + maxAmount: this.info.input.maxAmount.toString(), + adjustmentPerGweiBaseFee: + this.info.input.adjustmentPerGweiBaseFee.toString(), + }, + outputs: this.info.outputs.map((output) => ({ + token: output.token, + startAmount: output.startAmount.toString(), + curve: { + relativeBlocks: output.curve.relativeBlocks, + relativeAmounts: output.curve.relativeAmounts.map((amount) => + amount.toString() + ), + }, + recipient: output.recipient, + minAmount: output.minAmount.toString(), + adjustmentPerGweiBaseFee: output.adjustmentPerGweiBaseFee.toString(), + })), + chainId: this.chainId, + permit2Address: this.permit2Address, + }; + } + + permitData(): PermitTransferFromData { + return SignatureTransfer.getPermitData( + this.toPermit(), + this.permit2Address, + this.chainId, + this.witness() + ) as PermitTransferFromData; + } + + private toPermit(): PermitTransferFrom { + return { + permitted: { + token: this.info.input.token, + amount: this.info.input.maxAmount, + }, + spender: this.info.reactor, + nonce: this.info.nonce, + deadline: this.info.deadline, + }; + } + + private witnessInfo(): V3WitnessInfo { + return { + info: { + reactor: this.info.reactor, + swapper: this.info.swapper, + nonce: this.info.nonce, + deadline: this.info.deadline, + additionalValidationContract: this.info.additionalValidationContract, + additionalValidationData: this.info.additionalValidationData, + }, + cosigner: this.info.cosigner, + startingBaseFee: this.info.startingBaseFee, + baseInput: { + token: this.info.input.token, + startAmount: this.info.input.startAmount, + curve: { + relativeBlocks: encodeRelativeBlocks(this.info.input.curve.relativeBlocks), + relativeAmounts: this.info.input.curve.relativeAmounts, + }, + maxAmount: this.info.input.maxAmount, + adjustmentPerGweiBaseFee: this.info.input.adjustmentPerGweiBaseFee, + }, + baseOutputs: this.info.outputs.map((output) => ({ + token: output.token, + startAmount: output.startAmount, + curve: { + relativeBlocks: encodeRelativeBlocks(output.curve.relativeBlocks), + relativeAmounts: output.curve.relativeAmounts, + }, + recipient: output.recipient, + minAmount: output.minAmount, + adjustmentPerGweiBaseFee: output.adjustmentPerGweiBaseFee, + })), + }; + } + + private witness(): Witness { + return { + witness: this.witnessInfo(), + witnessTypeName: "V3DutchOrder", + witnessType: V3_DUTCH_ORDER_TYPES, + }; + } + + getSigner(signature: SignatureLike): string { + return ethers.utils.computeAddress( + ethers.utils.recoverPublicKey( + SignatureTransfer.hash( + this.toPermit(), + this.permit2Address, + this.chainId, + this.witness() + ), + signature + ) + ); + } + + hash(): string { + const witnessInfo = this.witnessInfo(); + return ethers.utils._TypedDataEncoder + .from(V3_DUTCH_ORDER_TYPES) + .hash(witnessInfo); + } + + cosignatureHash(cosignerData: V3CosignerData): string { + const abiCoder = new ethers.utils.AbiCoder(); + return ethers.utils.solidityKeccak256( + ["bytes32", "bytes"], + [ + this.hash(), + abiCoder.encode( + [COSIGNER_DATA_TUPLE_ABI], + [ + [ + cosignerData.decayStartBlock, + cosignerData.exclusiveFiller, + cosignerData.exclusivityOverrideBps, + cosignerData.inputOverride, + cosignerData.outputOverrides, + ], + ] + ), + ] + ); + } + + static parse( + encoded: string, + chainId: number, + permit2?: string + ): UnsignedV3DutchOrder { + return new UnsignedV3DutchOrder( + parseSerializedOrder(encoded), + chainId, + permit2 + ); + } +} + +export class CosignedV3DutchOrder extends UnsignedV3DutchOrder { + static fromUnsignedOrder( + order: UnsignedV3DutchOrder, + cosignerData: V3CosignerData, + cosignature: string + ): CosignedV3DutchOrder { + return new CosignedV3DutchOrder( + { + ...order.info, + cosignerData, + cosignature, + }, + order.chainId, + order.permit2Address + ); + } + + static fromJSON( + json: CosignedV3DutchOrderInfoJSON, + chainId: number, + _permit2Address?: string + ): CosignedV3DutchOrder { + return new CosignedV3DutchOrder( + { + ...json, + nonce: BigNumber.from(json.nonce), + startingBaseFee: BigNumber.from(json.startingBaseFee), + input: { + token: json.input.token, + startAmount: BigNumber.from(json.input.startAmount), + curve: { + relativeBlocks: json.input.curve.relativeBlocks, + relativeAmounts: json.input.curve.relativeAmounts.map((amount) => + BigInt(amount) + ), + }, + maxAmount: BigNumber.from(json.input.maxAmount), + adjustmentPerGweiBaseFee: BigNumber.from( + json.input.adjustmentPerGweiBaseFee + ), + }, + outputs: json.outputs.map((output) => ({ + token: output.token, + startAmount: BigNumber.from(output.startAmount), + curve: { + relativeBlocks: output.curve.relativeBlocks, + relativeAmounts: output.curve.relativeAmounts.map((amount) => + BigInt(amount) + ), + }, + recipient: output.recipient, + minAmount: BigNumber.from(output.minAmount), + adjustmentPerGweiBaseFee: BigNumber.from( + output.adjustmentPerGweiBaseFee + ), + })), + cosignerData: { + decayStartBlock: json.cosignerData.decayStartBlock, + exclusiveFiller: json.cosignerData.exclusiveFiller, + exclusivityOverrideBps: BigNumber.from( + json.cosignerData.exclusivityOverrideBps + ), + inputOverride: BigNumber.from(json.cosignerData.inputOverride), + outputOverrides: json.cosignerData.outputOverrides.map( + BigNumber.from + ), + }, + cosignature: json.cosignature, + }, + chainId, + _permit2Address + ); + } + + constructor( + public readonly info: CosignedV3DutchOrderInfo, + public readonly chainId: number, + _permit2Address?: string + ) { + super(info, chainId, _permit2Address); + } + + /** + * @inheritdoc order + */ + toJSON(): CosignedV3DutchOrderInfoJSON & { + permit2Address: string; + chainId: number; + } { + return { + ...super.toJSON(), + cosignerData: { + decayStartBlock: this.info.cosignerData.decayStartBlock, + exclusiveFiller: this.info.cosignerData.exclusiveFiller, + exclusivityOverrideBps: + this.info.cosignerData.exclusivityOverrideBps.toNumber(), + inputOverride: this.info.cosignerData.inputOverride.toString(), + outputOverrides: this.info.cosignerData.outputOverrides.map( + (override) => override.toString() + ), + }, + cosignature: this.info.cosignature, + }; + } + + static parse( + encoded: string, + chainId: number, + permit2?: string + ): CosignedV3DutchOrder { + return new CosignedV3DutchOrder( + parseSerializedOrder(encoded), + chainId, + permit2 + ); + } + + serialize(): string { + const encodedInputRelativeBlocks = encodeRelativeBlocks( + this.info.input.curve.relativeBlocks + ); + const abiCoder = new ethers.utils.AbiCoder(); + return abiCoder.encode(V3_DUTCH_ORDER_ABI, [ + [ + [ + this.info.reactor, + this.info.swapper, + this.info.nonce, + this.info.deadline, + this.info.additionalValidationContract, + this.info.additionalValidationData, + ], + this.info.cosigner, + this.info.startingBaseFee, + [ + this.info.input.token, + this.info.input.startAmount, + [encodedInputRelativeBlocks, this.info.input.curve.relativeAmounts], + this.info.input.maxAmount, + this.info.input.adjustmentPerGweiBaseFee, + ], + this.info.outputs.map((output) => [ + output.token, + output.startAmount, + [ + encodeRelativeBlocks(output.curve.relativeBlocks), + output.curve.relativeAmounts, + ], + output.recipient, + output.minAmount, + output.adjustmentPerGweiBaseFee, + ]), + [ + this.info.cosignerData.decayStartBlock, + this.info.cosignerData.exclusiveFiller, + this.info.cosignerData.exclusivityOverrideBps, + this.info.cosignerData.inputOverride.toString(), + this.info.cosignerData.outputOverrides.map((override) => + override.toString() + ), + ], + this.info.cosignature, + ], + ]); + } + + recoverCosigner(): string { + const messageHash = this.cosignatureHash(this.info.cosignerData); + const signature = this.info.cosignature; + return ethers.utils.recoverAddress(messageHash, signature); + } + + resolve(options: V3OrderResolutionOptions): ResolvedUniswapXOrder { + return { + input: { + token: this.info.input.token, + amount: getBlockDecayedAmount( + { + decayStartBlock: this.info.cosignerData.decayStartBlock, + startAmount: originalIfZero( + this.info.cosignerData.inputOverride, + this.info.input.startAmount + ), + relativeBlocks: this.info.input.curve.relativeBlocks, + relativeAmounts: this.info.input.curve.relativeAmounts, + }, + options.currentBlock + ), + }, + outputs: this.info.outputs.map((output, idx) => { + return { + token: output.token, + amount: getBlockDecayedAmount( + { + decayStartBlock: this.info.cosignerData.decayStartBlock, + startAmount: originalIfZero( + this.info.cosignerData.outputOverrides[idx], + output.startAmount + ), + relativeBlocks: output.curve.relativeBlocks, + relativeAmounts: output.curve.relativeAmounts, + }, + options.currentBlock + ), + }; + }), + }; + } +} + +function parseSerializedOrder(serialized: string): CosignedV3DutchOrderInfo { + const abiCoder = new ethers.utils.AbiCoder(); + const decoded = abiCoder.decode(V3_DUTCH_ORDER_ABI, serialized); + const [ + [ + [ + reactor, + swapper, + nonce, + deadline, + additionalValidationContract, + additionalValidationData, + ], + cosigner, + startingBaseFee, + [ + token, + startAmount, + [inputRelativeBlocks, relativeAmounts], + maxAmount, + adjustmentPerGweiBaseFee, + ], + outputs, + [ + decayStartBlock, + exclusiveFiller, + exclusivityOverrideBps, + inputOverride, + outputOverrides, + ], + cosignature, + ], + ] = decoded; + + return { + reactor, + swapper, + nonce, + deadline: deadline.toNumber(), + additionalValidationContract, + additionalValidationData, + cosigner, + startingBaseFee, + input: { + token, + startAmount, + curve: { + relativeBlocks: decodeRelativeBlocks( + inputRelativeBlocks, + relativeAmounts.length + ), + relativeAmounts: relativeAmounts.map((amount: BigNumber) => + amount.toBigInt() + ), + }, + maxAmount, + adjustmentPerGweiBaseFee, + }, + outputs: outputs.map( + ([ + token, + startAmount, + [outputRelativeBlocks, relativeAmounts], + recipient, + minAmount, + adjustmentPerGweiBaseFee, + ]: [ + string, + number, + [BigNumber, BigNumber[]], //abiDecode automatically converts to BigNumber + string, + BigNumber, + BigNumber + ]) => ({ + token, + startAmount, + curve: { + relativeBlocks: decodeRelativeBlocks( + outputRelativeBlocks, + relativeAmounts.length + ), + relativeAmounts: relativeAmounts.map((amount: BigNumber) => + amount.toBigInt() + ), + }, + recipient, + minAmount, + adjustmentPerGweiBaseFee, + }) + ), + cosignerData: { + decayStartBlock: decayStartBlock.toNumber(), + exclusiveFiller, + exclusivityOverrideBps: exclusivityOverrideBps, + inputOverride: inputOverride, + outputOverrides, + }, + cosignature, + }; +} + +export function encodeRelativeBlocks(relativeBlocks: number[]): BigNumber { + let packedData = BigNumber.from(0); + for (let i = 0; i < relativeBlocks.length; i++) { + packedData = packedData.or(BigNumber.from(relativeBlocks[i]).shl(i * 16)); + } + return packedData; +} + +function decodeRelativeBlocks( + packedData: BigNumber, + relativeAmountsLength: number +): number[] { + const relativeBlocks: number[] = []; + for (let i = 0; i < relativeAmountsLength; i++) { + const block = packedData.shr(i * 16).toNumber() & 0xffff; + relativeBlocks.push(block); + } + return relativeBlocks; +} diff --git a/sdks/uniswapx-sdk/src/order/index.ts b/sdks/uniswapx-sdk/src/order/index.ts index 310ae5220..899c53a3b 100644 --- a/sdks/uniswapx-sdk/src/order/index.ts +++ b/sdks/uniswapx-sdk/src/order/index.ts @@ -2,6 +2,7 @@ import { DutchOrder } from "./DutchOrder"; import { CosignedPriorityOrder, UnsignedPriorityOrder } from "./PriorityOrder"; import { RelayOrder } from "./RelayOrder"; import { CosignedV2DutchOrder, UnsignedV2DutchOrder } from "./V2DutchOrder"; +import { CosignedV3DutchOrder, UnsignedV3DutchOrder } from "./V3DutchOrder"; export * from "./DutchOrder"; export * from "./PriorityOrder"; @@ -9,12 +10,15 @@ export * from "./RelayOrder"; export * from "./types"; export * from "./validation"; export * from "./V2DutchOrder"; +// TODO: To make V3 exports cleaner, export here but resolve ambiguous names vs V2 export type UniswapXOrder = | DutchOrder | UnsignedV2DutchOrder | CosignedV2DutchOrder + | UnsignedV3DutchOrder + | CosignedV3DutchOrder | UnsignedPriorityOrder | CosignedPriorityOrder; -export type Order = UniswapXOrder | RelayOrder; +export type Order = UniswapXOrder | RelayOrder; \ No newline at end of file diff --git a/sdks/uniswapx-sdk/src/order/types.ts b/sdks/uniswapx-sdk/src/order/types.ts index 7e497ea5b..160f7861a 100644 --- a/sdks/uniswapx-sdk/src/order/types.ts +++ b/sdks/uniswapx-sdk/src/order/types.ts @@ -70,6 +70,11 @@ export type PriorityOrderResolutionOptions = { currentBlock?: BigNumber; }; +export type V3OrderResolutionOptions = { + currentBlock: number; + filler?: string; +} + export type DutchOutput = { readonly token: string; readonly startAmount: BigNumber; @@ -93,6 +98,24 @@ export type DutchInputJSON = Omit & { endAmount: string; }; +export type CosignerData = { + decayStartTime: number; + decayEndTime: number; + exclusiveFiller: string; + exclusivityOverrideBps: BigNumber; + inputOverride: BigNumber; + outputOverrides: BigNumber[]; +}; + +export type CosignerDataJSON = { + decayStartTime: number; + decayEndTime: number; + exclusiveFiller: string; + exclusivityOverrideBps: number; + inputOverride: string; + outputOverrides: string[]; +}; + export type PriorityInput = { readonly token: string; readonly amount: BigNumber; @@ -114,3 +137,57 @@ export type PriorityInputJSON = Omit< export type PriorityOutputJSON = PriorityInputJSON & { recipient: string; }; + +export type V3DutchInput = { + readonly token: string; + readonly startAmount: BigNumber; + readonly curve: NonlinearDutchDecay; + readonly maxAmount: BigNumber; + readonly adjustmentPerGweiBaseFee: BigNumber; +}; + +export type V3DutchInputJSON = Omit & { + startAmount: string; + curve: NonlinearDutchDecayJSON; + maxAmount: string; + adjustmentPerGweiBaseFee: string; +}; + +export type NonlinearDutchDecay = { + relativeBlocks: number[]; + relativeAmounts: bigint[]; // Cannot be BigNumber because could be negative +}; + +export type EncodedNonlinearDutchDecay = { + relativeBlocks: BigNumber; + relativeAmounts: bigint[]; +}; + +export type EncodedV3DutchInput = Omit & { + curve: EncodedNonlinearDutchDecay; +}; + +export type EncodedV3DutchOutput = Omit & { + curve: EncodedNonlinearDutchDecay; +}; + +export type NonlinearDutchDecayJSON = { + relativeBlocks: number[]; + relativeAmounts: string[]; +}; + +export type V3DutchOutput = { + readonly token: string; + readonly startAmount: BigNumber; + readonly curve: NonlinearDutchDecay; + readonly recipient: string; + readonly minAmount: BigNumber; + readonly adjustmentPerGweiBaseFee: BigNumber; +}; + +export type V3DutchOutputJSON = Omit & { + startAmount: string; + curve: NonlinearDutchDecayJSON; + minAmount: string; + adjustmentPerGweiBaseFee: string; +}; \ No newline at end of file diff --git a/sdks/uniswapx-sdk/src/trade/V3DutchOrderTrade.test.ts b/sdks/uniswapx-sdk/src/trade/V3DutchOrderTrade.test.ts new file mode 100644 index 000000000..832b76549 --- /dev/null +++ b/sdks/uniswapx-sdk/src/trade/V3DutchOrderTrade.test.ts @@ -0,0 +1,214 @@ +import { Currency, Ether, Token, TradeType } from "@uniswap/sdk-core"; +import { BigNumber, constants, ethers } from "ethers"; + +import { UnsignedV3DutchOrderInfo } from "../order/V3DutchOrder"; + +import { V3DutchOrderTrade } from "./V3DutchOrderTrade"; +import { NativeAssets } from "./utils"; + +const USDC = new Token( + 1, + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + 6, + "USDC" +); +const DAI = new Token( + 1, + "0x6B175474E89094C44Da98b954EedeAC495271d0F", + 18, + "DAI" +); + +describe("V3DutchOrderTrade", () => { + const NON_FEE_OUTPUT_AMOUNT = BigNumber.from("1000000000000000000"); + const NON_FEE_MINIMUM_AMOUNT_OUT = BigNumber.from("900000000000000000"); + + const orderInfo: UnsignedV3DutchOrderInfo = { + deadline: Math.floor(new Date().getTime() / 1000) + 1000, + reactor: "0x0000000000000000000000000000000000000000", + swapper: "0x0000000000000000000000000000000000000000", + nonce: BigNumber.from(10), + cosigner: "0x0000000000000000000000000000000000000000", + startingBaseFee: BigNumber.from(0), + additionalValidationContract: ethers.constants.AddressZero, + additionalValidationData: "0x", + input: { + token: USDC.address, + startAmount: BigNumber.from(1000), + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + maxAmount: BigNumber.from(1000), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }, + outputs: [ + { + token: DAI.address, + startAmount: NON_FEE_OUTPUT_AMOUNT, + curve: { + relativeBlocks: [21], + relativeAmounts: [BigInt("100000000000000000")], + }, + recipient: "0x0000000000000000000000000000000000000000", + minAmount: NON_FEE_MINIMUM_AMOUNT_OUT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }, + { + token: DAI.address, + startAmount: BigNumber.from("1000"), + curve: { + relativeBlocks: [21], + relativeAmounts: [BigInt("100")], + }, + recipient: "0x0000000000000000000000000000000000000000", + minAmount: BigNumber.from("900"), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }, + ], + }; + + const trade = new V3DutchOrderTrade({ + currencyIn: USDC, + currenciesOut: [DAI], + orderInfo, + tradeType: TradeType.EXACT_INPUT, + }); + + describe("Exact input", () => { + it("returns the right input amount for an exact-in trade", () => { + expect(trade.inputAmount.quotient.toString()).toEqual( + orderInfo.input.startAmount.toString() + ); + }); + + it("returns the correct non-fee output amount", () => { + expect(trade.outputAmount.quotient.toString()).toEqual( + NON_FEE_OUTPUT_AMOUNT.toString() + ); + }); + + it("returns the correct minimum amount out", () => { + expect(trade.minimumAmountOut().quotient.toString()).toEqual( + NON_FEE_MINIMUM_AMOUNT_OUT.toString() + ); + }); + }); + + describe("Exact output", () => { + const outOrderInfo: UnsignedV3DutchOrderInfo = { + deadline: Math.floor(new Date().getTime() / 1000) + 1000, + reactor: "0x0000000000000000000000000000000000000000", + swapper: "0x0000000000000000000000000000000000000000", + nonce: BigNumber.from(10), + cosigner: "0x0000000000000000000000000000000000000000", + startingBaseFee: BigNumber.from(0), + additionalValidationContract: ethers.constants.AddressZero, + additionalValidationData: "0x", + input: { + token: USDC.address, + startAmount: BigNumber.from(1000), + curve: { + relativeBlocks: [10], + relativeAmounts: [BigInt(-100)], + }, + maxAmount: BigNumber.from(1100), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }, + outputs: [ + { + token: DAI.address, + startAmount: NON_FEE_OUTPUT_AMOUNT, + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + recipient: "0x0000000000000000000000000000000000000000", + minAmount: NON_FEE_OUTPUT_AMOUNT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }, + { + token: DAI.address, + startAmount: BigNumber.from("1000"), + curve: { + relativeBlocks: [], + relativeAmounts: [], + }, + recipient: "0x0000000000000000000000000000000000000000", + minAmount: BigNumber.from("1000"), + adjustmentPerGweiBaseFee: BigNumber.from(0), + }, + ], + }; + const trade = new V3DutchOrderTrade({ + currencyIn: USDC, + currenciesOut: [DAI], + orderInfo: outOrderInfo, + tradeType: TradeType.EXACT_OUTPUT, + }); + + it("returns the correct maximum amount in", () => { + expect(trade.maximumAmountIn().quotient.toString()).toEqual( + outOrderInfo.input.maxAmount.toString() + ); + }); + }); + + describe("Qualitative tests", () => { + it("works for native output trades", () => { + const ethOutputOrderInfo = { + ...orderInfo, + outputs: [ + { + token: NativeAssets.ETH, + startAmount: NON_FEE_OUTPUT_AMOUNT, + curve: { + relativeBlocks: [21], + relativeAmounts: [BigInt("100000000000000000")], + }, + recipient: "0x0000000000000000000000000000000000000000", + minAmount: NON_FEE_MINIMUM_AMOUNT_OUT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }, + ], + }; + const ethOutputTrade = new V3DutchOrderTrade( + { + currencyIn: USDC, + currenciesOut: [Ether.onChain(1)], + orderInfo: ethOutputOrderInfo, + tradeType: TradeType.EXACT_INPUT, + } + ); + expect(ethOutputTrade.outputAmount.currency).toEqual(Ether.onChain(1)); + }); + + it("works for native output trades where order info has 0 address", () => { + const ethOutputOrderInfo = { + ...orderInfo, + outputs: [ + { + token: constants.AddressZero, + startAmount: NON_FEE_OUTPUT_AMOUNT, + curve: { + relativeBlocks: [21], + relativeAmounts: [BigInt("100000000000000000")], + }, + recipient: "0x0000000000000000000000000000000000000000", + minAmount: NON_FEE_MINIMUM_AMOUNT_OUT, + adjustmentPerGweiBaseFee: BigNumber.from(0), + }, + ], + }; + const ethOutputTrade = new V3DutchOrderTrade( + { + currencyIn: USDC, + currenciesOut: [Ether.onChain(1)], + orderInfo: ethOutputOrderInfo, + tradeType: TradeType.EXACT_INPUT, + } + ); + expect(ethOutputTrade.outputAmount.currency).toEqual(Ether.onChain(1)); + }); + }); +}); \ No newline at end of file diff --git a/sdks/uniswapx-sdk/src/trade/V3DutchOrderTrade.ts b/sdks/uniswapx-sdk/src/trade/V3DutchOrderTrade.ts new file mode 100644 index 000000000..74789f18a --- /dev/null +++ b/sdks/uniswapx-sdk/src/trade/V3DutchOrderTrade.ts @@ -0,0 +1,126 @@ +import { Currency, CurrencyAmount, Price, TradeType } from "@uniswap/sdk-core"; +import { BigNumber } from "ethers"; + +import { V3DutchOutput } from "../order"; +import { UnsignedV3DutchOrder, UnsignedV3DutchOrderInfo } from "../order/V3DutchOrder"; + +import { areCurrenciesEqual } from "./utils"; + +export class V3DutchOrderTrade< + TInput extends Currency, + TOutput extends Currency, + TTradeType extends TradeType +> { + public readonly tradeType: TTradeType + public readonly order: UnsignedV3DutchOrder + + private _inputAmount: CurrencyAmount | undefined + private _outputAmounts: CurrencyAmount[] | undefined + + private _currencyIn: TInput + private _currenciesOut: TOutput[] + + public constructor({ + currencyIn, + currenciesOut, + orderInfo, + tradeType, + }: { + currencyIn: TInput + currenciesOut: TOutput[] + orderInfo: UnsignedV3DutchOrderInfo + tradeType: TTradeType + }) { + this._currencyIn = currencyIn + this._currenciesOut = currenciesOut + this.tradeType = tradeType + + // Assuming not cross-chain + this.order = new UnsignedV3DutchOrder(orderInfo, currencyIn.chainId) + } + + public get inputAmount(): CurrencyAmount { + if (this._inputAmount) return this._inputAmount + + const amount = CurrencyAmount.fromRawAmount( + this._currencyIn, + this.order.info.input.startAmount.toString() + ) + this._inputAmount = amount + return amount + } + + public get outputAmounts(): CurrencyAmount[] { + if (this._outputAmounts) return this._outputAmounts + + const amounts = this.order.info.outputs.map((output) => { + // Assuming all outputs on the same chain + const currencyOut = this._currenciesOut.find((currency) => + areCurrenciesEqual(currency, output.token, currency.chainId) + ) + + if (!currencyOut) { + throw new Error("Currency out not found") + } + + return CurrencyAmount.fromRawAmount(currencyOut, output.startAmount.toString()) + }) + + this._outputAmounts = amounts + return amounts + } + + // Same assumption as V2 that there is only one non-fee output at a time, and it exists at index 0 + public get outputAmount(): CurrencyAmount { + return this.outputAmounts[0]; + } + + public minimumAmountOut(): CurrencyAmount { + const nonFeeOutput: V3DutchOutput = this.order.info.outputs[0]; + const relativeAmounts: bigint[] = nonFeeOutput.curve.relativeAmounts; + const startAmount: BigNumber = nonFeeOutput.startAmount; + // Get the maximum of the relative amounts + const maxRelativeAmount = relativeAmounts.reduce((max, amount) => amount > max ? amount : max, BigInt(0)); + // minimum is the start - the max of the relative amounts + const minOut = startAmount.sub(maxRelativeAmount.toString()); + return CurrencyAmount.fromRawAmount(this.outputAmount.currency, minOut.toString()); + } + + public maximumAmountIn(): CurrencyAmount { + const maxAmountIn = this.order.info.input.maxAmount; + return CurrencyAmount.fromRawAmount( + this._currencyIn, + maxAmountIn.toString() + ); + } + + private _executionPrice: Price | undefined; + + /** + * The price expressed in terms of output amount/input amount. + */ + public get executionPrice(): Price { + return ( + this._executionPrice ?? + (this._executionPrice = new Price( + this.inputAmount.currency, + this.outputAmount.currency, + this.inputAmount.quotient, + this.outputAmount.quotient + )) + ); + } + + /** + * Return the execution price after accounting for slippage tolerance + * @returns The execution price + */ + public worstExecutionPrice(): Price { + return new Price( + this.inputAmount.currency, + this.outputAmount.currency, + this.maximumAmountIn().quotient, + this.minimumAmountOut().quotient + ); + } +} \ No newline at end of file diff --git a/sdks/uniswapx-sdk/src/trade/index.ts b/sdks/uniswapx-sdk/src/trade/index.ts index 37d79ca70..b178c513f 100644 --- a/sdks/uniswapx-sdk/src/trade/index.ts +++ b/sdks/uniswapx-sdk/src/trade/index.ts @@ -2,3 +2,4 @@ export * from "./DutchOrderTrade"; export * from "./V2DutchOrderTrade"; export * from "./PriorityOrderTrade"; export * from "./RelayOrderTrade"; +export * from "./V3DutchOrderTrade"; diff --git a/sdks/uniswapx-sdk/src/utils/dutchBlockDecay.test.ts b/sdks/uniswapx-sdk/src/utils/dutchBlockDecay.test.ts new file mode 100644 index 000000000..3014ef209 --- /dev/null +++ b/sdks/uniswapx-sdk/src/utils/dutchBlockDecay.test.ts @@ -0,0 +1,103 @@ +import { BigNumber } from "ethers"; + +import { NonLinearDutchDecayLib } from "./dutchBlockDecay"; + +describe("NonLinearDutchDecayLib", () => { + describe("linearDecay", () => { + it("Simple linearDecay", () => { + const result = NonLinearDutchDecayLib.linearDecay(0, 10, 5, BigNumber.from(100), BigNumber.from(50)); + expect(result.toString()).toEqual('75'); + }); + + it("Test for mulDivDown for endAmount < startAmount", () => { + const result = NonLinearDutchDecayLib.linearDecay(0, 10, 5, BigNumber.from(100), BigNumber.from(75)); + expect(result.toString()).toEqual('88'); //If we successfully emulated mulDivDown then this is 88. + }); + + it("Simple linearDecay but with endAmount > startAmount", () => { + const result = NonLinearDutchDecayLib.linearDecay(0, 10, 5, BigNumber.from(100), BigNumber.from(120)); + expect(result.toString()).toEqual('110'); + }); + + it("Test for mulDivDown for endAmount > startAmount", () => { + const result = NonLinearDutchDecayLib.linearDecay(0, 10, 5, BigNumber.from(100), BigNumber.from(125)); + //if we successfully emulated mulDivDown then this is 112 + expect(result.toString()).toEqual('112'); + }); + }); + + describe("decay", () => { + it("Returns startAmount if decay hasnt started", () => { + const test_payload = { + curve: { + relativeBlocks: [1, 2, 3, 4, 5], + relativeAmounts: [0, 10, 20, 30, 40].map(BigInt), + }, + startAmount: BigNumber.from(100), + decayStartBlock: 0, + currentBlock: 0, + }; + const result = NonLinearDutchDecayLib.decay(test_payload.curve, test_payload.startAmount, test_payload.decayStartBlock, test_payload.currentBlock); + expect(result.toString()).toEqual('100'); + }); + + it("Correctly calculates non-rounding decay", () => { + const test_payload = { + curve: { + relativeBlocks: [4], + relativeAmounts: [40].map(BigInt), + }, + startAmount: BigNumber.from(100), + decayStartBlock: 0, + currentBlock: 2, + }; + const result = NonLinearDutchDecayLib.decay(test_payload.curve, test_payload.startAmount, test_payload.decayStartBlock, test_payload.currentBlock); + expect(result.toString()).toEqual('80'); + }); + + // Add a rounding decay once we clarify mulDivDown/mulDivUp + + it("Correctly calculates non-rounding decay with multiple points", () => { + const test_payload = { + curve: { + relativeBlocks: [4, 6], + relativeAmounts: [40, 20].map(BigInt), + }, + startAmount: BigNumber.from(100), + decayStartBlock: 0, + currentBlock: 5, + }; + const result = NonLinearDutchDecayLib.decay(test_payload.curve, test_payload.startAmount, test_payload.decayStartBlock, test_payload.currentBlock); + expect(result.toString()).toEqual('70'); + }); + + it("Correctly calculates non-rounding negative decay", () => { + const test_payload = { + curve: { + relativeBlocks: [4], + relativeAmounts: [BigInt(-40)], + }, + startAmount: BigNumber.from(100), + decayStartBlock: 0, + currentBlock: 2, + }; + const result = NonLinearDutchDecayLib.decay(test_payload.curve, test_payload.startAmount, test_payload.decayStartBlock, test_payload.currentBlock); + expect(result.toString()).toEqual('120'); + }); + + it("Correctly calculates non-rounding negative decay with multiple points", () => { + const test_payload = { + curve: { + relativeBlocks: [4, 6], + relativeAmounts: [BigInt(-40), BigInt(-20)], + }, + startAmount: BigNumber.from(100), + decayStartBlock: 0, + currentBlock: 5, + }; + const result = NonLinearDutchDecayLib.decay(test_payload.curve, test_payload.startAmount, test_payload.decayStartBlock, test_payload.currentBlock); + expect(result.toString()).toEqual('130'); + }); + + }); +}); \ No newline at end of file diff --git a/sdks/uniswapx-sdk/src/utils/dutchBlockDecay.ts b/sdks/uniswapx-sdk/src/utils/dutchBlockDecay.ts new file mode 100644 index 000000000..7f74405a2 --- /dev/null +++ b/sdks/uniswapx-sdk/src/utils/dutchBlockDecay.ts @@ -0,0 +1,124 @@ +import { BigNumber } from "ethers"; + +import { NonlinearDutchDecay } from "../order"; +/* +These functions mimic the smart contract functions as closely as possible to ensure that the same results are produced. +Essentially Solidity translated to TypeScript. +*/ +function locateArrayPosition( + curve: NonlinearDutchDecay, + currentRelativeBlock: number +): [number, number] { + const relativeBlocks = curve.relativeBlocks; + let prev = 0; + let next = 0; + for (; next < relativeBlocks.length; next++) { + if(relativeBlocks[next] >= currentRelativeBlock) { + return [prev, next]; + } + prev = next; + } + return [next - 1, next - 1]; +} + +class NonLinearDutchDecayLib { + static decay( + curve: NonlinearDutchDecay, + startAmount: BigNumber, + decayStartBlock: number, + currentBlock: number + ): BigNumber { + // mismatch of relativeAmounts and relativeBlocks + if (curve.relativeAmounts.length > 16) { + throw new Error("InvalidDecayCurve"); + } + + // handle current block before decay or no decay + if (decayStartBlock >= currentBlock || curve.relativeAmounts.length === 0) { + return startAmount; + } + + const blockDelta = currentBlock - decayStartBlock; + + // Special case for when we need to use the decayStartBlock (0) + if (curve.relativeBlocks[0] > blockDelta) { + return this.linearDecay( + 0, + curve.relativeBlocks[0], + blockDelta, + startAmount, + startAmount.sub(curve.relativeAmounts[0].toString()) + ); + } + + // the current pos is within or after the curve + const [prev, next] = locateArrayPosition(curve, blockDelta); + //relativeAmounts holds BigInts so we can't directly subtract without conversion + const lastAmount = startAmount.sub(curve.relativeAmounts[prev].toString()); + const nextAmount = startAmount.sub(curve.relativeAmounts[next].toString()); + return this.linearDecay( + curve.relativeBlocks[prev], + curve.relativeBlocks[next], + blockDelta, + lastAmount, + nextAmount + ); + } + + static linearDecay( + startPoint: number, + endPoint: number, + currentPoint: number, + startAmount: BigNumber, + endAmount: BigNumber + ): BigNumber { + if (currentPoint >= endPoint) { + return endAmount; + } + + const elapsed = BigNumber.from(currentPoint - startPoint); + const duration = BigNumber.from(endPoint - startPoint); + let delta; + if (endAmount.lt(startAmount)) { + delta = BigNumber.from(0).sub((startAmount.sub(endAmount)).mul(elapsed).div(duration)); // mulDivDown in contract + } else { + delta = (endAmount.sub(startAmount)).mul(elapsed).div(duration); // mulDivDown in contract + } + return startAmount.add(delta); + } +} + +export { NonLinearDutchDecayLib }; + +export interface DutchBlockDecayConfig { + decayStartBlock: number; + startAmount: BigNumber; + relativeBlocks: number[]; + relativeAmounts: bigint[]; +} + +export function getBlockDecayedAmount( + config: DutchBlockDecayConfig, + atBlock: number +): BigNumber { + const { decayStartBlock, startAmount, relativeBlocks, relativeAmounts } = + config; + return NonLinearDutchDecayLib.decay( + { relativeAmounts, relativeBlocks }, + startAmount, + decayStartBlock, + atBlock + ); +} + +export function getEndAmount( + config: Partial +): BigNumber { + const { startAmount, relativeAmounts } = config; + if (!startAmount || !relativeAmounts) { + throw new Error("Invalid config for getting V3 decay end amount"); + } + return startAmount.sub( + relativeAmounts[relativeAmounts.length - 1].toString() + ); +} \ No newline at end of file diff --git a/sdks/uniswapx-sdk/src/utils/order.ts b/sdks/uniswapx-sdk/src/utils/order.ts index 7fe653288..67a2bf389 100644 --- a/sdks/uniswapx-sdk/src/utils/order.ts +++ b/sdks/uniswapx-sdk/src/utils/order.ts @@ -1,4 +1,4 @@ -import { ethers } from "ethers"; +import { BigNumber, ethers } from "ethers"; import { OrderType, REVERSE_REACTOR_MAPPING } from "../constants"; import { MissingConfiguration } from "../errors"; @@ -12,6 +12,7 @@ import { UnsignedPriorityOrder, UnsignedV2DutchOrder, } from "../order"; +import { CosignedV3DutchOrder, UnsignedV3DutchOrder } from "../order/V3DutchOrder"; import { stripHexPrefix } from "."; @@ -100,6 +101,16 @@ export class UniswapXOrderParser extends OrderParser { // if cosignature exists then returned cosigned version return cosignedOrder; } + case OrderType.Dutch_V3: { + // cosigned and unsigned serialized versions are the same format + const cosignedOrder = CosignedV3DutchOrder.parse(order, chainId); + // if no cosignature, returned unsigned variant + if (cosignedOrder.info.cosignature === "0x") { + return UnsignedV3DutchOrder.parse(order, chainId); + } + // if cosignature exists then returned cosigned version + return cosignedOrder; + } case OrderType.Priority: { // cosigned and unsigned serialized versions are the same format const cosignedOrder = CosignedPriorityOrder.parse(order, chainId); @@ -147,3 +158,7 @@ export class RelayOrderParser extends OrderParser { return RelayOrder.parse(order, chainId); } } + +export function originalIfZero(value: BigNumber, original: BigNumber): BigNumber { + return value.isZero() ? original : value; +} \ No newline at end of file