From 817e4ea335965fdf05882e1b9a4959a0afa01810 Mon Sep 17 00:00:00 2001 From: Jacob Nyquist Date: Fri, 31 Mar 2023 11:28:27 -0400 Subject: [PATCH] bid pools --- .solcover.js | 2 +- docs/generated/main.js | 2 +- foundry.toml | 2 +- integration/helpers/index.ts | 90 ++ integration/integration.test.ts | 518 +++++++- src/HookBidPool.sol | 580 +++++++++ src/interfaces/IHookOption.sol | 49 + .../delegate-cash/IDelegationRegistry.sol | 184 +++ src/interfaces/delegate-cash/README.md | 6 + .../zeroex-v4/IPropertyValidator.sol | 12 + src/lib/PoolOrders.sol | 159 +++ src/lib/lyra/BlackScholes.sol | 412 +++++++ src/lib/lyra/FixedPointMathLib.sol | 162 +++ src/lib/lyra/Math.sol | 30 + src/lib/lyra/README.md | 6 + src/lib/synthetix/DecimalMath.sol | 202 ++++ src/lib/synthetix/SignedDecimalMath.sol | 203 ++++ src/test/HookBidPoolTest.t.sol | 1062 +++++++++++++++++ src/test/utils/mocks/PropertyValidator1.sol | 79 ++ .../utils/mocks/PropertyValidatorReverts.sol | 13 + 20 files changed, 3766 insertions(+), 7 deletions(-) create mode 100644 src/HookBidPool.sol create mode 100644 src/interfaces/IHookOption.sol create mode 100644 src/interfaces/delegate-cash/IDelegationRegistry.sol create mode 100644 src/interfaces/delegate-cash/README.md create mode 100644 src/interfaces/zeroex-v4/IPropertyValidator.sol create mode 100644 src/lib/PoolOrders.sol create mode 100644 src/lib/lyra/BlackScholes.sol create mode 100644 src/lib/lyra/FixedPointMathLib.sol create mode 100644 src/lib/lyra/Math.sol create mode 100644 src/lib/lyra/README.md create mode 100644 src/lib/synthetix/DecimalMath.sol create mode 100644 src/lib/synthetix/SignedDecimalMath.sol create mode 100644 src/test/HookBidPoolTest.t.sol create mode 100644 src/test/utils/mocks/PropertyValidator1.sol create mode 100644 src/test/utils/mocks/PropertyValidatorReverts.sol diff --git a/.solcover.js b/.solcover.js index 9819e96..94e1f39 100644 --- a/.solcover.js +++ b/.solcover.js @@ -1,3 +1,3 @@ module.exports = { - skipFiles: ["test", "mixin/HookInstrumentERC721.sol", "lib/HookStrings.sol"] + skipFiles: ["test", "mixin/HookInstrumentERC721.sol", "lib/HookStrings.sol", "lib/lyra", "lib/synthetix"] }; \ No newline at end of file diff --git a/docs/generated/main.js b/docs/generated/main.js index ad9091d..8edaec4 100644 --- a/docs/generated/main.js +++ b/docs/generated/main.js @@ -1,2 +1,2 @@ /*! For license information please see main.js.LICENSE.txt */ -(()=>{var e={268:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});var a=n(81),i=n.n(a),r=n(645),s=n.n(r)()(i());s.push([e.id,"@import url(https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@400;500;600;700&display=swap);"]),s.push([e.id,"\nhtml,\nbody {\n font-family: 'Source Code Pro', monospace;\n}\n",""]);const o=s},645:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n="",a=void 0!==t[5];return t[4]&&(n+="@supports (".concat(t[4],") {")),t[2]&&(n+="@media ".concat(t[2]," {")),a&&(n+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),n+=e(t),a&&(n+="}"),t[2]&&(n+="}"),t[4]&&(n+="}"),n})).join("")},t.i=function(e,n,a,i,r){"string"==typeof e&&(e=[[null,e,void 0]]);var s={};if(a)for(var o=0;o0?" ".concat(d[5]):""," {").concat(d[1],"}")),d[5]=r),n&&(d[2]?(d[1]="@media ".concat(d[2]," {").concat(d[1],"}"),d[2]=n):d[2]=n),i&&(d[4]?(d[1]="@supports (".concat(d[4],") {").concat(d[1],"}"),d[4]=i):d[4]="".concat(i)),t.push(d))}},t}},81:e=>{"use strict";e.exports=function(e){return e[1]}},387:(e,t,n)=>{var a=n(268);a.__esModule&&(a=a.default),"string"==typeof a&&(a=[[e.id,a,""]]),a.locals&&(e.exports=a.locals),(0,n(346).Z)("0b345cf4",a,!1,{})},346:(e,t,n)=>{"use strict";function a(e,t){for(var n=[],a={},i=0;if});var i="undefined"!=typeof document;if("undefined"!=typeof DEBUG&&DEBUG&&!i)throw new Error("vue-style-loader cannot be used in a non-browser environment. Use { target: 'node' } in your Webpack config to indicate a server-rendering environment.");var r={},s=i&&(document.head||document.getElementsByTagName("head")[0]),o=null,l=0,u=!1,d=function(){},p=null,c="data-vue-ssr-id",y="undefined"!=typeof navigator&&/msie [6-9]\b/.test(navigator.userAgent.toLowerCase());function f(e,t,n,i){u=n,p=i||{};var s=a(e,t);return m(s),function(t){for(var n=[],i=0;in.parts.length&&(a.parts.length=n.parts.length)}else{var s=[];for(i=0;i{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{"use strict";var e=Object.freeze({});function t(e){return null==e}function a(e){return null!=e}function i(e){return!0===e}function r(e){return"string"==typeof e||"number"==typeof e||"symbol"==typeof e||"boolean"==typeof e}function s(e){return null!==e&&"object"==typeof e}var o=Object.prototype.toString;function l(e){return"[object Object]"===o.call(e)}function u(e){var t=parseFloat(String(e));return t>=0&&Math.floor(t)===t&&isFinite(e)}function d(e){return a(e)&&"function"==typeof e.then&&"function"==typeof e.catch}function p(e){return null==e?"":Array.isArray(e)||l(e)&&e.toString===o?JSON.stringify(e,null,2):String(e)}function c(e){var t=parseFloat(e);return isNaN(t)?e:t}function y(e,t){for(var n=Object.create(null),a=e.split(","),i=0;i-1)return e.splice(n,1)}}var v=Object.prototype.hasOwnProperty;function b(e,t){return v.call(e,t)}function g(e){var t=Object.create(null);return function(n){return t[n]||(t[n]=e(n))}}var T=/-(\w)/g,w=g((function(e){return e.replace(T,(function(e,t){return t?t.toUpperCase():""}))})),k=g((function(e){return e.charAt(0).toUpperCase()+e.slice(1)})),C=/\B([A-Z])/g,I=g((function(e){return e.replace(C,"-$1").toLowerCase()})),_=Function.prototype.bind?function(e,t){return e.bind(t)}:function(e,t){function n(n){var a=arguments.length;return a?a>1?e.apply(t,arguments):e.call(t,n):e.call(t)}return n._length=e.length,n};function x(e,t){t=t||0;for(var n=e.length-t,a=new Array(n);n--;)a[n]=e[n+t];return a}function A(e,t){for(var n in t)e[n]=t[n];return e}function E(e){for(var t={},n=0;n0,X=J&&J.indexOf("edge/")>0,Y=(J&&J.indexOf("android"),J&&/iphone|ipad|ipod|ios/.test(J)||"ios"===G),Q=(J&&/chrome\/\d+/.test(J),J&&/phantomjs/.test(J),J&&J.match(/firefox\/(\d+)/)),ee={}.watch,te=!1;if(q)try{var ne={};Object.defineProperty(ne,"passive",{get:function(){te=!0}}),window.addEventListener("test-passive",null,ne)}catch(e){}var ae=function(){return void 0===D&&(D=!q&&!W&&void 0!==n.g&&n.g.process&&"server"===n.g.process.env.VUE_ENV),D},ie=q&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function re(e){return"function"==typeof e&&/native code/.test(e.toString())}var se,oe="undefined"!=typeof Symbol&&re(Symbol)&&"undefined"!=typeof Reflect&&re(Reflect.ownKeys);se="undefined"!=typeof Set&&re(Set)?Set:function(){function e(){this.set=Object.create(null)}return e.prototype.has=function(e){return!0===this.set[e]},e.prototype.add=function(e){this.set[e]=!0},e.prototype.clear=function(){this.set=Object.create(null)},e}();var le=R,ue=0,de=function(){this.id=ue++,this.subs=[]};de.prototype.addSub=function(e){this.subs.push(e)},de.prototype.removeSub=function(e){h(this.subs,e)},de.prototype.depend=function(){de.target&&de.target.addDep(this)},de.prototype.notify=function(){for(var e=this.subs.slice(),t=0,n=e.length;t-1)if(r&&!b(i,"default"))s=!1;else if(""===s||s===I(e)){var l=De(String,i.type);(l<0||o0&&(ct((o=yt(o,(n||"")+"_"+s))[0])&&ct(u)&&(d[l]=ve(u.text+o[0].text),o.shift()),d.push.apply(d,o)):r(o)?ct(u)?d[l]=ve(u.text+o):""!==o&&d.push(ve(o)):ct(o)&&ct(u)?d[l]=ve(u.text+o.text):(i(e._isVList)&&a(o.tag)&&t(o.key)&&a(n)&&(o.key="__vlist"+n+"_"+s+"__"),d.push(o)));return d}function ft(e,t){if(e){for(var n=Object.create(null),a=oe?Reflect.ownKeys(e):Object.keys(e),i=0;i0,s=t?!!t.$stable:!r,o=t&&t.$key;if(t){if(t._normalized)return t._normalized;if(s&&a&&a!==e&&o===a.$key&&!r&&!a.$hasNormal)return a;for(var l in i={},t)t[l]&&"$"!==l[0]&&(i[l]=gt(n,l,t[l]))}else i={};for(var u in n)u in i||(i[u]=Tt(n,u));return t&&Object.isExtensible(t)&&(t._normalized=i),B(i,"$stable",s),B(i,"$key",o),B(i,"$hasNormal",r),i}function gt(e,t,n){var a=function(){var e=arguments.length?n.apply(null,arguments):n({}),t=(e=e&&"object"==typeof e&&!Array.isArray(e)?[e]:pt(e))&&e[0];return e&&(!t||1===e.length&&t.isComment&&!vt(t))?void 0:e};return n.proxy&&Object.defineProperty(e,t,{get:a,enumerable:!0,configurable:!0}),a}function Tt(e,t){return function(){return e[t]}}function wt(e,t){var n,i,r,o,l;if(Array.isArray(e)||"string"==typeof e)for(n=new Array(e.length),i=0,r=e.length;idocument.createEvent("Event").timeStamp&&(mn=function(){return hn.now()})}function vn(){var e,t;for(fn=mn(),cn=!0,ln.sort((function(e,t){return e.id-t.id})),yn=0;ynyn&&ln[n].id>e.id;)n--;ln.splice(n+1,0,e)}else ln.push(e);pn||(pn=!0,nt(vn))}}(this)},gn.prototype.run=function(){if(this.active){var e=this.get();if(e!==this.value||s(e)||this.deep){var t=this.value;if(this.value=e,this.user){var n='callback for watcher "'+this.expression+'"';ze(this.cb,this.vm,[e,t],this.vm,n)}else this.cb.call(this.vm,e,t)}}},gn.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},gn.prototype.depend=function(){for(var e=this.deps.length;e--;)this.deps[e].depend()},gn.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||h(this.vm._watchers,this);for(var e=this.deps.length;e--;)this.deps[e].removeSub(this);this.active=!1}};var Tn={enumerable:!0,configurable:!0,get:R,set:R};function wn(e,t,n){Tn.get=function(){return this[t][n]},Tn.set=function(e){this[t][n]=e},Object.defineProperty(e,n,Tn)}var kn={lazy:!0};function Cn(e,t,n){var a=!ae();"function"==typeof n?(Tn.get=a?In(t):_n(n),Tn.set=R):(Tn.get=n.get?a&&!1!==n.cache?In(t):_n(n.get):R,Tn.set=n.set||R),Object.defineProperty(e,t,Tn)}function In(e){return function(){var t=this._computedWatchers&&this._computedWatchers[e];if(t)return t.dirty&&t.evaluate(),de.target&&t.depend(),t.value}}function _n(e){return function(){return e.call(this,this)}}function xn(e,t,n,a){return l(n)&&(a=n,n=n.handler),"string"==typeof n&&(n=e[n]),e.$watch(t,n,a)}var An=0;function En(e){var t=e.options;if(e.super){var n=En(e.super);if(n!==e.superOptions){e.superOptions=n;var a=function(e){var t,n=e.options,a=e.sealedOptions;for(var i in n)n[i]!==a[i]&&(t||(t={}),t[i]=n[i]);return t}(e);a&&A(e.extendOptions,a),(t=e.options=Pe(n,e.extendOptions)).name&&(t.components[t.name]=e)}}return t}function Rn(e){this._init(e)}function On(e){return e&&(e.Ctor.options.name||e.tag)}function Mn(e,t){return Array.isArray(e)?e.indexOf(t)>-1:"string"==typeof e?e.split(",").indexOf(t)>-1:(n=e,!("[object RegExp]"!==o.call(n))&&e.test(t));var n}function Sn(e,t){var n=e.cache,a=e.keys,i=e._vnode;for(var r in n){var s=n[r];if(s){var o=s.name;o&&!t(o)&&$n(n,r,a,i)}}}function $n(e,t,n,a){var i=e[t];!i||a&&i.tag===a.tag||i.componentInstance.$destroy(),e[t]=null,h(n,t)}!function(t){t.prototype._init=function(t){var n=this;n._uid=An++,n._isVue=!0,t&&t._isComponent?function(e,t){var n=e.$options=Object.create(e.constructor.options),a=t._parentVnode;n.parent=t.parent,n._parentVnode=a;var i=a.componentOptions;n.propsData=i.propsData,n._parentListeners=i.listeners,n._renderChildren=i.children,n._componentTag=i.tag,t.render&&(n.render=t.render,n.staticRenderFns=t.staticRenderFns)}(n,t):n.$options=Pe(En(n.constructor),t||{},n),n._renderProxy=n,n._self=n,function(e){var t=e.$options,n=t.parent;if(n&&!t.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(e)}e.$parent=n,e.$root=n?n.$root:e,e.$children=[],e.$refs={},e._watcher=null,e._inactive=null,e._directInactive=!1,e._isMounted=!1,e._isDestroyed=!1,e._isBeingDestroyed=!1}(n),function(e){e._events=Object.create(null),e._hasHookEvent=!1;var t=e.$options._parentListeners;t&&en(e,t)}(n),function(t){t._vnode=null,t._staticTrees=null;var n=t.$options,a=t.$vnode=n._parentVnode,i=a&&a.context;t.$slots=mt(n._renderChildren,i),t.$scopedSlots=e,t._c=function(e,n,a,i){return qt(t,e,n,a,i,!1)},t.$createElement=function(e,n,a,i){return qt(t,e,n,a,i,!0)};var r=a&&a.data;xe(t,"$attrs",r&&r.attrs||e,null,!0),xe(t,"$listeners",n._parentListeners||e,null,!0)}(n),on(n,"beforeCreate"),function(e){var t=ft(e.$options.inject,e);t&&(Ce(!1),Object.keys(t).forEach((function(n){xe(e,n,t[n])})),Ce(!0))}(n),function(e){e._watchers=[];var t=e.$options;t.props&&function(e,t){var n=e.$options.propsData||{},a=e._props={},i=e.$options._propKeys=[];!e.$parent||Ce(!1);var r=function(r){i.push(r);var s=He(r,t,n,e);xe(a,r,s),r in e||wn(e,"_props",r)};for(var s in t)r(s);Ce(!0)}(e,t.props),t.methods&&function(e,t){for(var n in e.$options.props,t)e[n]="function"!=typeof t[n]?R:_(t[n],e)}(e,t.methods),t.data?function(e){var t=e.$options.data;l(t=e._data="function"==typeof t?function(e,t){ce();try{return e.call(t,t)}catch(e){return Ue(e,t,"data()"),{}}finally{ye()}}(t,e):t||{})||(t={});for(var n=Object.keys(t),a=e.$options.props,i=(e.$options.methods,n.length);i--;){var r=n[i];a&&b(a,r)||N(r)||wn(e,"_data",r)}_e(t,!0)}(e):_e(e._data={},!0),t.computed&&function(e,t){var n=e._computedWatchers=Object.create(null),a=ae();for(var i in t){var r=t[i],s="function"==typeof r?r:r.get;a||(n[i]=new gn(e,s||R,R,kn)),i in e||Cn(e,i,r)}}(e,t.computed),t.watch&&t.watch!==ee&&function(e,t){for(var n in t){var a=t[n];if(Array.isArray(a))for(var i=0;i1?x(n):n;for(var a=x(arguments,1),i='event handler for "'+e+'"',r=0,s=n.length;rparseInt(this.max)&&$n(t,n[0],n,this._vnode),this.vnodeToCache=null}}},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){for(var e in this.cache)$n(this.cache,e,this.keys)},mounted:function(){var e=this;this.cacheVNode(),this.$watch("include",(function(t){Sn(e,(function(e){return Mn(t,e)}))})),this.$watch("exclude",(function(t){Sn(e,(function(e){return!Mn(t,e)}))}))},updated:function(){this.cacheVNode()},render:function(){var e=this.$slots.default,t=Zt(e),n=t&&t.componentOptions;if(n){var a=On(n),i=this.include,r=this.exclude;if(i&&(!a||!Mn(i,a))||r&&a&&Mn(r,a))return t;var s=this.cache,o=this.keys,l=null==t.key?n.Ctor.cid+(n.tag?"::"+n.tag:""):t.key;s[l]?(t.componentInstance=s[l].componentInstance,h(o,l),o.push(l)):(this.vnodeToCache=t,this.keyToCache=l),t.data.keepAlive=!0}return t||e&&e[0]}},Pn={KeepAlive:Fn};!function(e){var t={get:function(){return H}};Object.defineProperty(e,"config",t),e.util={warn:le,extend:A,mergeOptions:Pe,defineReactive:xe},e.set=Ae,e.delete=Ee,e.nextTick=nt,e.observable=function(e){return _e(e),e},e.options=Object.create(null),P.forEach((function(t){e.options[t+"s"]=Object.create(null)})),e.options._base=e,A(e.options.components,Pn),function(e){e.use=function(e){var t=this._installedPlugins||(this._installedPlugins=[]);if(t.indexOf(e)>-1)return this;var n=x(arguments,1);return n.unshift(this),"function"==typeof e.install?e.install.apply(e,n):"function"==typeof e&&e.apply(null,n),t.push(e),this}}(e),function(e){e.mixin=function(e){return this.options=Pe(this.options,e),this}}(e),function(e){e.cid=0;var t=1;e.extend=function(e){e=e||{};var n=this,a=n.cid,i=e._Ctor||(e._Ctor={});if(i[a])return i[a];var r=e.name||n.options.name,s=function(e){this._init(e)};return(s.prototype=Object.create(n.prototype)).constructor=s,s.cid=t++,s.options=Pe(n.options,e),s.super=n,s.options.props&&function(e){var t=e.options.props;for(var n in t)wn(e.prototype,"_props",n)}(s),s.options.computed&&function(e){var t=e.options.computed;for(var n in t)Cn(e.prototype,n,t[n])}(s),s.extend=n.extend,s.mixin=n.mixin,s.use=n.use,P.forEach((function(e){s[e]=n[e]})),r&&(s.options.components[r]=s),s.superOptions=n.options,s.extendOptions=e,s.sealedOptions=A({},s.options),i[a]=s,s}}(e),function(e){P.forEach((function(t){e[t]=function(e,n){return n?("component"===t&&l(n)&&(n.name=n.name||e,n=this.options._base.extend(n)),"directive"===t&&"function"==typeof n&&(n={bind:n,update:n}),this.options[t+"s"][e]=n,n):this.options[t+"s"][e]}}))}(e)}(Rn),Object.defineProperty(Rn.prototype,"$isServer",{get:ae}),Object.defineProperty(Rn.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(Rn,"FunctionalRenderContext",{value:Pt}),Rn.version="2.6.14";var jn=y("style,class"),Hn=y("input,textarea,option,select,progress"),Vn=function(e,t,n){return"value"===n&&Hn(e)&&"button"!==t||"selected"===n&&"option"===e||"checked"===n&&"input"===e||"muted"===n&&"video"===e},Nn=y("contenteditable,draggable,spellcheck"),Bn=y("events,caret,typing,plaintext-only"),Dn=function(e,t){return Gn(t)||"false"===t?"false":"contenteditable"===e&&Bn(t)?t:"true"},Un=y("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,truespeed,typemustmatch,visible"),zn="http://www.w3.org/1999/xlink",qn=function(e){return":"===e.charAt(5)&&"xlink"===e.slice(0,5)},Wn=function(e){return qn(e)?e.slice(6,e.length):""},Gn=function(e){return null==e||!1===e};function Jn(e,t){return{staticClass:Kn(e.staticClass,t.staticClass),class:a(e.class)?[e.class,t.class]:t.class}}function Kn(e,t){return e?t?e+" "+t:e:t||""}function Zn(e){return Array.isArray(e)?function(e){for(var t,n="",i=0,r=e.length;i-1?wa(e,t,n):Un(t)?Gn(n)?e.removeAttribute(t):(n="allowfullscreen"===t&&"EMBED"===e.tagName?"true":t,e.setAttribute(t,n)):Nn(t)?e.setAttribute(t,Dn(t,n)):qn(t)?Gn(n)?e.removeAttributeNS(zn,Wn(t)):e.setAttributeNS(zn,t,n):wa(e,t,n)}function wa(e,t,n){if(Gn(n))e.removeAttribute(t);else{if(K&&!Z&&"TEXTAREA"===e.tagName&&"placeholder"===t&&""!==n&&!e.__ieph){var a=function(t){t.stopImmediatePropagation(),e.removeEventListener("input",a)};e.addEventListener("input",a),e.__ieph=!0}e.setAttribute(t,n)}}var ka={create:ga,update:ga};function Ca(e,n){var i=n.elm,r=n.data,s=e.data;if(!(t(r.staticClass)&&t(r.class)&&(t(s)||t(s.staticClass)&&t(s.class)))){var o=function(e){for(var t=e.data,n=e,i=e;a(i.componentInstance);)(i=i.componentInstance._vnode)&&i.data&&(t=Jn(i.data,t));for(;a(n=n.parent);)n&&n.data&&(t=Jn(t,n.data));return r=t.staticClass,s=t.class,a(r)||a(s)?Kn(r,Zn(s)):"";var r,s}(n),l=i._transitionClasses;a(l)&&(o=Kn(o,Zn(l))),o!==i._prevClass&&(i.setAttribute("class",o),i._prevClass=o)}}var Ia,_a,xa,Aa,Ea,Ra,Oa={create:Ca,update:Ca},Ma=/[\w).+\-_$\]]/;function Sa(e){var t,n,a,i,r,s=!1,o=!1,l=!1,u=!1,d=0,p=0,c=0,y=0;for(a=0;a=0&&" "===(m=e.charAt(f));f--);m&&Ma.test(m)||(u=!0)}}else void 0===i?(y=a+1,i=e.slice(0,a).trim()):h();function h(){(r||(r=[])).push(e.slice(y,a).trim()),y=a+1}if(void 0===i?i=e.slice(0,a).trim():0!==y&&h(),r)for(a=0;a-1?{exp:e.slice(0,Aa),key:'"'+e.slice(Aa+1)+'"'}:{exp:e,key:null};for(_a=e,Aa=Ea=Ra=0;!Ka();)Za(xa=Ja())?Ya(xa):91===xa&&Xa(xa);return{exp:e.slice(0,Ea),key:e.slice(Ea+1,Ra)}}(e);return null===n.key?e+"="+t:"$set("+n.exp+", "+n.key+", "+t+")"}function Ja(){return _a.charCodeAt(++Aa)}function Ka(){return Aa>=Ia}function Za(e){return 34===e||39===e}function Xa(e){var t=1;for(Ea=Aa;!Ka();)if(Za(e=Ja()))Ya(e);else if(91===e&&t++,93===e&&t--,0===t){Ra=Aa;break}}function Ya(e){for(var t=e;!Ka()&&(e=Ja())!==t;);}var Qa,ei="__r",ti="__c";function ni(e,t,n){var a=Qa;return function i(){null!==t.apply(null,arguments)&&ri(e,i,n,a)}}var ai=Je&&!(Q&&Number(Q[1])<=53);function ii(e,t,n,a){if(ai){var i=fn,r=t;t=r._wrapper=function(e){if(e.target===e.currentTarget||e.timeStamp>=i||e.timeStamp<=0||e.target.ownerDocument!==document)return r.apply(this,arguments)}}Qa.addEventListener(e,t,te?{capture:n,passive:a}:n)}function ri(e,t,n,a){(a||Qa).removeEventListener(e,t._wrapper||t,n)}function si(e,n){if(!t(e.data.on)||!t(n.data.on)){var i=n.data.on||{},r=e.data.on||{};Qa=n.elm,function(e){if(a(e[ei])){var t=K?"change":"input";e[t]=[].concat(e[ei],e[t]||[]),delete e[ei]}a(e[ti])&&(e.change=[].concat(e[ti],e.change||[]),delete e[ti])}(i),lt(i,r,ii,ri,ni,n.context),Qa=void 0}}var oi,li={create:si,update:si};function ui(e,n){if(!t(e.data.domProps)||!t(n.data.domProps)){var i,r,s=n.elm,o=e.data.domProps||{},l=n.data.domProps||{};for(i in a(l.__ob__)&&(l=n.data.domProps=A({},l)),o)i in l||(s[i]="");for(i in l){if(r=l[i],"textContent"===i||"innerHTML"===i){if(n.children&&(n.children.length=0),r===o[i])continue;1===s.childNodes.length&&s.removeChild(s.childNodes[0])}if("value"===i&&"PROGRESS"!==s.tagName){s._value=r;var u=t(r)?"":String(r);di(s,u)&&(s.value=u)}else if("innerHTML"===i&&Qn(s.tagName)&&t(s.innerHTML)){(oi=oi||document.createElement("div")).innerHTML=""+r+"";for(var d=oi.firstChild;s.firstChild;)s.removeChild(s.firstChild);for(;d.firstChild;)s.appendChild(d.firstChild)}else if(r!==o[i])try{s[i]=r}catch(e){}}}}function di(e,t){return!e.composing&&("OPTION"===e.tagName||function(e,t){var n=!0;try{n=document.activeElement!==e}catch(e){}return n&&e.value!==t}(e,t)||function(e,t){var n=e.value,i=e._vModifiers;if(a(i)){if(i.number)return c(n)!==c(t);if(i.trim)return n.trim()!==t.trim()}return n!==t}(e,t))}var pi={create:ui,update:ui},ci=g((function(e){var t={},n=/:(.+)/;return e.split(/;(?![^(]*\))/g).forEach((function(e){if(e){var a=e.split(n);a.length>1&&(t[a[0].trim()]=a[1].trim())}})),t}));function yi(e){var t=fi(e.style);return e.staticStyle?A(e.staticStyle,t):t}function fi(e){return Array.isArray(e)?E(e):"string"==typeof e?ci(e):e}var mi,hi=/^--/,vi=/\s*!important$/,bi=function(e,t,n){if(hi.test(t))e.style.setProperty(t,n);else if(vi.test(n))e.style.setProperty(I(t),n.replace(vi,""),"important");else{var a=Ti(t);if(Array.isArray(n))for(var i=0,r=n.length;i-1?t.split(Ci).forEach((function(t){return e.classList.add(t)})):e.classList.add(t);else{var n=" "+(e.getAttribute("class")||"")+" ";n.indexOf(" "+t+" ")<0&&e.setAttribute("class",(n+t).trim())}}function _i(e,t){if(t&&(t=t.trim()))if(e.classList)t.indexOf(" ")>-1?t.split(Ci).forEach((function(t){return e.classList.remove(t)})):e.classList.remove(t),e.classList.length||e.removeAttribute("class");else{for(var n=" "+(e.getAttribute("class")||"")+" ",a=" "+t+" ";n.indexOf(a)>=0;)n=n.replace(a," ");(n=n.trim())?e.setAttribute("class",n):e.removeAttribute("class")}}function xi(e){if(e){if("object"==typeof e){var t={};return!1!==e.css&&A(t,Ai(e.name||"v")),A(t,e),t}return"string"==typeof e?Ai(e):void 0}}var Ai=g((function(e){return{enterClass:e+"-enter",enterToClass:e+"-enter-to",enterActiveClass:e+"-enter-active",leaveClass:e+"-leave",leaveToClass:e+"-leave-to",leaveActiveClass:e+"-leave-active"}})),Ei=q&&!Z,Ri="transition",Oi="animation",Mi="transition",Si="transitionend",$i="animation",Li="animationend";Ei&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(Mi="WebkitTransition",Si="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&($i="WebkitAnimation",Li="webkitAnimationEnd"));var Fi=q?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(e){return e()};function Pi(e){Fi((function(){Fi(e)}))}function ji(e,t){var n=e._transitionClasses||(e._transitionClasses=[]);n.indexOf(t)<0&&(n.push(t),Ii(e,t))}function Hi(e,t){e._transitionClasses&&h(e._transitionClasses,t),_i(e,t)}function Vi(e,t,n){var a=Bi(e,t),i=a.type,r=a.timeout,s=a.propCount;if(!i)return n();var o=i===Ri?Si:Li,l=0,u=function(){e.removeEventListener(o,d),n()},d=function(t){t.target===e&&++l>=s&&u()};setTimeout((function(){l0&&(n=Ri,d=s,p=r.length):t===Oi?u>0&&(n=Oi,d=u,p=l.length):p=(n=(d=Math.max(s,u))>0?s>u?Ri:Oi:null)?n===Ri?r.length:l.length:0,{type:n,timeout:d,propCount:p,hasTransform:n===Ri&&Ni.test(a[Mi+"Property"])}}function Di(e,t){for(;e.length1}function Ji(e,t){!0!==t.data.show&&zi(t)}var Ki=function(e){var n,s,o={},l=e.modules,u=e.nodeOps;for(n=0;nf?g(e,t(i[v+1])?null:i[v+1].elm,i,y,v,r):y>v&&w(n,c,f)}(c,m,v,r,d):a(v)?(a(e.text)&&u.setTextContent(c,""),g(c,null,v,0,v.length-1,r)):a(m)?w(m,0,m.length-1):a(e.text)&&u.setTextContent(c,""):e.text!==n.text&&u.setTextContent(c,n.text),a(f)&&a(y=f.hook)&&a(y=y.postpatch)&&y(e,n)}}}function _(e,t,n){if(i(n)&&a(e.parent))e.parent.data.pendingInsert=t;else for(var r=0;r-1,s.selected!==r&&(s.selected=r);else if(S(er(s),a))return void(e.selectedIndex!==o&&(e.selectedIndex=o));i||(e.selectedIndex=-1)}}function Qi(e,t){return t.every((function(t){return!S(t,e)}))}function er(e){return"_value"in e?e._value:e.value}function tr(e){e.target.composing=!0}function nr(e){e.target.composing&&(e.target.composing=!1,ar(e.target,"input"))}function ar(e,t){var n=document.createEvent("HTMLEvents");n.initEvent(t,!0,!0),e.dispatchEvent(n)}function ir(e){return!e.componentInstance||e.data&&e.data.transition?e:ir(e.componentInstance._vnode)}var rr={bind:function(e,t,n){var a=t.value,i=(n=ir(n)).data&&n.data.transition,r=e.__vOriginalDisplay="none"===e.style.display?"":e.style.display;a&&i?(n.data.show=!0,zi(n,(function(){e.style.display=r}))):e.style.display=a?r:"none"},update:function(e,t,n){var a=t.value;!a!=!t.oldValue&&((n=ir(n)).data&&n.data.transition?(n.data.show=!0,a?zi(n,(function(){e.style.display=e.__vOriginalDisplay})):qi(n,(function(){e.style.display="none"}))):e.style.display=a?e.__vOriginalDisplay:"none")},unbind:function(e,t,n,a,i){i||(e.style.display=e.__vOriginalDisplay)}},sr={model:Zi,show:rr},or={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function lr(e){var t=e&&e.componentOptions;return t&&t.Ctor.options.abstract?lr(Zt(t.children)):e}function ur(e){var t={},n=e.$options;for(var a in n.propsData)t[a]=e[a];var i=n._parentListeners;for(var r in i)t[w(r)]=i[r];return t}function dr(e,t){if(/\d-keep-alive$/.test(t.tag))return e("keep-alive",{props:t.componentOptions.propsData})}var pr=function(e){return e.tag||vt(e)},cr=function(e){return"show"===e.name},yr={name:"transition",props:or,abstract:!0,render:function(e){var t=this,n=this.$slots.default;if(n&&(n=n.filter(pr)).length){var a=this.mode,i=n[0];if(function(e){for(;e=e.parent;)if(e.data.transition)return!0}(this.$vnode))return i;var s=lr(i);if(!s)return i;if(this._leaving)return dr(e,i);var o="__transition-"+this._uid+"-";s.key=null==s.key?s.isComment?o+"comment":o+s.tag:r(s.key)?0===String(s.key).indexOf(o)?s.key:o+s.key:s.key;var l=(s.data||(s.data={})).transition=ur(this),u=this._vnode,d=lr(u);if(s.data.directives&&s.data.directives.some(cr)&&(s.data.show=!0),d&&d.data&&!function(e,t){return t.key===e.key&&t.tag===e.tag}(s,d)&&!vt(d)&&(!d.componentInstance||!d.componentInstance._vnode.isComment)){var p=d.data.transition=A({},l);if("out-in"===a)return this._leaving=!0,ut(p,"afterLeave",(function(){t._leaving=!1,t.$forceUpdate()})),dr(e,i);if("in-out"===a){if(vt(s))return u;var c,y=function(){c()};ut(l,"afterEnter",y),ut(l,"enterCancelled",y),ut(p,"delayLeave",(function(e){c=e}))}}return i}}},fr=A({tag:String,moveClass:String},or);delete fr.mode;var mr={props:fr,beforeMount:function(){var e=this,t=this._update;this._update=function(n,a){var i=nn(e);e.__patch__(e._vnode,e.kept,!1,!0),e._vnode=e.kept,i(),t.call(e,n,a)}},render:function(e){for(var t=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),a=this.prevChildren=this.children,i=this.$slots.default||[],r=this.children=[],s=ur(this),o=0;o-1?na[e]=t.constructor===window.HTMLUnknownElement||t.constructor===window.HTMLElement:na[e]=/HTMLUnknownElement/.test(t.toString())},A(Rn.options.directives,sr),A(Rn.options.components,gr),Rn.prototype.__patch__=q?Ki:R,Rn.prototype.$mount=function(e,t){return function(e,t,n){var a;return e.$el=t,e.$options.render||(e.$options.render=he),on(e,"beforeMount"),a=function(){e._update(e._render(),n)},new gn(e,a,R,{before:function(){e._isMounted&&!e._isDestroyed&&on(e,"beforeUpdate")}},!0),n=!1,null==e.$vnode&&(e._isMounted=!0,on(e,"mounted")),e}(this,e=e&&q?ia(e):void 0,t)},q&&setTimeout((function(){H.devtools&&ie&&ie.emit("init",Rn)}),0);var Tr,wr=/\{\{((?:.|\r?\n)+?)\}\}/g,kr=/[-.*+?^${}()|[\]\/\\]/g,Cr=g((function(e){var t=e[0].replace(kr,"\\$&"),n=e[1].replace(kr,"\\$&");return new RegExp(t+"((?:.|\\n)+?)"+n,"g")})),Ir={staticKeys:["staticClass"],transformNode:function(e,t){t.warn;var n=Ua(e,"class");n&&(e.staticClass=JSON.stringify(n));var a=Da(e,"class",!1);a&&(e.classBinding=a)},genData:function(e){var t="";return e.staticClass&&(t+="staticClass:"+e.staticClass+","),e.classBinding&&(t+="class:"+e.classBinding+","),t}},_r={staticKeys:["staticStyle"],transformNode:function(e,t){t.warn;var n=Ua(e,"style");n&&(e.staticStyle=JSON.stringify(ci(n)));var a=Da(e,"style",!1);a&&(e.styleBinding=a)},genData:function(e){var t="";return e.staticStyle&&(t+="staticStyle:"+e.staticStyle+","),e.styleBinding&&(t+="style:("+e.styleBinding+"),"),t}},xr=y("area,base,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),Ar=y("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),Er=y("address,article,aside,base,blockquote,body,caption,col,colgroup,dd,details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,title,tr,track"),Rr=/^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,Or=/^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+?\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,Mr="[a-zA-Z_][\\-\\.0-9_a-zA-Z"+V.source+"]*",Sr="((?:"+Mr+"\\:)?"+Mr+")",$r=new RegExp("^<"+Sr),Lr=/^\s*(\/?)>/,Fr=new RegExp("^<\\/"+Sr+"[^>]*>"),Pr=/^]+>/i,jr=/^",""":'"',"&":"&"," ":"\n"," ":"\t","'":"'"},Dr=/&(?:lt|gt|quot|amp|#39);/g,Ur=/&(?:lt|gt|quot|amp|#39|#10|#9);/g,zr=y("pre,textarea",!0),qr=function(e,t){return e&&zr(e)&&"\n"===t[0]};function Wr(e,t){var n=t?Ur:Dr;return e.replace(n,(function(e){return Br[e]}))}var Gr,Jr,Kr,Zr,Xr,Yr,Qr,es,ts=/^@|^v-on:/,ns=/^v-|^@|^:|^#/,as=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,is=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,rs=/^\(|\)$/g,ss=/^\[.*\]$/,os=/:(.*)$/,ls=/^:|^\.|^v-bind:/,us=/\.[^.\]]+(?=[^\]]*$)/g,ds=/^v-slot(:|$)|^#/,ps=/[\r\n]/,cs=/[ \f\t\r\n]+/g,ys=g((function(e){return(Tr=Tr||document.createElement("div")).innerHTML=e,Tr.textContent})),fs="_empty_";function ms(e,t,n){return{type:1,tag:e,attrsList:t,attrsMap:ws(t),rawAttrsMap:{},parent:n,children:[]}}function hs(e,t){var n;!function(e){var t=Da(e,"key");t&&(e.key=t)}(e),e.plain=!e.key&&!e.scopedSlots&&!e.attrsList.length,function(e){var t=Da(e,"ref");t&&(e.ref=t,e.refInFor=function(e){for(var t=e;t;){if(void 0!==t.for)return!0;t=t.parent}return!1}(e))}(e),function(e){var t;"template"===e.tag?(t=Ua(e,"scope"),e.slotScope=t||Ua(e,"slot-scope")):(t=Ua(e,"slot-scope"))&&(e.slotScope=t);var n=Da(e,"slot");if(n&&(e.slotTarget='""'===n?'"default"':n,e.slotTargetDynamic=!(!e.attrsMap[":slot"]&&!e.attrsMap["v-bind:slot"]),"template"===e.tag||e.slotScope||ja(e,"slot",n,function(e,t){return e.rawAttrsMap[":"+t]||e.rawAttrsMap["v-bind:"+t]||e.rawAttrsMap[t]}(e,"slot"))),"template"===e.tag){var a=za(e,ds);if(a){var i=gs(a),r=i.name,s=i.dynamic;e.slotTarget=r,e.slotTargetDynamic=s,e.slotScope=a.value||fs}}else{var o=za(e,ds);if(o){var l=e.scopedSlots||(e.scopedSlots={}),u=gs(o),d=u.name,p=u.dynamic,c=l[d]=ms("template",[],e);c.slotTarget=d,c.slotTargetDynamic=p,c.children=e.children.filter((function(e){if(!e.slotScope)return e.parent=c,!0})),c.slotScope=o.value||fs,e.children=[],e.plain=!1}}}(e),"slot"===(n=e).tag&&(n.slotName=Da(n,"name")),function(e){var t;(t=Da(e,"is"))&&(e.component=t),null!=Ua(e,"inline-template")&&(e.inlineTemplate=!0)}(e);for(var a=0;a-1"+("true"===r?":("+t+")":":_q("+t+","+r+")")),Ba(e,"change","var $$a="+t+",$$el=$event.target,$$c=$$el.checked?("+r+"):("+s+");if(Array.isArray($$a)){var $$v="+(a?"_n("+i+")":i)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+Ga(t,"$$a.concat([$$v])")+")}else{$$i>-1&&("+Ga(t,"$$a.slice(0,$$i).concat($$a.slice($$i+1))")+")}}else{"+Ga(t,"$$c")+"}",null,!0)}(e,a,i);else if("input"===r&&"radio"===s)!function(e,t,n){var a=n&&n.number,i=Da(e,"value")||"null";Pa(e,"checked","_q("+t+","+(i=a?"_n("+i+")":i)+")"),Ba(e,"change",Ga(t,i),null,!0)}(e,a,i);else if("input"===r||"textarea"===r)!function(e,t,n){var a=e.attrsMap.type,i=n||{},r=i.lazy,s=i.number,o=i.trim,l=!r&&"range"!==a,u=r?"change":"range"===a?ei:"input",d="$event.target.value";o&&(d="$event.target.value.trim()"),s&&(d="_n("+d+")");var p=Ga(t,d);l&&(p="if($event.target.composing)return;"+p),Pa(e,"value","("+t+")"),Ba(e,u,p,null,!0),(o||s)&&Ba(e,"blur","$forceUpdate()")}(e,a,i);else if(!H.isReservedTag(r))return Wa(e,a,i),!1;return!0},text:function(e,t){t.value&&Pa(e,"textContent","_s("+t.value+")",t)},html:function(e,t){t.value&&Pa(e,"innerHTML","_s("+t.value+")",t)}},Os={expectHTML:!0,modules:Es,directives:Rs,isPreTag:function(e){return"pre"===e},isUnaryTag:xr,mustUseProp:Vn,canBeLeftOpenTag:Ar,isReservedTag:ea,getTagNamespace:ta,staticKeys:(As=Es,As.reduce((function(e,t){return e.concat(t.staticKeys||[])}),[]).join(","))},Ms=g((function(e){return y("type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap"+(e?","+e:""))}));function Ss(e,t){e&&(_s=Ms(t.staticKeys||""),xs=t.isReservedTag||O,$s(e),Ls(e,!1))}function $s(e){if(e.static=function(e){return 2!==e.type&&(3===e.type||!(!e.pre&&(e.hasBindings||e.if||e.for||f(e.tag)||!xs(e.tag)||function(e){for(;e.parent;){if("template"!==(e=e.parent).tag)return!1;if(e.for)return!0}return!1}(e)||!Object.keys(e).every(_s))))}(e),1===e.type){if(!xs(e.tag)&&"slot"!==e.tag&&null==e.attrsMap["inline-template"])return;for(var t=0,n=e.children.length;t|^function(?:\s+[\w$]+)?\s*\(/,Ps=/\([^)]*?\);*$/,js=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,Hs={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},Vs={esc:["Esc","Escape"],tab:"Tab",enter:"Enter",space:[" ","Spacebar"],up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete","Del"]},Ns=function(e){return"if("+e+")return null;"},Bs={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:Ns("$event.target !== $event.currentTarget"),ctrl:Ns("!$event.ctrlKey"),shift:Ns("!$event.shiftKey"),alt:Ns("!$event.altKey"),meta:Ns("!$event.metaKey"),left:Ns("'button' in $event && $event.button !== 0"),middle:Ns("'button' in $event && $event.button !== 1"),right:Ns("'button' in $event && $event.button !== 2")};function Ds(e,t){var n=t?"nativeOn:":"on:",a="",i="";for(var r in e){var s=Us(e[r]);e[r]&&e[r].dynamic?i+=r+","+s+",":a+='"'+r+'":'+s+","}return a="{"+a.slice(0,-1)+"}",i?n+"_d("+a+",["+i.slice(0,-1)+"])":n+a}function Us(e){if(!e)return"function(){}";if(Array.isArray(e))return"["+e.map((function(e){return Us(e)})).join(",")+"]";var t=js.test(e.value),n=Fs.test(e.value),a=js.test(e.value.replace(Ps,""));if(e.modifiers){var i="",r="",s=[];for(var o in e.modifiers)if(Bs[o])r+=Bs[o],Hs[o]&&s.push(o);else if("exact"===o){var l=e.modifiers;r+=Ns(["ctrl","shift","alt","meta"].filter((function(e){return!l[e]})).map((function(e){return"$event."+e+"Key"})).join("||"))}else s.push(o);return s.length&&(i+=function(e){return"if(!$event.type.indexOf('key')&&"+e.map(zs).join("&&")+")return null;"}(s)),r&&(i+=r),"function($event){"+i+(t?"return "+e.value+".apply(null, arguments)":n?"return ("+e.value+").apply(null, arguments)":a?"return "+e.value:e.value)+"}"}return t||n?e.value:"function($event){"+(a?"return "+e.value:e.value)+"}"}function zs(e){var t=parseInt(e,10);if(t)return"$event.keyCode!=="+t;var n=Hs[e],a=Vs[e];return"_k($event.keyCode,"+JSON.stringify(e)+","+JSON.stringify(n)+",$event.key,"+JSON.stringify(a)+")"}var qs={on:function(e,t){e.wrapListeners=function(e){return"_g("+e+","+t.value+")"}},bind:function(e,t){e.wrapData=function(n){return"_b("+n+",'"+e.tag+"',"+t.value+","+(t.modifiers&&t.modifiers.prop?"true":"false")+(t.modifiers&&t.modifiers.sync?",true":"")+")"}},cloak:R},Ws=function(e){this.options=e,this.warn=e.warn||La,this.transforms=Fa(e.modules,"transformCode"),this.dataGenFns=Fa(e.modules,"genData"),this.directives=A(A({},qs),e.directives);var t=e.isReservedTag||O;this.maybeComponent=function(e){return!!e.component||!t(e.tag)},this.onceId=0,this.staticRenderFns=[],this.pre=!1};function Gs(e,t){var n=new Ws(t);return{render:"with(this){return "+(e?"script"===e.tag?"null":Js(e,n):'_c("div")')+"}",staticRenderFns:n.staticRenderFns}}function Js(e,t){if(e.parent&&(e.pre=e.pre||e.parent.pre),e.staticRoot&&!e.staticProcessed)return Ks(e,t);if(e.once&&!e.onceProcessed)return Zs(e,t);if(e.for&&!e.forProcessed)return Qs(e,t);if(e.if&&!e.ifProcessed)return Xs(e,t);if("template"!==e.tag||e.slotTarget||t.pre){if("slot"===e.tag)return function(e,t){var n=e.slotName||'"default"',a=ao(e,t),i="_t("+n+(a?",function(){return "+a+"}":""),r=e.attrs||e.dynamicAttrs?so((e.attrs||[]).concat(e.dynamicAttrs||[]).map((function(e){return{name:w(e.name),value:e.value,dynamic:e.dynamic}}))):null,s=e.attrsMap["v-bind"];return!r&&!s||a||(i+=",null"),r&&(i+=","+r),s&&(i+=(r?"":",null")+","+s),i+")"}(e,t);var n;if(e.component)n=function(e,t,n){var a=t.inlineTemplate?null:ao(t,n,!0);return"_c("+e+","+eo(t,n)+(a?","+a:"")+")"}(e.component,e,t);else{var a;(!e.plain||e.pre&&t.maybeComponent(e))&&(a=eo(e,t));var i=e.inlineTemplate?null:ao(e,t,!0);n="_c('"+e.tag+"'"+(a?","+a:"")+(i?","+i:"")+")"}for(var r=0;r>>0}(s):"")+")"}(e,e.scopedSlots,t)+","),e.model&&(n+="model:{value:"+e.model.value+",callback:"+e.model.callback+",expression:"+e.model.expression+"},"),e.inlineTemplate){var r=function(e,t){var n=e.children[0];if(n&&1===n.type){var a=Gs(n,t.options);return"inlineTemplate:{render:function(){"+a.render+"},staticRenderFns:["+a.staticRenderFns.map((function(e){return"function(){"+e+"}"})).join(",")+"]}"}}(e,t);r&&(n+=r+",")}return n=n.replace(/,$/,"")+"}",e.dynamicAttrs&&(n="_b("+n+',"'+e.tag+'",'+so(e.dynamicAttrs)+")"),e.wrapData&&(n=e.wrapData(n)),e.wrapListeners&&(n=e.wrapListeners(n)),n}function to(e){return 1===e.type&&("slot"===e.tag||e.children.some(to))}function no(e,t){var n=e.attrsMap["slot-scope"];if(e.if&&!e.ifProcessed&&!n)return Xs(e,t,no,"null");if(e.for&&!e.forProcessed)return Qs(e,t,no);var a=e.slotScope===fs?"":String(e.slotScope),i="function("+a+"){return "+("template"===e.tag?e.if&&n?"("+e.if+")?"+(ao(e,t)||"undefined")+":undefined":ao(e,t)||"undefined":Js(e,t))+"}",r=a?"":",proxy:true";return"{key:"+(e.slotTarget||'"default"')+",fn:"+i+r+"}"}function ao(e,t,n,a,i){var r=e.children;if(r.length){var s=r[0];if(1===r.length&&s.for&&"template"!==s.tag&&"slot"!==s.tag){var o=n?t.maybeComponent(s)?",1":",0":"";return""+(a||Js)(s,t)+o}var l=n?function(e,t){for(var n=0,a=0;a]*>)","i")),c=e.replace(p,(function(e,n,a){return u=a.length,Vr(d)||"noscript"===d||(n=n.replace(//g,"$1").replace(//g,"$1")),qr(d,n)&&(n=n.slice(1)),t.chars&&t.chars(n),""}));l+=e.length-c.length,e=c,x(d,l-u,l)}else{var y=e.indexOf("<");if(0===y){if(jr.test(e)){var f=e.indexOf("--\x3e");if(f>=0){t.shouldKeepComment&&t.comment(e.substring(4,f),l,l+f+3),C(f+3);continue}}if(Hr.test(e)){var m=e.indexOf("]>");if(m>=0){C(m+2);continue}}var h=e.match(Pr);if(h){C(h[0].length);continue}var v=e.match(Fr);if(v){var b=l;C(v[0].length),x(v[1],b,l);continue}var g=I();if(g){_(g),qr(g.tagName,e)&&C(1);continue}}var T=void 0,w=void 0,k=void 0;if(y>=0){for(w=e.slice(y);!(Fr.test(w)||$r.test(w)||jr.test(w)||Hr.test(w)||(k=w.indexOf("<",1))<0);)y+=k,w=e.slice(y);T=e.substring(0,y)}y<0&&(T=e),T&&C(T.length),t.chars&&T&&t.chars(T,l-T.length,l)}if(e===n){t.chars&&t.chars(e);break}}function C(t){l+=t,e=e.substring(t)}function I(){var t=e.match($r);if(t){var n,a,i={tagName:t[1],attrs:[],start:l};for(C(t[0].length);!(n=e.match(Lr))&&(a=e.match(Or)||e.match(Rr));)a.start=l,C(a[0].length),a.end=l,i.attrs.push(a);if(n)return i.unarySlash=n[1],C(n[0].length),i.end=l,i}}function _(e){var n=e.tagName,l=e.unarySlash;r&&("p"===a&&Er(n)&&x(a),o(n)&&a===n&&x(n));for(var u=s(n)||!!l,d=e.attrs.length,p=new Array(d),c=0;c=0&&i[s].lowerCasedTag!==o;s--);else s=0;if(s>=0){for(var u=i.length-1;u>=s;u--)t.end&&t.end(i[u].tag,n,r);i.length=s,a=s&&i[s-1].tag}else"br"===o?t.start&&t.start(e,[],!0,n,r):"p"===o&&(t.start&&t.start(e,[],!1,n,r),t.end&&t.end(e,n,r))}x()}(e,{warn:Gr,expectHTML:t.expectHTML,isUnaryTag:t.isUnaryTag,canBeLeftOpenTag:t.canBeLeftOpenTag,shouldDecodeNewlines:t.shouldDecodeNewlines,shouldDecodeNewlinesForHref:t.shouldDecodeNewlinesForHref,shouldKeepComment:t.comments,outputSourceRange:t.outputSourceRange,start:function(e,r,s,d,p){var c=a&&a.ns||es(e);K&&"svg"===c&&(r=function(e){for(var t=[],n=0;nl&&(o.push(r=e.slice(l,i)),s.push(JSON.stringify(r)));var u=Sa(a[1].trim());s.push("_s("+u+")"),o.push({"@binding":u}),l=i+a[0].length}return l':'
',co.innerHTML.indexOf(" ")>0}var vo=!!q&&ho(!1),bo=!!q&&ho(!0),go=g((function(e){var t=ia(e);return t&&t.innerHTML})),To=Rn.prototype.$mount;Rn.prototype.$mount=function(e,t){if((e=e&&ia(e))===document.body||e===document.documentElement)return this;var n=this.$options;if(!n.render){var a=n.template;if(a)if("string"==typeof a)"#"===a.charAt(0)&&(a=go(a));else{if(!a.nodeType)return this;a=a.innerHTML}else e&&(a=function(e){if(e.outerHTML)return e.outerHTML;var t=document.createElement("div");return t.appendChild(e.cloneNode(!0)),t.innerHTML}(e));if(a){var i=mo(a,{outputSourceRange:!1,shouldDecodeNewlines:vo,shouldDecodeNewlinesForHref:bo,delimiters:n.delimiters,comments:n.comments},this),r=i.render,s=i.staticRenderFns;n.render=r,n.staticRenderFns=s}}return To.call(this,e,t)},Rn.compile=mo;const wo=Rn;function ko(e,t){for(var n in t)e[n]=t[n];return e}var Co=/[!'()*]/g,Io=function(e){return"%"+e.charCodeAt(0).toString(16)},_o=/%2C/g,xo=function(e){return encodeURIComponent(e).replace(Co,Io).replace(_o,",")};function Ao(e){try{return decodeURIComponent(e)}catch(e){}return e}var Eo=function(e){return null==e||"object"==typeof e?e:String(e)};function Ro(e){var t={};return(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var n=e.replace(/\+/g," ").split("="),a=Ao(n.shift()),i=n.length>0?Ao(n.join("=")):null;void 0===t[a]?t[a]=i:Array.isArray(t[a])?t[a].push(i):t[a]=[t[a],i]})),t):t}function Oo(e){var t=e?Object.keys(e).map((function(t){var n=e[t];if(void 0===n)return"";if(null===n)return xo(t);if(Array.isArray(n)){var a=[];return n.forEach((function(e){void 0!==e&&(null===e?a.push(xo(t)):a.push(xo(t)+"="+xo(e)))})),a.join("&")}return xo(t)+"="+xo(n)})).filter((function(e){return e.length>0})).join("&"):null;return t?"?"+t:""}var Mo=/\/?$/;function So(e,t,n,a){var i=a&&a.options.stringifyQuery,r=t.query||{};try{r=$o(r)}catch(e){}var s={name:t.name||e&&e.name,meta:e&&e.meta||{},path:t.path||"/",hash:t.hash||"",query:r,params:t.params||{},fullPath:Po(t,i),matched:e?Fo(e):[]};return n&&(s.redirectedFrom=Po(n,i)),Object.freeze(s)}function $o(e){if(Array.isArray(e))return e.map($o);if(e&&"object"==typeof e){var t={};for(var n in e)t[n]=$o(e[n]);return t}return e}var Lo=So(null,{path:"/"});function Fo(e){for(var t=[];e;)t.unshift(e),e=e.parent;return t}function Po(e,t){var n=e.path,a=e.query;void 0===a&&(a={});var i=e.hash;return void 0===i&&(i=""),(n||"/")+(t||Oo)(a)+i}function jo(e,t,n){return t===Lo?e===t:!!t&&(e.path&&t.path?e.path.replace(Mo,"")===t.path.replace(Mo,"")&&(n||e.hash===t.hash&&Ho(e.query,t.query)):!(!e.name||!t.name)&&e.name===t.name&&(n||e.hash===t.hash&&Ho(e.query,t.query)&&Ho(e.params,t.params)))}function Ho(e,t){if(void 0===e&&(e={}),void 0===t&&(t={}),!e||!t)return e===t;var n=Object.keys(e).sort(),a=Object.keys(t).sort();return n.length===a.length&&n.every((function(n,i){var r=e[n];if(a[i]!==n)return!1;var s=t[n];return null==r||null==s?r===s:"object"==typeof r&&"object"==typeof s?Ho(r,s):String(r)===String(s)}))}function Vo(e){for(var t=0;t=0&&(t=e.slice(a),e=e.slice(0,a));var i=e.indexOf("?");return i>=0&&(n=e.slice(i+1),e=e.slice(0,i)),{path:e,query:n,hash:t}}(i.path||""),u=t&&t.path||"/",d=l.path?Do(l.path,u,n||i.append):u,p=function(e,t,n){void 0===t&&(t={});var a,i=n||Ro;try{a=i(e||"")}catch(e){a={}}for(var r in t){var s=t[r];a[r]=Array.isArray(s)?s.map(Eo):Eo(s)}return a}(l.query,i.query,a&&a.options.parseQuery),c=i.hash||l.hash;return c&&"#"!==c.charAt(0)&&(c="#"+c),{_normalized:!0,path:d,query:p,hash:c}}var ll,ul=function(){},dl={name:"RouterLink",props:{to:{type:[String,Object],required:!0},tag:{type:String,default:"a"},custom:Boolean,exact:Boolean,exactPath:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,ariaCurrentValue:{type:String,default:"page"},event:{type:[String,Array],default:"click"}},render:function(e){var t=this,n=this.$router,a=this.$route,i=n.resolve(this.to,a,this.append),r=i.location,s=i.route,o=i.href,l={},u=n.options.linkActiveClass,d=n.options.linkExactActiveClass,p=null==u?"router-link-active":u,c=null==d?"router-link-exact-active":d,y=null==this.activeClass?p:this.activeClass,f=null==this.exactActiveClass?c:this.exactActiveClass,m=s.redirectedFrom?So(null,ol(s.redirectedFrom),null,n):s;l[f]=jo(a,m,this.exactPath),l[y]=this.exact||this.exactPath?l[f]:function(e,t){return 0===e.path.replace(Mo,"/").indexOf(t.path.replace(Mo,"/"))&&(!t.hash||e.hash===t.hash)&&function(e,t){for(var n in t)if(!(n in e))return!1;return!0}(e.query,t.query)}(a,m);var h=l[f]?this.ariaCurrentValue:null,v=function(e){pl(e)&&(t.replace?n.replace(r,ul):n.push(r,ul))},b={click:pl};Array.isArray(this.event)?this.event.forEach((function(e){b[e]=v})):b[this.event]=v;var g={class:l},T=!this.$scopedSlots.$hasNormal&&this.$scopedSlots.default&&this.$scopedSlots.default({href:o,route:s,navigate:v,isActive:l[y],isExactActive:l[f]});if(T){if(1===T.length)return T[0];if(T.length>1||!T.length)return 0===T.length?e():e("span",{},T)}if("a"===this.tag)g.on=b,g.attrs={href:o,"aria-current":h};else{var w=cl(this.$slots.default);if(w){w.isStatic=!1;var k=w.data=ko({},w.data);for(var C in k.on=k.on||{},k.on){var I=k.on[C];C in b&&(k.on[C]=Array.isArray(I)?I:[I])}for(var _ in b)_ in k.on?k.on[_].push(b[_]):k.on[_]=v;var x=w.data.attrs=ko({},w.data.attrs);x.href=o,x["aria-current"]=h}else g.on=b}return e(this.tag,g,this.$slots.default)}};function pl(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey||e.defaultPrevented||void 0!==e.button&&0!==e.button)){if(e.currentTarget&&e.currentTarget.getAttribute){var t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function cl(e){if(e)for(var t,n=0;n-1&&(l.params[c]=n.params[c]);return l.path=sl(d.path,l.params),o(d,l,s)}if(l.path){l.params={};for(var y=0;y=e.length?n():e[i]?t(e[i],(function(){a(i+1)})):a(i+1)};a(0)}var Vl={redirected:2,aborted:4,cancelled:8,duplicated:16};function Nl(e,t){return Bl(e,t,Vl.cancelled,'Navigation cancelled from "'+e.fullPath+'" to "'+t.fullPath+'" with a new navigation.')}function Bl(e,t,n,a){var i=new Error(a);return i._isRouter=!0,i.from=e,i.to=t,i.type=n,i}var Dl=["params","query","hash"];function Ul(e){return Object.prototype.toString.call(e).indexOf("Error")>-1}function zl(e,t){return Ul(e)&&e._isRouter&&(null==t||e.type===t)}function ql(e,t){return Wl(e.map((function(e){return Object.keys(e.components).map((function(n){return t(e.components[n],e.instances[n],e,n)}))})))}function Wl(e){return Array.prototype.concat.apply([],e)}var Gl="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag;function Jl(e){var t=!1;return function(){for(var n=[],a=arguments.length;a--;)n[a]=arguments[a];if(!t)return t=!0,e.apply(this,n)}}var Kl=function(e,t){this.router=e,this.base=function(e){if(!e)if(yl){var t=document.querySelector("base");e=(e=t&&t.getAttribute("href")||"/").replace(/^https?:\/\/[^\/]+/,"")}else e="/";return"/"!==e.charAt(0)&&(e="/"+e),e.replace(/\/$/,"")}(t),this.current=Lo,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[],this.listeners=[]};function Zl(e,t,n,a){var i=ql(e,(function(e,a,i,r){var s=function(e,t){return"function"!=typeof e&&(e=ll.extend(e)),e.options[t]}(e,t);if(s)return Array.isArray(s)?s.map((function(e){return n(e,a,i,r)})):n(s,a,i,r)}));return Wl(a?i.reverse():i)}function Xl(e,t){if(t)return function(){return e.apply(t,arguments)}}Kl.prototype.listen=function(e){this.cb=e},Kl.prototype.onReady=function(e,t){this.ready?e():(this.readyCbs.push(e),t&&this.readyErrorCbs.push(t))},Kl.prototype.onError=function(e){this.errorCbs.push(e)},Kl.prototype.transitionTo=function(e,t,n){var a,i=this;try{a=this.router.match(e,this.current)}catch(e){throw this.errorCbs.forEach((function(t){t(e)})),e}var r=this.current;this.confirmTransition(a,(function(){i.updateRoute(a),t&&t(a),i.ensureURL(),i.router.afterHooks.forEach((function(e){e&&e(a,r)})),i.ready||(i.ready=!0,i.readyCbs.forEach((function(e){e(a)})))}),(function(e){n&&n(e),e&&!i.ready&&(zl(e,Vl.redirected)&&r===Lo||(i.ready=!0,i.readyErrorCbs.forEach((function(t){t(e)}))))}))},Kl.prototype.confirmTransition=function(e,t,n){var a=this,i=this.current;this.pending=e;var r,s,o=function(e){!zl(e)&&Ul(e)&&(a.errorCbs.length?a.errorCbs.forEach((function(t){t(e)})):console.error(e)),n&&n(e)},l=e.matched.length-1,u=i.matched.length-1;if(jo(e,i)&&l===u&&e.matched[l]===i.matched[u])return this.ensureURL(),e.hash&&xl(this.router,i,e,!1),o(((s=Bl(r=i,e,Vl.duplicated,'Avoided redundant navigation to current location: "'+r.fullPath+'".')).name="NavigationDuplicated",s));var d,p=function(e,t){var n,a=Math.max(e.length,t.length);for(n=0;n0)){var t=this.router,n=t.options.scrollBehavior,a=Fl&&n;a&&this.listeners.push(_l());var i=function(){var n=e.current,i=Ql(e.base);e.current===Lo&&i===e._startLocation||e.transitionTo(i,(function(e){a&&xl(t,e,n,!0)}))};window.addEventListener("popstate",i),this.listeners.push((function(){window.removeEventListener("popstate",i)}))}},t.prototype.go=function(e){window.history.go(e)},t.prototype.push=function(e,t,n){var a=this,i=this.current;this.transitionTo(e,(function(e){Pl(Uo(a.base+e.fullPath)),xl(a.router,e,i,!1),t&&t(e)}),n)},t.prototype.replace=function(e,t,n){var a=this,i=this.current;this.transitionTo(e,(function(e){jl(Uo(a.base+e.fullPath)),xl(a.router,e,i,!1),t&&t(e)}),n)},t.prototype.ensureURL=function(e){if(Ql(this.base)!==this.current.fullPath){var t=Uo(this.base+this.current.fullPath);e?Pl(t):jl(t)}},t.prototype.getCurrentLocation=function(){return Ql(this.base)},t}(Kl);function Ql(e){var t=window.location.pathname,n=t.toLowerCase(),a=e.toLowerCase();return!e||n!==a&&0!==n.indexOf(Uo(a+"/"))||(t=t.slice(e.length)),(t||"/")+window.location.search+window.location.hash}var eu=function(e){function t(t,n,a){e.call(this,t,n),a&&function(e){var t=Ql(e);if(!/^\/#/.test(t))return window.location.replace(Uo(e+"/#"+t)),!0}(this.base)||tu()}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.setupListeners=function(){var e=this;if(!(this.listeners.length>0)){var t=this.router.options.scrollBehavior,n=Fl&&t;n&&this.listeners.push(_l());var a=function(){var t=e.current;tu()&&e.transitionTo(nu(),(function(a){n&&xl(e.router,a,t,!0),Fl||ru(a.fullPath)}))},i=Fl?"popstate":"hashchange";window.addEventListener(i,a),this.listeners.push((function(){window.removeEventListener(i,a)}))}},t.prototype.push=function(e,t,n){var a=this,i=this.current;this.transitionTo(e,(function(e){iu(e.fullPath),xl(a.router,e,i,!1),t&&t(e)}),n)},t.prototype.replace=function(e,t,n){var a=this,i=this.current;this.transitionTo(e,(function(e){ru(e.fullPath),xl(a.router,e,i,!1),t&&t(e)}),n)},t.prototype.go=function(e){window.history.go(e)},t.prototype.ensureURL=function(e){var t=this.current.fullPath;nu()!==t&&(e?iu(t):ru(t))},t.prototype.getCurrentLocation=function(){return nu()},t}(Kl);function tu(){var e=nu();return"/"===e.charAt(0)||(ru("/"+e),!1)}function nu(){var e=window.location.href,t=e.indexOf("#");return t<0?"":e=e.slice(t+1)}function au(e){var t=window.location.href,n=t.indexOf("#");return(n>=0?t.slice(0,n):t)+"#"+e}function iu(e){Fl?Pl(au(e)):window.location.hash=e}function ru(e){Fl?jl(au(e)):window.location.replace(au(e))}var su=function(e){function t(t,n){e.call(this,t,n),this.stack=[],this.index=-1}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.push=function(e,t,n){var a=this;this.transitionTo(e,(function(e){a.stack=a.stack.slice(0,a.index+1).concat(e),a.index++,t&&t(e)}),n)},t.prototype.replace=function(e,t,n){var a=this;this.transitionTo(e,(function(e){a.stack=a.stack.slice(0,a.index).concat(e),t&&t(e)}),n)},t.prototype.go=function(e){var t=this,n=this.index+e;if(!(n<0||n>=this.stack.length)){var a=this.stack[n];this.confirmTransition(a,(function(){var e=t.current;t.index=n,t.updateRoute(a),t.router.afterHooks.forEach((function(t){t&&t(a,e)}))}),(function(e){zl(e,Vl.duplicated)&&(t.index=n)}))}},t.prototype.getCurrentLocation=function(){var e=this.stack[this.stack.length-1];return e?e.fullPath:"/"},t.prototype.ensureURL=function(){},t}(Kl),ou=function(e){void 0===e&&(e={}),this.app=null,this.apps=[],this.options=e,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=vl(e.routes||[],this);var t=e.mode||"hash";switch(this.fallback="history"===t&&!Fl&&!1!==e.fallback,this.fallback&&(t="hash"),yl||(t="abstract"),this.mode=t,t){case"history":this.history=new Yl(this,e.base);break;case"hash":this.history=new eu(this,e.base,this.fallback);break;case"abstract":this.history=new su(this,e.base)}},lu={currentRoute:{configurable:!0}};function uu(e,t){return e.push(t),function(){var n=e.indexOf(t);n>-1&&e.splice(n,1)}}ou.prototype.match=function(e,t,n){return this.matcher.match(e,t,n)},lu.currentRoute.get=function(){return this.history&&this.history.current},ou.prototype.init=function(e){var t=this;if(this.apps.push(e),e.$once("hook:destroyed",(function(){var n=t.apps.indexOf(e);n>-1&&t.apps.splice(n,1),t.app===e&&(t.app=t.apps[0]||null),t.app||t.history.teardown()})),!this.app){this.app=e;var n=this.history;if(n instanceof Yl||n instanceof eu){var a=function(e){n.setupListeners(),function(e){var a=n.current,i=t.options.scrollBehavior;Fl&&i&&"fullPath"in e&&xl(t,e,a,!1)}(e)};n.transitionTo(n.getCurrentLocation(),a,a)}n.listen((function(e){t.apps.forEach((function(t){t._route=e}))}))}},ou.prototype.beforeEach=function(e){return uu(this.beforeHooks,e)},ou.prototype.beforeResolve=function(e){return uu(this.resolveHooks,e)},ou.prototype.afterEach=function(e){return uu(this.afterHooks,e)},ou.prototype.onReady=function(e,t){this.history.onReady(e,t)},ou.prototype.onError=function(e){this.history.onError(e)},ou.prototype.push=function(e,t,n){var a=this;if(!t&&!n&&"undefined"!=typeof Promise)return new Promise((function(t,n){a.history.push(e,t,n)}));this.history.push(e,t,n)},ou.prototype.replace=function(e,t,n){var a=this;if(!t&&!n&&"undefined"!=typeof Promise)return new Promise((function(t,n){a.history.replace(e,t,n)}));this.history.replace(e,t,n)},ou.prototype.go=function(e){this.history.go(e)},ou.prototype.back=function(){this.go(-1)},ou.prototype.forward=function(){this.go(1)},ou.prototype.getMatchedComponents=function(e){var t=e?e.matched?e:this.resolve(e).route:this.currentRoute;return t?[].concat.apply([],t.matched.map((function(e){return Object.keys(e.components).map((function(t){return e.components[t]}))}))):[]},ou.prototype.resolve=function(e,t,n){var a=ol(e,t=t||this.history.current,n,this),i=this.match(a,t),r=i.redirectedFrom||i.fullPath,s=function(e,t,n){var a="hash"===n?"#"+t:t;return e?Uo(e+"/"+a):a}(this.history.base,r,this.mode);return{location:a,route:i,href:s,normalizedTo:a,resolved:i}},ou.prototype.getRoutes=function(){return this.matcher.getRoutes()},ou.prototype.addRoute=function(e,t){this.matcher.addRoute(e,t),this.history.current!==Lo&&this.history.transitionTo(this.history.getCurrentLocation())},ou.prototype.addRoutes=function(e){this.matcher.addRoutes(e),this.history.current!==Lo&&this.history.transitionTo(this.history.getCurrentLocation())},Object.defineProperties(ou.prototype,lu),ou.install=function e(t){if(!e.installed||ll!==t){e.installed=!0,ll=t;var n=function(e){return void 0!==e},a=function(e,t){var a=e.$options._parentVnode;n(a)&&n(a=a.data)&&n(a=a.registerRouteInstance)&&a(e,t)};t.mixin({beforeCreate:function(){n(this.$options.router)?(this._routerRoot=this,this._router=this.$options.router,this._router.init(this),t.util.defineReactive(this,"_route",this._router.history.current)):this._routerRoot=this.$parent&&this.$parent._routerRoot||this,a(this,this)},destroyed:function(){a(this)}}),Object.defineProperty(t.prototype,"$router",{get:function(){return this._routerRoot._router}}),Object.defineProperty(t.prototype,"$route",{get:function(){return this._routerRoot._route}}),t.component("RouterView",No),t.component("RouterLink",dl);var i=t.config.optionMergeStrategies;i.beforeRouteEnter=i.beforeRouteLeave=i.beforeRouteUpdate=i.created}},ou.version="3.5.4",ou.isNavigationFailure=zl,ou.NavigationFailureType=Vl,ou.START_LOCATION=Lo,yl&&window.Vue&&window.Vue.use(ou);const du=ou;var pu=function(){var e=this.$createElement,t=this._self._c||e;return t("div",{staticClass:"min-h-screen bg-gray-100 px-4 pt-6"},[t("router-view")],1)};function cu(e,t,n,a,i,r,s,o){var l,u="function"==typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=n,u._compiled=!0),a&&(u.functional=!0),r&&(u._scopeId="data-v-"+r),s?(l=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),i&&i.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(s)},u._ssrRegister=l):i&&(l=o?function(){i.call(this,(u.functional?this.parent:this).$root.$options.shadowRoot)}:i),l)if(u.functional){u._injectStyles=l;var d=u.render;u.render=function(e,t){return l.call(t),d(e,t)}}else{var p=u.beforeCreate;u.beforeCreate=p?[].concat(p,l):[l]}return{exports:e,options:u}}pu._withStripped=!0,n(387);var yu=cu({},pu,[],!1,null,null,null);yu.options.__file="node_modules/hardhat-docgen/src/App.vue";const fu=yu.exports;var mu=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"w-full space-y-10 md:max-w-screen-sm lg:max-w-screen-md mx-auto"},[n("HeaderBar"),e._v(" "),n("div",{staticClass:"pb-32"},[n("div",{staticClass:"space-y-4"},[n("span",{staticClass:"text-lg"},[e._v("\n "+e._s(e.json.source)+"\n ")]),e._v(" "),n("h1",{staticClass:"text-xl"},[e._v("\n "+e._s(e.json.name)+"\n ")]),e._v(" "),n("h2",{staticClass:"text-lg"},[e._v("\n "+e._s(e.json.title)+"\n ")]),e._v(" "),n("h2",{staticClass:"text-lg"},[e._v("\n "+e._s(e.json.author)+"\n ")]),e._v(" "),n("p",[e._v(e._s(e.json.notice))]),e._v(" "),n("p",[e._v(e._s(e.json.details))])]),e._v(" "),n("div",{staticClass:"mt-8"},[e.json.hasOwnProperty("constructor")?n("Member",{attrs:{json:e.json.constructor}}):e._e()],1),e._v(" "),n("div",{staticClass:"mt-8"},[e.json.receive?n("Member",{attrs:{json:e.json.receive}}):e._e()],1),e._v(" "),n("div",{staticClass:"mt-8"},[e.json.fallback?n("Member",{attrs:{json:e.json.fallback}}):e._e()],1),e._v(" "),e.json.events?n("MemberSet",{attrs:{title:"Events",json:e.json.events}}):e._e(),e._v(" "),e.json.stateVariables?n("MemberSet",{attrs:{title:"State Variables",json:e.json.stateVariables}}):e._e(),e._v(" "),e.json.methods?n("MemberSet",{attrs:{title:"Methods",json:e.json.methods}}):e._e()],1),e._v(" "),n("FooterBar")],1)};mu._withStripped=!0;var hu=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"bg-gray-100 fixed bottom-0 right-0 w-full border-t border-dashed border-gray-300"},[n("div",{staticClass:"w-full text-center py-2 md:max-w-screen-sm lg:max-w-screen-md mx-auto"},[n("button",{staticClass:"py-1 px-2 text-gray-500",on:{click:function(t){return e.openLink(e.repository)}}},[e._v("\n built with "+e._s(e.name)+"\n ")])])])};hu._withStripped=!0;const vu=JSON.parse('{"u2":"hardhat-docgen","cj":"https://github.com/ItsNickBarry/hardhat-docgen"}');var bu=cu({data:function(){return{repository:vu.cj,name:vu.u2}},methods:{openLink(e){window.open(e,"_blank")}}},hu,[],!1,null,null,null);bu.options.__file="node_modules/hardhat-docgen/src/components/FooterBar.vue";const gu=bu.exports;var Tu=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"w-full border-b border-dashed py-2 border-gray-300"},[n("router-link",{staticClass:"py-2 text-gray-500",attrs:{to:"/"}},[e._v("\n <- Go back\n ")])],1)};Tu._withStripped=!0;var wu=cu({},Tu,[],!1,null,null,null);wu.options.__file="node_modules/hardhat-docgen/src/components/HeaderBar.vue";const ku=wu.exports;var Cu=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"border-2 border-gray-400 border-dashed w-full p-2"},[n("h3",{staticClass:"text-lg pb-2 mb-2 border-b-2 border-gray-400 border-dashed"},[e._v("\n "+e._s(e.name)+" "+e._s(e.keywords)+" "+e._s(e.inputSignature)+"\n ")]),e._v(" "),n("div",{staticClass:"space-y-3"},[n("p",[e._v(e._s(e.json.notice))]),e._v(" "),n("p",[e._v(e._s(e.json.details))]),e._v(" "),n("MemberSection",{attrs:{name:"Parameters",items:e.inputs}}),e._v(" "),n("MemberSection",{attrs:{name:"Return Values",items:e.outputs}})],1)])};Cu._withStripped=!0;var Iu=function(){var e=this,t=e.$createElement,n=e._self._c||t;return e.items.length>0?n("ul",[n("h4",{staticClass:"text-lg"},[e._v("\n "+e._s(e.name)+"\n ")]),e._v(" "),e._l(e.items,(function(t,a){return n("li",{key:a},[n("span",{staticClass:"bg-gray-300"},[e._v(e._s(t.type))]),e._v(" "),n("b",[e._v(e._s(t.name||"_"+a))]),t.desc?n("span",[e._v(": "),n("i",[e._v(e._s(t.desc))])]):e._e()])}))],2):e._e()};Iu._withStripped=!0;var _u=cu({props:{name:{type:String,default:""},items:{type:Array,default:()=>new Array}}},Iu,[],!1,null,null,null);_u.options.__file="node_modules/hardhat-docgen/src/components/MemberSection.vue";const xu={components:{MemberSection:_u.exports},props:{json:{type:Object,default:()=>new Object}},computed:{name:function(){return this.json.name||this.json.type},keywords:function(){let e=[];return this.json.stateMutability&&e.push(this.json.stateMutability),"true"===this.json.anonymous&&e.push("anonymous"),e.join(" ")},params:function(){return this.json.params||{}},returns:function(){return this.json.returns||{}},inputs:function(){return(this.json.inputs||[]).map((e=>({...e,desc:this.params[e.name]})))},inputSignature:function(){return`(${this.inputs.map((e=>e.type)).join(",")})`},outputs:function(){return(this.json.outputs||[]).map(((e,t)=>({...e,desc:this.returns[e.name||`_${t}`]})))},outputSignature:function(){return`(${this.outputs.map((e=>e.type)).join(",")})`}}};var Au=cu(xu,Cu,[],!1,null,null,null);Au.options.__file="node_modules/hardhat-docgen/src/components/Member.vue";const Eu=Au.exports;var Ru=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"w-full mt-8"},[n("h2",{staticClass:"text-lg"},[e._v(e._s(e.title))]),e._v(" "),e._l(Object.keys(e.json),(function(t){return n("Member",{key:t,staticClass:"mt-3",attrs:{json:e.json[t]}})}))],2)};Ru._withStripped=!0;var Ou=cu({components:{Member:Eu},props:{title:{type:String,default:""},json:{type:Object,default:()=>new Object}}},Ru,[],!1,null,null,null);Ou.options.__file="node_modules/hardhat-docgen/src/components/MemberSet.vue";var Mu=cu({components:{Member:Eu,MemberSet:Ou.exports,HeaderBar:ku,FooterBar:gu},props:{json:{type:Object,default:()=>new Object}}},mu,[],!1,null,null,null);Mu.options.__file="node_modules/hardhat-docgen/src/components/Contract.vue";const Su=Mu.exports;var $u=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"w-full space-y-10 md:max-w-screen-sm lg:max-w-screen-md mx-auto pb-32"},[n("Branch",{attrs:{json:e.trees,name:"Sources:"}}),e._v(" "),n("FooterBar",{staticClass:"mt-20"})],1)};$u._withStripped=!0;var Lu=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",[e._v("\n "+e._s(e.name)+"\n "),Array.isArray(e.json)?n("div",{staticClass:"pl-5"},e._l(e.json,(function(t,a){return n("div",{key:a},[n("router-link",{attrs:{to:t.source+":"+t.name}},[e._v("\n "+e._s(t.name)+"\n ")])],1)})),0):n("div",{staticClass:"pl-5"},e._l(Object.keys(e.json),(function(t){return n("div",{key:t},[n("Branch",{attrs:{json:e.json[t],name:t}})],1)})),0)])};Lu._withStripped=!0;var Fu=cu({name:"Branch",props:{name:{type:String,default:null},json:{type:[Object,Array],default:()=>new Object}}},Lu,[],!1,null,null,null);Fu.options.__file="node_modules/hardhat-docgen/src/components/Branch.vue";var Pu=cu({components:{Branch:Fu.exports,FooterBar:gu},props:{json:{type:Object,default:()=>new Object}},computed:{trees:function(){let e={};for(let t in this.json)t.replace("/","//").split(/\/(?=[^\/])/).reduce(function(e,n){if(!n.includes(":"))return e[n]=e[n]||{},e[n];{let[a]=n.split(":");e[a]=e[a]||[],e[a].push(this.json[t])}}.bind(this),e);return e}}},$u,[],!1,null,null,null);Pu.options.__file="node_modules/hardhat-docgen/src/components/Index.vue";const ju=Pu.exports;wo.use(du);const Hu={"src/HookBeaconProxy.sol:HookBeaconProxy":{source:"src/HookBeaconProxy.sol",name:"HookBeaconProxy",title:"HookBeaconProxy a proxy contract that points to an implementation provided by a Beacon",details:"This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}. The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't conflict with the storage layout of the implementation behind the proxy. This is an extension of the OpenZeppelin beacon proxy, however differs in that it is initializeable, which means it is usable with Create2.",constructor:{inputs:[],stateMutability:"nonpayable",type:"constructor"},fallback:{stateMutability:"payable",type:"fallback"},receive:{stateMutability:"payable",type:"receive"},events:{"AdminChanged(address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"previousAdmin",type:"address"},{indexed:!1,internalType:"address",name:"newAdmin",type:"address"}],name:"AdminChanged",type:"event"},"BeaconUpgraded(address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"beacon",type:"address"}],name:"BeaconUpgraded",type:"event"},"Initialized(uint8)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint8",name:"version",type:"uint8"}],name:"Initialized",type:"event",details:"Triggered when the contract has been initialized or reinitialized."},"Upgraded(address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"implementation",type:"address"}],name:"Upgraded",type:"event"}},methods:{"initializeBeacon(address,bytes)":{inputs:[{internalType:"address",name:"beacon",type:"address"},{internalType:"bytes",name:"data",type:"bytes"}],name:"initializeBeacon",outputs:[],stateMutability:"nonpayable",type:"function",details:"Initializes the proxy with `beacon`. If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. Requirements: - `beacon` must be a contract with the interface {IBeacon}."}}},"src/HookCoveredCallFactory.sol:HookCoveredCallFactory":{source:"src/HookCoveredCallFactory.sol",name:"HookCoveredCallFactory",title:"Hook Covered Call Factory",author:"Jake Nyquist-j@hook.xyz",details:"See {IHookCoveredCallFactory}.The factory looks up certain roles by calling the {IHookProtocol} to verify",constructor:{inputs:[{internalType:"address",name:"hookProtocolAddress",type:"address"},{internalType:"address",name:"beaconAddress",type:"address"},{internalType:"address",name:"preApprovedMarketplace",type:"address"}],stateMutability:"nonpayable",type:"constructor"},events:{"CoveredCallInstrumentCreated(address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"assetAddress",type:"address"},{indexed:!1,internalType:"address",name:"instrumentAddress",type:"address"}],name:"CoveredCallInstrumentCreated",type:"event"}},methods:{"ALLOWLISTER_ROLE()":{inputs:[],name:"ALLOWLISTER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the allowlister is able to enable and disable projects to mint instruments"},"CALL_UPGRADER()":{inputs:[],name:"CALL_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the call upgrader role is able to upgrade the implementation of the covered call options"},"COLLECTION_CONF()":{inputs:[],name:"COLLECTION_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the collection configuration role allows the actor to make changes the collection configs on the protocol contract"},"MARKET_CONF()":{inputs:[],name:"MARKET_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the market configuration role allows the actor to make changes to how the market operates"},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the pauser is able to start and pause various components of the protocol"},"VAULT_UPGRADER()":{inputs:[],name:"VAULT_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the vault upgrader role is able to upgrade the implementation for all vaults"},"getCallInstrument(address)":{inputs:[{internalType:"address",name:"",type:"address"}],name:"getCallInstrument",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"Registry of all of the active markets projects with supported call instruments"},"makeCallInstrument(address)":{inputs:[{internalType:"address",name:"assetAddress",type:"address"}],name:"makeCallInstrument",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCallFactory-makeCallInstrument}.Only holders of the ALLOWLISTER_ROLE on the {IHookProtocol} can create these addresses."}}},"src/HookCoveredCallImplV1.sol:HookCoveredCallImplV1":{source:"src/HookCoveredCallImplV1.sol",name:"HookCoveredCallImplV1",title:"HookCoveredCallImplV1 an implementation of covered calls on Hook",author:"Jake Nyquist-j@hook.xyz",details:"In the context of a single call option, the role of the writer is non-transferrable.This contract is intended to be an implementation referenced by a proxy",notice:"See {IHookCoveredCall}.",constructor:{inputs:[],stateMutability:"nonpayable",type:"constructor"},events:{"Approval(address,address,uint256)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"owner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint256",name:"tokenId",type:"uint256"}],name:"Approval",type:"event"},"ApprovalForAll(address,address,bool)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"owner",type:"address"},{indexed:!0,internalType:"address",name:"operator",type:"address"},{indexed:!1,internalType:"bool",name:"approved",type:"bool"}],name:"ApprovalForAll",type:"event"},"Bid(uint256,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"uint256",name:"bidAmount",type:"uint256"},{indexed:!1,internalType:"address",name:"bidder",type:"address"}],name:"Bid",type:"event",notice:"emitted when a call option settlement auction gets and accepts a new bid"},"CallCreated(address,address,uint256,uint256,uint256,uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"writer",type:"address"},{indexed:!1,internalType:"address",name:"vaultAddress",type:"address"},{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"uint256",name:"strikePrice",type:"uint256"},{indexed:!1,internalType:"uint256",name:"expiration",type:"uint256"}],name:"CallCreated",type:"event",notice:"emitted when a new call option is successfully minted with a specific underlying vault"},"CallProceedsDistributed(uint256,address,uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"uint256",name:"amount",type:"uint256"}],name:"CallProceedsDistributed",type:"event",notice:"emitted when an option owner claims their proceeds"},"CallReclaimed(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"}],name:"CallReclaimed",type:"event",notice:"emitted when a call option is reclaimed"},"CallSettled(uint256,bool)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"bool",name:"claimable",type:"bool"}],name:"CallSettled",type:"event",notice:"emitted when a call option is settled"},"ExpiredCallBurned(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"}],name:"ExpiredCallBurned",type:"event",notice:"emitted when a expired call option is burned"},"Initialized(uint8)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint8",name:"version",type:"uint8"}],name:"Initialized",type:"event"},"MarketPauseUpdated(bool)":{anonymous:!1,inputs:[{indexed:!1,internalType:"bool",name:"paused",type:"bool"}],name:"MarketPauseUpdated",type:"event",details:"Emitted when the market is paused or unpaused",params:{paused:"true if paused false otherwise"}},"MinBidIncrementUpdated(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"bidIncrementBips",type:"uint256"}],name:"MinBidIncrementUpdated",type:"event",details:"Emitted when the bid increment is updated",params:{bidIncrementBips:"the new bid increment amount in bips"}},"MinOptionDurationUpdated(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionDuration",type:"uint256"}],name:"MinOptionDurationUpdated",type:"event",details:"emitted when the minimum duration for an option is changed",params:{optionDuration:"new minimum length of an option in seconds."}},"SettlementAuctionStartOffsetUpdated(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"startOffset",type:"uint256"}],name:"SettlementAuctionStartOffsetUpdated",type:"event",details:"emitted when the settlement auction start offset is updated",params:{startOffset:"new number of seconds from expiration when the start offset begins"}},"Transfer(address,address,uint256)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"from",type:"address"},{indexed:!0,internalType:"address",name:"to",type:"address"},{indexed:!0,internalType:"uint256",name:"tokenId",type:"uint256"}],name:"Transfer",type:"event"}},stateVariables:{"allowedUnderlyingAddress()":{inputs:[],name:"allowedUnderlyingAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"stateVariable",details:"the address of the token contract permitted to serve as underlying assets for this instrument."},"marketPaused()":{inputs:[],name:"marketPaused",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"stateVariable",details:"this is a flag that can be set to pause this particular instance of the call option contract. NOTE: settlement auctions are still enabled in this case because pausing the market should not change the financial situation for the holder of the options."},"minBidIncrementBips()":{inputs:[],name:"minBidIncrementBips",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"stateVariable",details:"this is the minimum amount of the current bid that the new bid must exceed the current bid by in order to be considered valid. This amount is expressed in basis points (i.e. 1/100th of 1%)"},"minimumOptionDuration()":{inputs:[],name:"minimumOptionDuration",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"stateVariable",details:"this is the minimum duration of an option created in this contract instance"},"settlementAuctionStartOffset()":{inputs:[],name:"settlementAuctionStartOffset",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"stateVariable",details:"this is the amount of time before the expiration of the option that the settlement auction will begin."},"weth()":{inputs:[],name:"weth",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"stateVariable",details:"the address of WETH on the chain where this contract is deployed"}},methods:{"ALLOWLISTER_ROLE()":{inputs:[],name:"ALLOWLISTER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the allowlister is able to enable and disable projects to mint instruments"},"CALL_UPGRADER()":{inputs:[],name:"CALL_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the call upgrader role is able to upgrade the implementation of the covered call options"},"COLLECTION_CONF()":{inputs:[],name:"COLLECTION_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the collection configuration role allows the actor to make changes the collection configs on the protocol contract"},"MARKET_CONF()":{inputs:[],name:"MARKET_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the market configuration role allows the actor to make changes to how the market operates"},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the pauser is able to start and pause various components of the protocol"},"VAULT_UPGRADER()":{inputs:[],name:"VAULT_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the vault upgrader role is able to upgrade the implementation for all vaults"},"_preApprovedMarketplace()":{inputs:[],name:"_preApprovedMarketplace",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function"},"approve(address,uint256)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"approve",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-approve}."},"assetOptions(address,uint32)":{inputs:[{internalType:"contract IHookVault",name:"",type:"address"},{internalType:"uint32",name:"",type:"uint32"}],name:"assetOptions",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"},"balanceOf(address)":{inputs:[{internalType:"address",name:"owner",type:"address"}],name:"balanceOf",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"See {IERC721-balanceOf}."},"bid(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"bid",outputs:[],stateMutability:"payable",type:"function",details:"See {IHookCoveredCall-bid}."},"burn(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"burn",outputs:[],stateMutability:"nonpayable",type:"function",details:"Burns `tokenId`. See {ERC721-_burn}. Requirements: - The caller must own `tokenId` or be an approved operator."},"burnExpiredOption(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"burnExpiredOption",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-burnExpiredOption}."},"claimOptionProceeds(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"claimOptionProceeds",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-claimOptionProceeds}"},"contractUri(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"contractUri",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"this is the OpenSea compatible collection - level metadata URI."},"currentBid(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"currentBid",outputs:[{internalType:"uint128",name:"",type:"uint128"}],stateMutability:"view",type:"function",details:"See {IHookCoveredCall-currentBid}."},"currentBidder(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"currentBidder",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IHookCoveredCall-currentBidder}."},"getApproved(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"getApproved",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IERC721-getApproved}."},"getAssetId(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getAssetId",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",details:"see {IHookCoveredCall-getAssetId}."},"getExpiration(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getExpiration",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"see {IHookCoveredCall-getExpiration}."},"getOptionIdForAsset(address,uint32)":{inputs:[{internalType:"address",name:"vault",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getOptionIdForAsset",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"see {IHookCoveredCall-getOptionIdForAsset}"},"getStrikePrice(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getStrikePrice",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"see {IHookCoveredCall-getStrikePrice}."},"getTransferCount(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getTransferCount",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"this count can be used by overbooks to invalidate orders after a token has been transferred, preventing stale order execution by malicious parties",notice:"the number of times the token has been transferred"},"getVaultAddress(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getVaultAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"see {IHookCoveredCall-getVaultAddress}."},"initialize(address,address,address,address)":{inputs:[{internalType:"address",name:"protocol",type:"address"},{internalType:"address",name:"nftContract",type:"address"},{internalType:"address",name:"hookVaultFactory",type:"address"},{internalType:"address",name:"preApprovedMarketplace",type:"address"}],name:"initialize",outputs:[],stateMutability:"nonpayable",type:"function",details:"Because the deployed contract is proxied, arguments unique to each deployment must be passed in an individual initializer. This function is like a constructor.",params:{hookVaultFactory:"the address of the ERC-721 vault registry",nftContract:"the address for the ERC-721 contract that can serve as underlying instruments",preApprovedMarketplace:"the address of the contract which will automatically approved to transfer option ERC721s owned by any account when they're minted",protocol:"the address of the Hook protocol (which contains configurations)"},notice:"Initializes the specific instance of the instrument contract."},"isApprovedForAll(address,address)":{inputs:[{internalType:"address",name:"owner",type:"address"},{internalType:"address",name:"operator",type:"address"}],name:"isApprovedForAll",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC721-isApprovedForAll}. this extension ensures that any operator contract located at {_approvedMarketpace} is considered approved internally in the ERC721 contract"},"mintWithEntitledVault(address,uint32,uint128,uint32)":{inputs:[{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint128",name:"strikePrice",type:"uint128"},{internalType:"uint32",name:"expirationTime",type:"uint32"}],name:"mintWithEntitledVault",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-mintWithEntitledVault}."},"mintWithErc721(address,uint256,uint128,uint32)":{inputs:[{internalType:"address",name:"tokenAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"uint128",name:"strikePrice",type:"uint128"},{internalType:"uint32",name:"expirationTime",type:"uint32"}],name:"mintWithErc721",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-mintWithErc721}."},"mintWithVault(address,uint32,uint128,uint32,(uint8,uint8,bytes32,bytes32))":{inputs:[{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint128",name:"strikePrice",type:"uint128"},{internalType:"uint32",name:"expirationTime",type:"uint32"},{components:[{internalType:"enum Signatures.SignatureType",name:"signatureType",type:"uint8"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],internalType:"struct Signatures.Signature",name:"signature",type:"tuple"}],name:"mintWithVault",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-mintWithVault}."},"name()":{inputs:[],name:"name",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"See {IERC721Metadata-name}."},"optionClaims(uint256)":{inputs:[{internalType:"uint256",name:"",type:"uint256"}],name:"optionClaims",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"},"optionParams(uint256)":{inputs:[{internalType:"uint256",name:"",type:"uint256"}],name:"optionParams",outputs:[{internalType:"address",name:"writer",type:"address"},{internalType:"uint32",name:"expiration",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint128",name:"strike",type:"uint128"},{internalType:"uint128",name:"bid",type:"uint128"},{internalType:"address",name:"highBidder",type:"address"},{internalType:"bool",name:"settled",type:"bool"}],stateMutability:"view",type:"function"},"ownerOf(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"ownerOf",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IERC721-ownerOf}."},"reclaimAsset(uint256,bool)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"},{internalType:"bool",name:"returnNft",type:"bool"}],name:"reclaimAsset",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-reclaimAsset}."},"safeTransferFrom(address,address,uint256)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"safeTransferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-safeTransferFrom}."},"safeTransferFrom(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"_data",type:"bytes"}],name:"safeTransferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-safeTransferFrom}."},"setApprovalForAll(address,bool)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"bool",name:"approved",type:"bool"}],name:"setApprovalForAll",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-setApprovalForAll}."},"setBidIncrement(uint256)":{inputs:[{internalType:"uint256",name:"newBidIncrement",type:"uint256"}],name:"setBidIncrement",outputs:[],stateMutability:"nonpayable",type:"function",details:"set the minimum overage, in bips, for a new bid compared to the current bid.",params:{newBidIncrement:"the minimum bid increment in basis points (1/100th of 1%)"}},"setMarketPaused(bool)":{inputs:[{internalType:"bool",name:"paused",type:"bool"}],name:"setMarketPaused",outputs:[],stateMutability:"nonpayable",type:"function",details:"sets a paused / unpaused state for the market corresponding to this contract",params:{paused:"should the market be set to paused or unpaused"}},"setMinOptionDuration(uint256)":{inputs:[{internalType:"uint256",name:"newMinDuration",type:"uint256"}],name:"setMinOptionDuration",outputs:[],stateMutability:"nonpayable",type:"function",details:"configures the minimum duration for a newly minted option. Options must be at least this far away in the future.",params:{newMinDuration:"is the minimum option duration in seconds"}},"setSettlementAuctionStartOffset(uint256)":{inputs:[{internalType:"uint256",name:"newSettlementStartOffset",type:"uint256"}],name:"setSettlementAuctionStartOffset",outputs:[],stateMutability:"nonpayable",type:"function",details:"set the settlement auction start offset. Settlement auctions begin at this time prior to expiration.",params:{newSettlementStartOffset:"in seconds (i.e. block.timestamp increments)"}},"settleOption(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"settleOption",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-settleOption}."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC165-supportsInterface}."},"symbol()":{inputs:[],name:"symbol",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"See {IERC721Metadata-symbol}."},"tokenURI(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"tokenURI",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"See {IERC721-tokenURI}."},"transferFrom(address,address,uint256)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"transferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-transferFrom}."}}},"src/HookERC721MultiVaultImplV1.sol:HookERC721MultiVaultImplV1":{source:"src/HookERC721MultiVaultImplV1.sol",name:"HookERC721MultiVaultImplV1",title:"HookMultiVault-implementation of a Vault for multiple assets within a NFT collection, with entitlements.",author:"Jake Nyquist - j@hook.xyz",details:"This contract implements ERC721Receiver This contract views the tokenId for the asset on the ERC721 contract as the corresponding assetId for that asset when deposited into the vault",notice:'HookVault holds a multiple NFT asset in escrow on behalf of multiple beneficial owners. Other contracts are able to register "entitlements" for a fixed period of time on the asset, which give them the ability to change the vault\'s owner.',constructor:{inputs:[],stateMutability:"nonpayable",type:"constructor"},events:{"Approval(address,address,uint32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint32",name:"assetId",type:"uint32"}],name:"Approval",type:"event",notice:"Emitted when `beneficialOwner` enables `approved` to manage the `assetId` asset."},"AssetFlashLoaned(address,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"uint256",name:"tokenId",type:"uint256"},{indexed:!1,internalType:"address",name:"flashLoanImpl",type:"address"}],name:"AssetFlashLoaned",type:"event",notice:"emitted after an asset is flash loaned by its beneficial owner."},"AssetReceived(address,address,address,uint32)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"address",name:"sender",type:"address"},{indexed:!1,internalType:"address",name:"contractAddress",type:"address"},{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"}],name:"AssetReceived",type:"event",notice:"emitted when an asset is added into the vault"},"AssetWithdrawn(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"AssetWithdrawn",type:"event",notice:"emitted when an asset is withdrawn from the vault"},"BeneficialOwnerSet(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!1,internalType:"address",name:"setBy",type:"address"}],name:"BeneficialOwnerSet",type:"event",notice:"emitted when the beneficial owner of an asset changes"},"EntitlementCleared(uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementCleared",type:"event",notice:"emitted when an entitlement is cleared from an asset"},"EntitlementImposed(uint32,address,uint32,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"entitledAccount",type:"address"},{indexed:!1,internalType:"uint32",name:"expiry",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementImposed",type:"event",notice:"emitted when an entitlement is placed on an asset"},"Initialized(uint8)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint8",name:"version",type:"uint8"}],name:"Initialized",type:"event"}},methods:{"EIP712_DOMAIN_SEPARATOR()":{inputs:[],name:"EIP712_DOMAIN_SEPARATOR",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function"},"approveOperator(address,uint32)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"approveOperator",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookVault-approveOperator}."},"assetAddress(uint32)":{inputs:[{internalType:"uint32",name:"",type:"uint32"}],name:"assetAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function"},"assetTokenId(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetTokenId",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"returns the underlying token ID for a given asset. In this case the tokenId == the assetId"},"clearEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"clearEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-clearEntitlement}.This can only be called if an entitlement currently exists, otherwise it would be a no-op"},"clearEntitlementAndDistribute(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiver",type:"address"}],name:"clearEntitlementAndDistribute",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-clearEntitlementAndDistribute}.The entitlement must be exist, and must be called by the {operator}. The operator can specify a intended receiver, which should match the beneficialOwner. The function will throw if the receiver and owner do not match.",params:{assetId:"the id of the specific vaulted asset",receiver:"the intended receiver of the asset"}},"entitlementExpiration(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"entitlementExpiration",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",details:"See {IHookVault-entitlementExpiration}."},"flashLoan(uint32,address,bytes)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiverAddress",type:"address"},{internalType:"bytes",name:"params",type:"bytes"}],name:"flashLoan",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-flashLoan}."},"getApprovedOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getApprovedOperator",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IHookVault-getApprovedOperator}."},"getBeneficialOwner(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getBeneficialOwner",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IHookERC721Vault-getBeneficialOwner}."},"getCurrentEntitlementOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getCurrentEntitlementOperator",outputs:[{internalType:"bool",name:"",type:"bool"},{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the id of the underlying asset"},notice:"looks up the current operator of an entitlement on an asset"},"getHoldsAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getHoldsAsset",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IHookERC721Vault-getHoldsAsset}."},"grantEntitlement((address,address,address,uint32,uint32))":{inputs:[{components:[{internalType:"address",name:"beneficialOwner",type:"address"},{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint32",name:"expiry",type:"uint32"}],internalType:"struct Entitlements.Entitlement",name:"entitlement",type:"tuple"}],name:"grantEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-grantEntitlement}.The entitlement must be sent by the current beneficial owner"},"hasActiveEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"hasActiveEntitlement",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function"},"imposeEntitlement(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"imposeEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-imposeEntitlement}.The entitlement must be signed by the current beneficial owner of the contract. Anyone can submit the entitlement"},"initialize(address,address)":{inputs:[{internalType:"address",name:"nftContract",type:"address"},{internalType:"address",name:"hookAddress",type:"address"}],name:"initialize",outputs:[],stateMutability:"nonpayable",type:"function",notice:"-constructor"},"onERC721Received(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"from",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"data",type:"bytes"}],name:"onERC721Received",outputs:[{internalType:"bytes4",name:"",type:"bytes4"}],stateMutability:"nonpayable",type:"function",details:"See {IERC721Receiver-onERC721Received}. Always returns `IERC721Receiver.onERC721Received.selector`."},"setBeneficialOwner(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"newBeneficialOwner",type:"address"}],name:"setBeneficialOwner",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-setBeneficialOwner}. setBeneficialOwner can only be called by the entitlementContract if there is an activeEntitlement."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC165-supportsInterface}."},"validateEntitlementSignature(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"validateEntitlementSignature",outputs:[],stateMutability:"view",type:"function",details:"Validates that a specific signature is actually the entitlement EIP-712 signed by the beneficial owner specified in the entitlement."},"withdrawalAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"withdrawalAsset",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-withdrawalAsset}.withdrawals can only be performed to the beneficial owner if there are no entitlements"}}},"src/HookERC721VaultFactory.sol:HookERC721VaultFactory":{source:"src/HookERC721VaultFactory.sol",name:"HookERC721VaultFactory",title:"Hook Vault Factory",author:"Jake Nyquist-j@hook.xyz",details:"See {IHookERC721VaultFactory}.The factory itself is non-upgradeable; however, each vault is upgradeable (i.e. all vaults) created by this factory can be upgraded at one time via the beacon pattern.",constructor:{inputs:[{internalType:"address",name:"hookProtocolAddress",type:"address"},{internalType:"address",name:"beaconAddress",type:"address"},{internalType:"address",name:"multiBeaconAddress",type:"address"}],stateMutability:"nonpayable",type:"constructor"},events:{"ERC721MultiVaultCreated(address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"nftAddress",type:"address"},{indexed:!1,internalType:"address",name:"vaultAddress",type:"address"}],name:"ERC721MultiVaultCreated",type:"event",notice:"emitted when a new MultiVault is deployed by the protocol"},"ERC721VaultCreated(address,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"nftAddress",type:"address"},{indexed:!1,internalType:"uint256",name:"tokenId",type:"uint256"},{indexed:!1,internalType:"address",name:"vaultAddress",type:"address"}],name:"ERC721VaultCreated",type:"event"}},methods:{"ALLOWLISTER_ROLE()":{inputs:[],name:"ALLOWLISTER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the allowlister is able to enable and disable projects to mint instruments"},"CALL_UPGRADER()":{inputs:[],name:"CALL_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the call upgrader role is able to upgrade the implementation of the covered call options"},"COLLECTION_CONF()":{inputs:[],name:"COLLECTION_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the collection configuration role allows the actor to make changes the collection configs on the protocol contract"},"MARKET_CONF()":{inputs:[],name:"MARKET_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the market configuration role allows the actor to make changes to how the market operates"},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the pauser is able to start and pause various components of the protocol"},"VAULT_UPGRADER()":{inputs:[],name:"VAULT_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the vault upgrader role is able to upgrade the implementation for all vaults"},"findOrCreateVault(address,uint256)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"findOrCreateVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",notice:"See {IHookERC721VaultFactory-findOrCreateVault}."},"getMultiVault(address)":{inputs:[{internalType:"address",name:"",type:"address"}],name:"getMultiVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"Registry of all of the active multi-vaults within the protocol"},"getVault(address,uint256)":{inputs:[{internalType:"address",name:"",type:"address"},{internalType:"uint256",name:"",type:"uint256"}],name:"getVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"Registry of all of the active vaults within the protocol, allowing users to find vaults by project address and tokenId;"},"makeMultiVault(address)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"}],name:"makeMultiVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",notice:"See {IHookERC721VaultFactory-makeMultiVault}."},"makeSoloVault(address,uint256)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"makeSoloVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",notice:"See {IHookERC721VaultFactory-makeSoloVault}."}}},"src/HookERC721VaultImplV1.sol:HookERC721VaultImplV1":{source:"src/HookERC721VaultImplV1.sol",name:"HookERC721VaultImplV1",title:"HookVault-implementation of a Vault for a single NFT asset, with entitlements.",author:"Jake Nyquist - j@hook.xyz",details:"This contract implements ERC721Receiver and extends the MultiVault, simply treating the stored asset as assetId 0 in all cases. SEND TRANSACTION - (1) owners are able to forward transactions to this vault to other wallets (2) calls to the ERC-721 address are blocked to prevent approvals from being set on the NFT while in escrow, which could allow for theft (3) At the end of each transaction, the ownerOf the vaulted token must still be the vault",notice:'HookVault holds a single NFT asset in escrow on behalf of a user. Other contracts are able to register "entitlements" for a fixed period of time on the asset, which give them the ability to change the vault\'s owner.',constructor:{inputs:[],stateMutability:"nonpayable",type:"constructor"},events:{"Approval(address,address,uint32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint32",name:"assetId",type:"uint32"}],name:"Approval",type:"event",notice:"Emitted when `beneficialOwner` enables `approved` to manage the `assetId` asset."},"AssetFlashLoaned(address,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"uint256",name:"tokenId",type:"uint256"},{indexed:!1,internalType:"address",name:"flashLoanImpl",type:"address"}],name:"AssetFlashLoaned",type:"event",notice:"emitted after an asset is flash loaned by its beneficial owner."},"AssetReceived(address,address,address,uint32)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"address",name:"sender",type:"address"},{indexed:!1,internalType:"address",name:"contractAddress",type:"address"},{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"}],name:"AssetReceived",type:"event",notice:"emitted when an asset is added into the vault"},"AssetWithdrawn(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"AssetWithdrawn",type:"event",notice:"emitted when an asset is withdrawn from the vault"},"BeneficialOwnerSet(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!1,internalType:"address",name:"setBy",type:"address"}],name:"BeneficialOwnerSet",type:"event",notice:"emitted when the beneficial owner of an asset changes"},"EntitlementCleared(uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementCleared",type:"event",notice:"emitted when an entitlement is cleared from an asset"},"EntitlementImposed(uint32,address,uint32,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"entitledAccount",type:"address"},{indexed:!1,internalType:"uint32",name:"expiry",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementImposed",type:"event",notice:"emitted when an entitlement is placed on an asset"},"Initialized(uint8)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint8",name:"version",type:"uint8"}],name:"Initialized",type:"event"}},methods:{"EIP712_DOMAIN_SEPARATOR()":{inputs:[],name:"EIP712_DOMAIN_SEPARATOR",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function"},"approveOperator(address,uint32)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"approveOperator",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookVault-approveOperator}."},"assetAddress(uint32)":{inputs:[{internalType:"uint32",name:"",type:"uint32"}],name:"assetAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function"},"assetTokenId(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetTokenId",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"returns the underlying token ID for a given asset. In this case the tokenId == the assetId"},"clearEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"clearEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-clearEntitlement}.This can only be called if an entitlement currently exists, otherwise it would be a no-op"},"clearEntitlementAndDistribute(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiver",type:"address"}],name:"clearEntitlementAndDistribute",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-clearEntitlementAndDistribute}.The entitlement must be exist, and must be called by the {operator}. The operator can specify a intended receiver, which should match the beneficialOwner. The function will throw if the receiver and owner do not match.",params:{assetId:"the id of the specific vaulted asset",receiver:"the intended receiver of the asset"}},"entitlementExpiration(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"entitlementExpiration",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",details:"See {IHookVault-entitlementExpiration}."},"execTransaction(address,bytes)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"bytes",name:"data",type:"bytes"}],name:"execTransaction",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"payable",type:"function",details:"See {IHookERC721Vault-execTransaction}.Allows a beneficial owner to send an arbitrary call from this wallet as long as the underlying NFT is still owned by us after the transaction. The ether value sent is forwarded. Return value is suppressed. Because this contract holds only a single asset owned by a single address, it supports calling exec transaction from this address because such calls are unlikely to impact other owner's assets."},"flashLoan(uint32,address,bytes)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiverAddress",type:"address"},{internalType:"bytes",name:"params",type:"bytes"}],name:"flashLoan",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-flashLoan}."},"getApprovedOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getApprovedOperator",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IHookVault-getApprovedOperator}."},"getBeneficialOwner(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getBeneficialOwner",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IHookERC721Vault-getBeneficialOwner}."},"getCurrentEntitlementOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getCurrentEntitlementOperator",outputs:[{internalType:"bool",name:"",type:"bool"},{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the id of the underlying asset"},notice:"looks up the current operator of an entitlement on an asset"},"getHoldsAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getHoldsAsset",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IHookERC721Vault-getHoldsAsset}."},"grantEntitlement((address,address,address,uint32,uint32))":{inputs:[{components:[{internalType:"address",name:"beneficialOwner",type:"address"},{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint32",name:"expiry",type:"uint32"}],internalType:"struct Entitlements.Entitlement",name:"entitlement",type:"tuple"}],name:"grantEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-grantEntitlement}.The entitlement must be sent by the current beneficial owner"},"hasActiveEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"hasActiveEntitlement",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function"},"imposeEntitlement(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"imposeEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-imposeEntitlement}.The entitlement must be signed by the current beneficial owner of the contract. Anyone may call this function and successfully impose the entitlement as long as the signature is valid."},"initialize(address,address)":{inputs:[{internalType:"address",name:"nftContract",type:"address"},{internalType:"address",name:"hookAddress",type:"address"}],name:"initialize",outputs:[],stateMutability:"nonpayable",type:"function",notice:"-constructor"},"initialize(address,uint256,address)":{inputs:[{internalType:"address",name:"nftContract",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"address",name:"hookAddress",type:"address"}],name:"initialize",outputs:[],stateMutability:"nonpayable",type:"function",notice:"-constructor"},"onERC721Received(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"from",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"data",type:"bytes"}],name:"onERC721Received",outputs:[{internalType:"bytes4",name:"",type:"bytes4"}],stateMutability:"nonpayable",type:"function",details:"See {IERC721Receiver-onERC721Received}. Always returns `IERC721Receiver.onERC721Received.selector`. This method requires an override implementation because the the arguments must be embedded in the body of the function"},"setBeneficialOwner(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"newBeneficialOwner",type:"address"}],name:"setBeneficialOwner",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-setBeneficialOwner}."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC165-supportsInterface}."},"validateEntitlementSignature(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"validateEntitlementSignature",outputs:[],stateMutability:"view",type:"function",details:"Validates that a specific signature is actually the entitlement EIP-712 signed by the beneficial owner specified in the entitlement."},"withdrawalAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"withdrawalAsset",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-withdrawalAsset}.withdrawals can only be performed by the beneficial owner if there are no entitlements"}}},"src/HookProtocol.sol:HookProtocol":{source:"src/HookProtocol.sol",name:"HookProtocol",details:"Other contracts in the protocol refer to this one to get configuration and pausing issues. to reduce attack surface area, this contract cannot be upgraded; however, additional roles can be added. This contract does not implement any specific timelocks or other safety measures. The roles are granted with the principal of least privilege. As the protocol matures, these additional measures can be layered by granting these roles to other contracts. In the extreme, the upgrade and other roles can be burned, which would effectively make the protocol static and non-upgradeable.",constructor:{inputs:[{internalType:"address",name:"allowlister",type:"address"},{internalType:"address",name:"pauser",type:"address"},{internalType:"address",name:"vaultUpgrader",type:"address"},{internalType:"address",name:"callUpgrader",type:"address"},{internalType:"address",name:"marketConf",type:"address"},{internalType:"address",name:"collectionConf",type:"address"},{internalType:"address",name:"weth",type:"address"}],stateMutability:"nonpayable",type:"constructor"},events:{"Paused(address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"account",type:"address"}],name:"Paused",type:"event"},"RoleAdminChanged(bytes32,bytes32,bytes32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"bytes32",name:"previousAdminRole",type:"bytes32"},{indexed:!0,internalType:"bytes32",name:"newAdminRole",type:"bytes32"}],name:"RoleAdminChanged",type:"event"},"RoleGranted(bytes32,address,address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"address",name:"account",type:"address"},{indexed:!0,internalType:"address",name:"sender",type:"address"}],name:"RoleGranted",type:"event"},"RoleRevoked(bytes32,address,address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"address",name:"account",type:"address"},{indexed:!0,internalType:"address",name:"sender",type:"address"}],name:"RoleRevoked",type:"event"},"Unpaused(address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"account",type:"address"}],name:"Unpaused",type:"event"}},stateVariables:{"getWETHAddress()":{inputs:[],name:"getWETHAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"stateVariable",details:"these are values for popular chains: mainnet: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 kovan: 0xd0a1e359811322d97991e03f863a0c30c2cf029c ropsten: 0xc778417e063141139fce010982780140aa0cd5ab rinkeby: 0xc778417e063141139fce010982780140aa0cd5ab",return:"the weth address",returns:{_0:"the weth address"},notice:"the standard weth address on this chain"}},methods:{"ALLOWLISTER_ROLE()":{inputs:[],name:"ALLOWLISTER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the allowlister is able to enable and disable projects to mint instruments"},"CALL_UPGRADER()":{inputs:[],name:"CALL_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the call upgrader role is able to upgrade the implementation of the covered call options"},"COLLECTION_CONF()":{inputs:[],name:"COLLECTION_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the collection configuration role allows the actor to make changes the collection configs on the protocol contract"},"DEFAULT_ADMIN_ROLE()":{inputs:[],name:"DEFAULT_ADMIN_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function"},"MARKET_CONF()":{inputs:[],name:"MARKET_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the market configuration role allows the actor to make changes to how the market operates"},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the pauser is able to start and pause various components of the protocol"},"VAULT_UPGRADER()":{inputs:[],name:"VAULT_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the vault upgrader role is able to upgrade the implementation for all vaults"},"coveredCallContract()":{inputs:[],name:"coveredCallContract",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"the address of the deployed CoveredCallFactory used by the protocol"},"getCollectionConfig(address,bytes32)":{inputs:[{internalType:"address",name:"collectionAddress",type:"address"},{internalType:"bytes32",name:"conf",type:"bytes32"}],name:"getCollectionConfig",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IHookProtocol-getCollectionConfig}."},"getRoleAdmin(bytes32)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"}],name:"getRoleAdmin",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",details:"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"grantRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"hasRole",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns `true` if `account` has been granted `role`."},"pause()":{inputs:[],name:"pause",outputs:[],stateMutability:"nonpayable",type:"function",notice:"pauses the protocol if the protocol is currently unpaused"},"paused()":{inputs:[],name:"paused",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns true if the contract is paused, and false otherwise."},"renounceRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"renounceRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`."},"revokeRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"revokeRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."},"setCollectionConfig(address,bytes32,bool)":{inputs:[{internalType:"address",name:"collectionAddress",type:"address"},{internalType:"bytes32",name:"config",type:"bytes32"},{internalType:"bool",name:"value",type:"bool"}],name:"setCollectionConfig",outputs:[],stateMutability:"nonpayable",type:"function",details:"the conf value can be read with getCollectionConfig",params:{collectionAddress:"the address for the collection",config:"the configuration field to set",value:"the value to set for the configuration"},notice:"allows an account with the COLLECTION_CONF role to set a boolean config value for a collection"},"setCoveredCallFactory(address)":{inputs:[{internalType:"address",name:"coveredCallFactoryContract",type:"address"}],name:"setCoveredCallFactory",outputs:[],stateMutability:"nonpayable",type:"function",details:"This address is used by other protocols searching for the registry of protocols.",params:{coveredCallFactoryContract:"the address of the deployed covered call contract"},notice:"Allows an admin to set the address of the deployed covered call factory"},"setVaultFactory(address)":{inputs:[{internalType:"address",name:"vaultFactoryContract",type:"address"}],name:"setVaultFactory",outputs:[],stateMutability:"nonpayable",type:"function",details:"allows all protocol components, including the call factory, to look up the vault factory.",params:{vaultFactoryContract:"the deployed vault factory"},notice:"Allows an admin to set the address of the deployed vault factory"},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC165-supportsInterface}."},"throwWhenPaused()":{inputs:[],name:"throwWhenPaused",outputs:[],stateMutability:"view",type:"function",notice:"throws an exception when the protocol is paused"},"unpause()":{inputs:[],name:"unpause",outputs:[],stateMutability:"nonpayable",type:"function",notice:"unpauses the protocol if the protocol is already paused"},"vaultContract()":{inputs:[],name:"vaultContract",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"the address of the deployed VaultFactory used by the protocol"}}},"src/HookUpgradeableBeacon.sol:HookUpgradeableBeacon":{source:"src/HookUpgradeableBeacon.sol",name:"HookUpgradeableBeacon",details:"This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their implementation contract, which is where they will delegate all function calls. An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon. Ownership is managed centrally on the Hook protocol level, where the owner is the holder of a specific permission. This permission should be used only for the purpose of upgrading the particular contract (i.e., the permissions should not be reused). This contract is deliberately simple and only has one non-view method - `upgrade`. Timelocks or other upgrade conditions will be managed by the owner of this contract. This contract is based on the UpgradeableBeaconContract from OZ and DharmaUpgradeBeaconController from Dharma",constructor:{inputs:[{internalType:"address",name:"implementation_",type:"address"},{internalType:"address",name:"hookProtocol",type:"address"},{internalType:"bytes32",name:"upgraderRole",type:"bytes32"}],stateMutability:"nonpayable",type:"constructor"},events:{"Upgraded(address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"implementation",type:"address"}],name:"Upgraded",type:"event",details:"Emitted when the implementation returned by the beacon is changed."}},methods:{"ALLOWLISTER_ROLE()":{inputs:[],name:"ALLOWLISTER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the allowlister is able to enable and disable projects to mint instruments"},"CALL_UPGRADER()":{inputs:[],name:"CALL_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the call upgrader role is able to upgrade the implementation of the covered call options"},"COLLECTION_CONF()":{inputs:[],name:"COLLECTION_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the collection configuration role allows the actor to make changes the collection configs on the protocol contract"},"MARKET_CONF()":{inputs:[],name:"MARKET_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the market configuration role allows the actor to make changes to how the market operates"},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the pauser is able to start and pause various components of the protocol"},"VAULT_UPGRADER()":{inputs:[],name:"VAULT_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the vault upgrader role is able to upgrade the implementation for all vaults"},"implementation()":{inputs:[],name:"implementation",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"Returns the current implementation address."},"upgradeTo(address)":{inputs:[{internalType:"address",name:"newImplementation",type:"address"}],name:"upgradeTo",outputs:[],stateMutability:"nonpayable",type:"function",details:"Upgrades the beacon to a new implementation. Emits an {Upgraded} event. Requirements: - msg.sender must be the owner of the contract. - `newImplementation` must be a contract."}}},"src/interfaces/IERC721FlashLoanReceiver.sol:IERC721FlashLoanReceiver":{source:"src/interfaces/IERC721FlashLoanReceiver.sol",name:"IERC721FlashLoanReceiver",title:"Flash Loan Operator Interface (ERC-721)",author:"Jake Nyquist-j@hook.xyz",details:"contracts that will utilize vaulted assets in flash loans should implement this interface in order to receive the asset. Users may want to receive the asset within a single block to claim airdrops, participate in governance, and other things with their assets. The implementer may do whatever they like with the vaulted NFT within the executeOperation method, so long as they approve the vault (passed as a param) to operate the underlying NFT. The Vault will move the asset back into the vault after executionOperation returns, and also validate that it is the owner of the asset. The flashloan receiver is able to abort a flashloan by returning false from the executeOperation method.",methods:{"executeOperation(address,uint256,address,address,bytes)":{inputs:[{internalType:"address",name:"nftContract",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"address",name:"beneficialOwner",type:"address"},{internalType:"address",name:"vault",type:"address"},{internalType:"bytes",name:"params",type:"bytes"}],name:"executeOperation",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"nonpayable",type:"function",details:"executeOperation is called immediately after the asset is transferred to this contract. After return, the asset is returned to the vault by the vault contract. The executeOperation implementation MUST approve the {vault} to operate the transferred NFT i.e. `IERC721(nftContract).setApprovalForAll(vault, true);`",params:{beneficialOwner:"the current beneficialOwner of the vault, who initialized the flashLoan",nftContract:"the address of the underlying erc-721 asset",params:"additional params passed by the caller into the flashloan",tokenId:"the address of the received erc-721 asset",vault:"the address of the vault performing the flashloan (in most cases, equal to msg.sender)"},notice:"the method that contains the operations to be performed with the loaned asset"},"onERC721Received(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"from",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"data",type:"bytes"}],name:"onERC721Received",outputs:[{internalType:"bytes4",name:"",type:"bytes4"}],stateMutability:"nonpayable",type:"function",details:"Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} by `operator` from `from`, this function is called. It must return its Solidity selector to confirm the token transfer. If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`."}}},"src/interfaces/IHookCoveredCall.sol:IHookCoveredCall":{source:"src/interfaces/IHookCoveredCall.sol",name:"IHookCoveredCall",title:"A covered call instrument",author:"Jake Nyquist-j@hook.xyz",notice:'This contract implements a "Covered Call Option". A call option gives the holder the right, but not the obligation to purchase an asset at a fixed time in the future (the expiry) for a fixed price (the strike). This call option implementation here is similar to a "european" call option because the asset can only be purchased at the expiration. The call option is "covered" because the underlying asset, must be held in escrow within a IHookVault for the entire duration of the option. There are three phases to the call option: (1) WRITING: The owner of the NFT can mint an option by calling the "mint" function using the parameters of the subject ERC-721; specifying additionally their preferred strike price and expiration. An "instrument nft" is minted to the writer\'s address, where the holder of this ERC-721 will receive the economic benefit of holding the option. (2) SALE: The sale occurs outside of the context of this contract; however, the ZeroEx market contracts are pre-approved to transfer the tokens. By Selling the instrument NFT, the writer earns a "premium" for selling their option. The option may be sold and re-sold multiple times. (3) SETTLEMENT: One day prior to the expiration, and auction begins. People are able to call bid() for more than the strike price to place a bid. If, at settlement, the high bid is greater than the strike, (b-strike) is transferred to the holder of the instrument NFT, the strike price is transferred to the writer. The high bid is transferred to the holder of the option.',events:{"Approval(address,address,uint256)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"owner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint256",name:"tokenId",type:"uint256"}],name:"Approval",type:"event"},"ApprovalForAll(address,address,bool)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"owner",type:"address"},{indexed:!0,internalType:"address",name:"operator",type:"address"},{indexed:!1,internalType:"bool",name:"approved",type:"bool"}],name:"ApprovalForAll",type:"event"},"Bid(uint256,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"uint256",name:"bidAmount",type:"uint256"},{indexed:!1,internalType:"address",name:"bidder",type:"address"}],name:"Bid",type:"event",params:{bidAmount:"the amount of wei bid",bidder:"the account placing the bid that is now the high bidder",optionId:"the option for the underlying that was bid on"},notice:"emitted when a call option settlement auction gets and accepts a new bid"},"CallCreated(address,address,uint256,uint256,uint256,uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"writer",type:"address"},{indexed:!1,internalType:"address",name:"vaultAddress",type:"address"},{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"uint256",name:"strikePrice",type:"uint256"},{indexed:!1,internalType:"uint256",name:"expiration",type:"uint256"}],name:"CallCreated",type:"event",notice:"emitted when a new call option is successfully minted with a specific underlying vault"},"CallProceedsDistributed(uint256,address,uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"uint256",name:"amount",type:"uint256"}],name:"CallProceedsDistributed",type:"event",params:{amount:"the amount of the claim distributed",optionId:"the option the claim is on",to:"the option owner making the claim"},notice:"emitted when an option owner claims their proceeds"},"CallReclaimed(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"}],name:"CallReclaimed",type:"event",notice:"emitted when a call option is reclaimed"},"CallSettled(uint256,bool)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"bool",name:"claimable",type:"bool"}],name:"CallSettled",type:"event",notice:"emitted when a call option is settled"},"ExpiredCallBurned(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"}],name:"ExpiredCallBurned",type:"event",notice:"emitted when a expired call option is burned"},"Transfer(address,address,uint256)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"from",type:"address"},{indexed:!0,internalType:"address",name:"to",type:"address"},{indexed:!0,internalType:"uint256",name:"tokenId",type:"uint256"}],name:"Transfer",type:"event"}},methods:{"approve(address,uint256)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"approve",outputs:[],stateMutability:"nonpayable",type:"function",details:"Gives permission to `to` to transfer `tokenId` token to another account. The approval is cleared when the token is transferred. Only a single account can be approved at a time, so approving the zero address clears previous approvals. Requirements: - The caller must own the token or be an approved operator. - `tokenId` must exist. Emits an {Approval} event."},"balanceOf(address)":{inputs:[{internalType:"address",name:"owner",type:"address"}],name:"balanceOf",outputs:[{internalType:"uint256",name:"balance",type:"uint256"}],stateMutability:"view",type:"function",details:"Returns the number of tokens in ``owner``'s account."},"bid(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"bid",outputs:[],stateMutability:"payable",type:"function",params:{optionId:"the optionId corresponding to the settlement to bid on."},notice:"Bid in the settlement auction for an option. The paid amount is the bid, and the bidder is required to escrow this amount until either the auction ends or another bidder bids higher The bid must be greater than the strike price"},"burnExpiredOption(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"burnExpiredOption",outputs:[],stateMutability:"nonpayable",type:"function",params:{optionId:"of the option to burn."},notice:"Allows anyone to burn the instrument NFT for an expired option."},"claimOptionProceeds(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"claimOptionProceeds",outputs:[],stateMutability:"nonpayable",type:"function",details:"this mechanism prevents the proceeds from being sent to an account temporarily custodying the option asset.",params:{optionId:"the option to claim and burn."},notice:"allows the option owner to claim proceeds if the option was settled by another account. The option NFT is burned after settlement."},"currentBid(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"currentBid",outputs:[{internalType:"uint128",name:"",type:"uint128"}],stateMutability:"view",type:"function",params:{optionId:"of the option to check"},notice:"view function to get the current high settlement bid of an option, or 0 if there is no high bid"},"currentBidder(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"currentBidder",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{optionId:"of the option to check"},returns:{_0:"address of the account for the current high bidder, or the null address if there is none"},notice:"view function to get the current high bidder for an option settlement auction, or the null address if no high bidder exists"},"getApproved(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"getApproved",outputs:[{internalType:"address",name:"operator",type:"address"}],stateMutability:"view",type:"function",details:"Returns the account approved for `tokenId` token. Requirements: - `tokenId` must exist."},"getOptionIdForAsset(address,uint32)":{inputs:[{internalType:"address",name:"vault",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getOptionIdForAsset",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"getOptionIdForAsset",params:{assetId:"the id of the asset to check",vault:"the address of the hook vault that holds the covered asset"},returns:{_0:"the optionId, if one exists or 0 otherwise"},notice:"Looks up the latest optionId that covers a particular asset, if one exists. This option may be already settled."},"isApprovedForAll(address,address)":{inputs:[{internalType:"address",name:"owner",type:"address"},{internalType:"address",name:"operator",type:"address"}],name:"isApprovedForAll",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns if the `operator` is allowed to manage all of the assets of `owner`. See {setApprovalForAll}"},"mintWithEntitledVault(address,uint32,uint128,uint32)":{inputs:[{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint128",name:"strikePrice",type:"uint128"},{internalType:"uint32",name:"expirationTime",type:"uint32"}],name:"mintWithEntitledVault",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset within the vault",expirationTime:"time the timestamp after which the option will be expired",strikePrice:"the strike price for the call option being written",vaultAddress:"the contract address of the vault currently holding the call option"},notice:"Mints a new call option for the assets deposited in a particular vault given strike price and expiration. That vault must already have a registered entitlement for this contract with the an expiration equal to {expirationTime}"},"mintWithErc721(address,uint256,uint128,uint32)":{inputs:[{internalType:"address",name:"tokenAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"uint128",name:"strikePrice",type:"uint128"},{internalType:"uint32",name:"expirationTime",type:"uint32"}],name:"mintWithErc721",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"nonpayable",type:"function",params:{expirationTime:"time the timestamp after which the option will be expired",strikePrice:"the strike price for the call option being written",tokenAddress:"the contract address of the ERC-721 token that serves as the underlying asset for the call option",tokenId:"the tokenId of the underlying ERC-721 token"},notice:'Mints a new call option for a particular "underlying" ERC-721 NFT with a given strike price and expiration'},"mintWithVault(address,uint32,uint128,uint32,(uint8,uint8,bytes32,bytes32))":{inputs:[{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint128",name:"strikePrice",type:"uint128"},{internalType:"uint32",name:"expirationTime",type:"uint32"},{components:[{internalType:"enum Signatures.SignatureType",name:"signatureType",type:"uint8"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],internalType:"struct Signatures.Signature",name:"signature",type:"tuple"}],name:"mintWithVault",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset within the vault",expirationTime:"time the timestamp after which the option will be expired",signature:"the signature used to place the entitlement onto the vault",strikePrice:"the strike price for the call option being written",vaultAddress:"the contract address of the vault currently holding the call option"},notice:"Mints a new call option for the assets deposited in a particular vault given strike price and expiration."},"name()":{inputs:[],name:"name",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"Returns the token collection name."},"ownerOf(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"ownerOf",outputs:[{internalType:"address",name:"owner",type:"address"}],stateMutability:"view",type:"function",details:"Returns the owner of the `tokenId` token. Requirements: - `tokenId` must exist."},"reclaimAsset(uint256,bool)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"},{internalType:"bool",name:"returnNft",type:"bool"}],name:"reclaimAsset",outputs:[],stateMutability:"nonpayable",type:"function",details:"Allows the writer to reclaim a NFT if they also hold the option NFT.",params:{optionId:"the option being reclaimed.",returnNft:"true if token should be withdrawn from vault, false to leave token in the vault."},notice:"Allows the writer to reclaim an entitled asset. This is only possible when the writer holds the option nft and calls this function."},"safeTransferFrom(address,address,uint256)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"safeTransferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients are aware of the ERC721 protocol to prevent tokens from being forever locked. Requirements: - `from` cannot be the zero address. - `to` cannot be the zero address. - `tokenId` token must exist and be owned by `from`. - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. Emits a {Transfer} event."},"safeTransferFrom(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"data",type:"bytes"}],name:"safeTransferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"Safely transfers `tokenId` token from `from` to `to`. Requirements: - `from` cannot be the zero address. - `to` cannot be the zero address. - `tokenId` token must exist and be owned by `from`. - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. Emits a {Transfer} event."},"setApprovalForAll(address,bool)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"bool",name:"_approved",type:"bool"}],name:"setApprovalForAll",outputs:[],stateMutability:"nonpayable",type:"function",details:"Approve or remove `operator` as an operator for the caller. Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. Requirements: - The `operator` cannot be the caller. Emits an {ApprovalForAll} event."},"settleOption(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"settleOption",outputs:[],stateMutability:"nonpayable",type:"function",details:"the return nft param allows the underlying asset to remain in its vault. This saves gas compared to first distributing it and then re-depositing it. No royalties or other payments are subtracted from the distribution amounts.",params:{optionId:"of the option to settle."},notice:"Permissionlessly settle an expired option when the option expires in the money, distributing the proceeds to the Writer, Holder, and Bidder as follows: WRITER (who originally called mint() and owned underlying asset) - receives the `strike` HOLDER (ownerOf(optionId)) - receives `b-strike` HIGH BIDDER (call.highBidder) - becomes ownerOf NFT, pays `bid`."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."},"symbol()":{inputs:[],name:"symbol",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"Returns the token collection symbol."},"tokenURI(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"tokenURI",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"Returns the Uniform Resource Identifier (URI) for `tokenId` token."},"transferFrom(address,address,uint256)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"transferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"Transfers `tokenId` token from `from` to `to`. WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. Requirements: - `from` cannot be the zero address. - `to` cannot be the zero address. - `tokenId` token must be owned by `from`. - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. Emits a {Transfer} event."}}},"src/interfaces/IHookCoveredCallFactory.sol:IHookCoveredCallFactory":{source:"src/interfaces/IHookCoveredCallFactory.sol",name:"IHookCoveredCallFactory",title:"HookCoveredCallFactory-factory for instances of the Covered Call contract",author:"Jake Nyquist-j@hook.xyz",notice:"The Factory creates covered call instruments that support specific ERC-721 contracts, and also tracks all of the existing active markets.",events:{"CoveredCallInstrumentCreated(address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"assetAddress",type:"address"},{indexed:!1,internalType:"address",name:"instrumentAddress",type:"address"}],name:"CoveredCallInstrumentCreated",type:"event",details:"emitted whenever a new call instrument instance is created",params:{assetAddress:"the address of the asset underlying the covered call",instrumentAddress:"the address of the covered call instrument"}}},methods:{"getCallInstrument(address)":{inputs:[{internalType:"address",name:"assetAddress",type:"address"}],name:"getCallInstrument",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetAddress:"the contract address for the underlying asset"},returns:{_0:"the address of the instrument contract or the null address if one does not exist"},notice:"Lookup the call instrument contract based on the asset address"},"makeCallInstrument(address)":{inputs:[{internalType:"address",name:"assetAddress",type:"address"}],name:"makeCallInstrument",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",params:{assetAddress:"the address for the underling asset"},returns:{_0:"the address of the call option instrument contract (upgradeable)"},notice:"Create a call option instrument for a specific underlying asset address"}}},"src/interfaces/IHookERC20Vault.sol:IHookERC20Vault":{source:"src/interfaces/IHookERC20Vault.sol",name:"IHookERC20Vault",title:"Hook ERC-20 Vault interface",author:"Jake Nyquist-j@hook.xyz",details:"the IHookERC20 vault is an extension of the standard IHookVault specifically designed to hold and receive ERC20 Tokens.",events:{"Approval(address,address,uint32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint32",name:"assetId",type:"uint32"}],name:"Approval",type:"event",notice:"Emitted when `beneficialOwner` enables `approved` to manage the `assetId` asset."},"AssetReceived(address,address,address,uint32)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"address",name:"sender",type:"address"},{indexed:!1,internalType:"address",name:"contractAddress",type:"address"},{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"}],name:"AssetReceived",type:"event",notice:"emitted when an asset is added into the vault"},"AssetWithdrawn(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"AssetWithdrawn",type:"event",notice:"emitted when an asset is withdrawn from the vault"},"BeneficialOwnerSet(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!1,internalType:"address",name:"setBy",type:"address"}],name:"BeneficialOwnerSet",type:"event",notice:"emitted when the beneficial owner of an asset changes"},"EntitlementCleared(uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementCleared",type:"event",notice:"emitted when an entitlement is cleared from an asset"},"EntitlementImposed(uint32,address,uint32,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"entitledAccount",type:"address"},{indexed:!1,internalType:"uint32",name:"expiry",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementImposed",type:"event",notice:"emitted when an entitlement is placed on an asset"}},methods:{"approveOperator(address,uint32)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"approveOperator",outputs:[],stateMutability:"nonpayable",type:"function",details:"Only a single account can be approved at a time, so approving the zero address clears previous approvals. * Requirements: - The caller must be the beneficial owner - `tokenId` must exist. Emits an {Approval} event.",notice:"Gives permission to `to` to impose an entitlement upon `assetId`"},"assetAddress(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"the contract address of the vaulted asset"},notice:"the contract address of the vaulted asset"},"assetBalance(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetBalance",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",notice:"returns the balance of the underlying ERC20 token"},"clearEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"clearEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset to clear"},notice:"Allows the entitled address to release their claim on the asset"},"clearEntitlementAndDistribute(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiver",type:"address"}],name:"clearEntitlementAndDistribute",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the Id of the asset to clear",receiver:"the intended receiver of the asset"},notice:"Removes the active entitlement from a vault and returns the asset to the beneficial owner"},"entitlementExpiration(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"entitlementExpiration",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",details:"returns the 0 if no entitlement is set",returns:{_0:"the block timestamp after which the entitlement expires"},notice:"Looks up the expiration timestamp of the current entitlement"},"getApprovedOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getApprovedOperator",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"Returns the account approved for `tokenId` token. Requirements: - `assetId` must exist."},"getBeneficialOwner(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getBeneficialOwner",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"the address of the beneficial owner of the asset"},notice:"looks up the current beneficial owner of the asset"},"getCurrentEntitlementOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getCurrentEntitlementOperator",outputs:[{internalType:"bool",name:"",type:"bool"},{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the id of the underlying asset"},notice:"looks up the current operator of an entitlement on an asset"},"getHoldsAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getHoldsAsset",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"true if the asset is currently within the vault, false otherwise"},notice:"checks if the asset is currently stored in the vault"},"grantEntitlement((address,address,address,uint32,uint32))":{inputs:[{components:[{internalType:"address",name:"beneficialOwner",type:"address"},{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint32",name:"expiry",type:"uint32"}],internalType:"struct Entitlements.Entitlement",name:"entitlement",type:"tuple"}],name:"grantEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"this function call is signed by the sender per the EVM, so we know the entitlement is authentic",params:{entitlement:"The entitlement to impose onto the contract"},notice:"Allows the beneficial owner to grant an entitlement to an asset within the contract"},"imposeEntitlement(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"imposeEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset within the vault",expiry:"the duration of the entitlement",operator:"the operator to entitle",r:"sig r",s:"sig s",v:"sig v"},notice:"Add an entitlement claim to the asset held within the contract"},"setBeneficialOwner(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"newBeneficialOwner",type:"address"}],name:"setBeneficialOwner",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the subject asset to impose the entitlement",newBeneficialOwner:"the account of the person who is able to withdrawal when there are no entitlements."},notice:"setBeneficialOwner updates the current address that can claim the asset when it is free of entitlements."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."},"withdrawalAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"withdrawalAsset",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the asset to remove from the vault"},notice:"Withdrawal an unencumbered asset from this vault"}}},"src/interfaces/IHookERC721Vault.sol:IHookERC721Vault":{source:"src/interfaces/IHookERC721Vault.sol",name:"IHookERC721Vault",title:"Hook ERC-721 Vault interface",author:"Jake Nyquist-j@hook.xyz",details:"the IHookERC721 vault is an extension of the standard IHookVault specifically designed to hold and receive ERC721 Tokens. FLASH LOAN - (1) beneficial owners are able to borrow the vaulted asset for a single function call (2) to borrow the asset, they must implement and deploy a {IERC721FlashLoanReceiver} contract, and then call the flashLoan method. (3) At the end of the flashLoan, we ensure the asset is still owned by the vault.",events:{"Approval(address,address,uint32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint32",name:"assetId",type:"uint32"}],name:"Approval",type:"event",notice:"Emitted when `beneficialOwner` enables `approved` to manage the `assetId` asset."},"AssetFlashLoaned(address,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"uint256",name:"tokenId",type:"uint256"},{indexed:!1,internalType:"address",name:"flashLoanImpl",type:"address"}],name:"AssetFlashLoaned",type:"event",details:"only one asset can be flash loaned at a time, and that asset is denoted by the tokenId emitted.",notice:"emitted after an asset is flash loaned by its beneficial owner."},"AssetReceived(address,address,address,uint32)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"address",name:"sender",type:"address"},{indexed:!1,internalType:"address",name:"contractAddress",type:"address"},{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"}],name:"AssetReceived",type:"event",notice:"emitted when an asset is added into the vault"},"AssetWithdrawn(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"AssetWithdrawn",type:"event",notice:"emitted when an asset is withdrawn from the vault"},"BeneficialOwnerSet(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!1,internalType:"address",name:"setBy",type:"address"}],name:"BeneficialOwnerSet",type:"event",notice:"emitted when the beneficial owner of an asset changes"},"EntitlementCleared(uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementCleared",type:"event",notice:"emitted when an entitlement is cleared from an asset"},"EntitlementImposed(uint32,address,uint32,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"entitledAccount",type:"address"},{indexed:!1,internalType:"uint32",name:"expiry",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementImposed",type:"event",notice:"emitted when an entitlement is placed on an asset"}},methods:{"approveOperator(address,uint32)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"approveOperator",outputs:[],stateMutability:"nonpayable",type:"function",details:"Only a single account can be approved at a time, so approving the zero address clears previous approvals. * Requirements: - The caller must be the beneficial owner - `tokenId` must exist. Emits an {Approval} event.",notice:"Gives permission to `to` to impose an entitlement upon `assetId`"},"assetAddress(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"the contract address of the vaulted asset"},notice:"the contract address of the vaulted asset"},"assetTokenId(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetTokenId",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",notice:"the tokenID of the underlying ERC721 token;"},"clearEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"clearEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset to clear"},notice:"Allows the entitled address to release their claim on the asset"},"clearEntitlementAndDistribute(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiver",type:"address"}],name:"clearEntitlementAndDistribute",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the Id of the asset to clear",receiver:"the intended receiver of the asset"},notice:"Removes the active entitlement from a vault and returns the asset to the beneficial owner"},"entitlementExpiration(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"entitlementExpiration",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",details:"returns the 0 if no entitlement is set",returns:{_0:"the block timestamp after which the entitlement expires"},notice:"Looks up the expiration timestamp of the current entitlement"},"flashLoan(uint32,address,bytes)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiverAddress",type:"address"},{internalType:"bytes",name:"params",type:"bytes"}],name:"flashLoan",outputs:[],stateMutability:"nonpayable",type:"function",details:"the flashloan receiver can perform arbitrary logic, but must approve the vault as an operator before returning.",params:{params:"calldata params to forward to the receiver",receiverAddress:"the contract which implements the {IERC721FlashLoanReceiver} interface to utilize the asset while it is loaned out"},notice:"flashLoans the vaulted asset to another contract for use and return to the vault. Only the owner may perform the flashloan"},"getApprovedOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getApprovedOperator",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"Returns the account approved for `tokenId` token. Requirements: - `assetId` must exist."},"getBeneficialOwner(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getBeneficialOwner",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"the address of the beneficial owner of the asset"},notice:"looks up the current beneficial owner of the asset"},"getCurrentEntitlementOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getCurrentEntitlementOperator",outputs:[{internalType:"bool",name:"",type:"bool"},{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the id of the underlying asset"},notice:"looks up the current operator of an entitlement on an asset"},"getHoldsAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getHoldsAsset",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"true if the asset is currently within the vault, false otherwise"},notice:"checks if the asset is currently stored in the vault"},"grantEntitlement((address,address,address,uint32,uint32))":{inputs:[{components:[{internalType:"address",name:"beneficialOwner",type:"address"},{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint32",name:"expiry",type:"uint32"}],internalType:"struct Entitlements.Entitlement",name:"entitlement",type:"tuple"}],name:"grantEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"this function call is signed by the sender per the EVM, so we know the entitlement is authentic",params:{entitlement:"The entitlement to impose onto the contract"},notice:"Allows the beneficial owner to grant an entitlement to an asset within the contract"},"imposeEntitlement(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"imposeEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset within the vault",expiry:"the duration of the entitlement",operator:"the operator to entitle",r:"sig r",s:"sig s",v:"sig v"},notice:"Add an entitlement claim to the asset held within the contract"},"onERC721Received(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"from",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"data",type:"bytes"}],name:"onERC721Received",outputs:[{internalType:"bytes4",name:"",type:"bytes4"}],stateMutability:"nonpayable",type:"function",details:"Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} by `operator` from `from`, this function is called. It must return its Solidity selector to confirm the token transfer. If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`."},"setBeneficialOwner(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"newBeneficialOwner",type:"address"}],name:"setBeneficialOwner",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the subject asset to impose the entitlement",newBeneficialOwner:"the account of the person who is able to withdrawal when there are no entitlements."},notice:"setBeneficialOwner updates the current address that can claim the asset when it is free of entitlements."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."},"withdrawalAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"withdrawalAsset",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the asset to remove from the vault"},notice:"Withdrawal an unencumbered asset from this vault"}}},"src/interfaces/IHookERC721VaultFactory.sol:IHookERC721VaultFactory":{source:"src/interfaces/IHookERC721VaultFactory.sol",name:"IHookERC721VaultFactory",title:"HookERC721Factory-factory for instances of the hook vault",author:"Jake Nyquist-j@hook.xyz",notice:"The Factory creates a specific vault for ERC721s.",events:{"ERC721MultiVaultCreated(address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"nftAddress",type:"address"},{indexed:!1,internalType:"address",name:"vaultAddress",type:"address"}],name:"ERC721MultiVaultCreated",type:"event",params:{nftAddress:"the address of the nft contract that may be deposited into the new vault",vaultAddress:"address of the newly deployed vault"},notice:"emitted when a new MultiVault is deployed by the protocol"},"ERC721VaultCreated(address,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"nftAddress",type:"address"},{indexed:!1,internalType:"uint256",name:"tokenId",type:"uint256"},{indexed:!1,internalType:"address",name:"vaultAddress",type:"address"}],name:"ERC721VaultCreated",type:"event"}},methods:{"findOrCreateVault(address,uint256)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"findOrCreateVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",params:{nftAddress:"the contract address for the ERC-721",tokenId:"the tokenId for the ERC-721"},notice:"creates a vault for a specific tokenId. If there is a multi-vault in existence which supports that address the address for that vault is returned as a new one does not need to be made."},"getMultiVault(address)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"}],name:"getMultiVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"view",type:"function",params:{nftAddress:"the contract address for the ERC-721"},returns:{_0:"the address of the {IERC721Vault} multi asset vault, or the null address if one does not exist"},notice:"gets the address of a multi-asset vault for a particular ERC-721 contract, if one exists"},"getVault(address,uint256)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"getVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"view",type:"function",params:{nftAddress:"the contract address for the ERC-721",tokenId:"the tokenId for the ERC-721"},returns:{_0:"the address of a {IERC721Vault} if one exists that supports the particular ERC-721, or the null address otherwise"},notice:"gets the address of a vault for a particular ERC-721 token"},"makeMultiVault(address)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"}],name:"makeMultiVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",params:{nftAddress:"the contract address for the ERC-721 to be supported by the vault"},returns:{_0:"the address of the newly deployed {IERC721Vault} multi asset vault"},notice:"deploy a multi-asset vault if one has not already been deployed"},"makeSoloVault(address,uint256)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"makeSoloVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",details:"the only valid asset id in this vault is = 0",params:{nftAddress:"the address of the underlying nft contract",tokenId:"the individual token that can be deposited into this vault"},notice:"make a new vault that can contain a single asset only"}}},"src/interfaces/IHookProtocol.sol:IHookProtocol":{source:"src/interfaces/IHookProtocol.sol",name:"IHookProtocol",title:"HookProtocol configuration and access control repository",author:"Jake Nyquist-j@hook.xyz",details:"it is critically important that the particular protocol implementation is correct as, if it is not, all assets contained within protocol contracts can be easily compromised.",events:{"RoleAdminChanged(bytes32,bytes32,bytes32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"bytes32",name:"previousAdminRole",type:"bytes32"},{indexed:!0,internalType:"bytes32",name:"newAdminRole",type:"bytes32"}],name:"RoleAdminChanged",type:"event"},"RoleGranted(bytes32,address,address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"address",name:"account",type:"address"},{indexed:!0,internalType:"address",name:"sender",type:"address"}],name:"RoleGranted",type:"event"},"RoleRevoked(bytes32,address,address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"address",name:"account",type:"address"},{indexed:!0,internalType:"address",name:"sender",type:"address"}],name:"RoleRevoked",type:"event"}},methods:{"coveredCallContract()":{inputs:[],name:"coveredCallContract",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"the address of the deployed CoveredCallFactory used by the protocol"},"getCollectionConfig(address,bytes32)":{inputs:[{internalType:"address",name:"collectionAddress",type:"address"},{internalType:"bytes32",name:"conf",type:"bytes32"}],name:"getCollectionConfig",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",params:{collectionAddress:"the collection for which to lookup a configuration flag",conf:"the config identifier for the configuration flag"},returns:{_0:"the true or false value of the config"},notice:"get a configuration flag with a specific key for a collection"},"getRoleAdmin(bytes32)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"}],name:"getRoleAdmin",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",details:"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getWETHAddress()":{inputs:[],name:"getWETHAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"these are values for popular chains: mainnet: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 kovan: 0xd0a1e359811322d97991e03f863a0c30c2cf029c ropsten: 0xc778417e063141139fce010982780140aa0cd5ab rinkeby: 0xc778417e063141139fce010982780140aa0cd5ab",returns:{_0:"the weth address"},notice:"the standard weth address on this chain"},"grantRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"grantRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"hasRole",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"renounceRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`."},"revokeRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"revokeRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."},"throwWhenPaused()":{inputs:[],name:"throwWhenPaused",outputs:[],stateMutability:"nonpayable",type:"function",notice:"callable function that reverts when the protocol is paused"},"vaultContract()":{inputs:[],name:"vaultContract",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"the address of the deployed VaultFactory used by the protocol"}}},"src/interfaces/IHookVault.sol:IHookVault":{source:"src/interfaces/IHookVault.sol",name:"IHookVault",title:"Generic Hook Vault-a vault designed to contain a single asset to be used as escrow.",author:"Jake Nyquist-j@hook.xyz",notice:'The Vault holds an asset on behalf of the owner. The owner is able to post this asset as collateral to other protocols by signing a message, called an "entitlement", that gives a specific account the ability to change the owner. The vault can work with multiple assets via the assetId, where the asset or set of assets covered by each segment is granted an individual id. Every asset must be identified by an assetId to comply with this interface, even if the vault only contains one asset. ENTITLEMENTS - (1) only one entitlement can be placed at a time. (2) entitlements must expire, but can also be cleared by the entitled party (3) if an entitlement expires, the current beneficial owner gains immediate sole control over the asset (4) the entitled entity can modify the beneficial owner of the asset, but cannot withdrawal. (5) the beneficial owner cannot modify the beneficial owner while an entitlement is in place',events:{"Approval(address,address,uint32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint32",name:"assetId",type:"uint32"}],name:"Approval",type:"event",notice:"Emitted when `beneficialOwner` enables `approved` to manage the `assetId` asset."},"AssetReceived(address,address,address,uint32)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"address",name:"sender",type:"address"},{indexed:!1,internalType:"address",name:"contractAddress",type:"address"},{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"}],name:"AssetReceived",type:"event",notice:"emitted when an asset is added into the vault"},"AssetWithdrawn(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"AssetWithdrawn",type:"event",notice:"emitted when an asset is withdrawn from the vault"},"BeneficialOwnerSet(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!1,internalType:"address",name:"setBy",type:"address"}],name:"BeneficialOwnerSet",type:"event",details:"it is not required that this event is emitted when an entitlement is imposed that also modifies the beneficial owner.",notice:"emitted when the beneficial owner of an asset changes"},"EntitlementCleared(uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementCleared",type:"event",notice:"emitted when an entitlement is cleared from an asset"},"EntitlementImposed(uint32,address,uint32,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"entitledAccount",type:"address"},{indexed:!1,internalType:"uint32",name:"expiry",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementImposed",type:"event",notice:"emitted when an entitlement is placed on an asset"}},methods:{"approveOperator(address,uint32)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"approveOperator",outputs:[],stateMutability:"nonpayable",type:"function",details:"Only a single account can be approved at a time, so approving the zero address clears previous approvals. * Requirements: - The caller must be the beneficial owner - `tokenId` must exist. Emits an {Approval} event.",notice:"Gives permission to `to` to impose an entitlement upon `assetId`"},"assetAddress(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"the contract address of the vaulted asset"},notice:"the contract address of the vaulted asset"},"clearEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"clearEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset to clear"},notice:"Allows the entitled address to release their claim on the asset"},"clearEntitlementAndDistribute(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiver",type:"address"}],name:"clearEntitlementAndDistribute",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the Id of the asset to clear",receiver:"the intended receiver of the asset"},notice:"Removes the active entitlement from a vault and returns the asset to the beneficial owner"},"entitlementExpiration(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"entitlementExpiration",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",details:"returns the 0 if no entitlement is set",returns:{_0:"the block timestamp after which the entitlement expires"},notice:"Looks up the expiration timestamp of the current entitlement"},"getApprovedOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getApprovedOperator",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"Returns the account approved for `tokenId` token. Requirements: - `assetId` must exist."},"getBeneficialOwner(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getBeneficialOwner",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"the address of the beneficial owner of the asset"},notice:"looks up the current beneficial owner of the asset"},"getCurrentEntitlementOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getCurrentEntitlementOperator",outputs:[{internalType:"bool",name:"",type:"bool"},{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the id of the underlying asset"},notice:"looks up the current operator of an entitlement on an asset"},"getHoldsAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getHoldsAsset",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"true if the asset is currently within the vault, false otherwise"},notice:"checks if the asset is currently stored in the vault"},"grantEntitlement((address,address,address,uint32,uint32))":{inputs:[{components:[{internalType:"address",name:"beneficialOwner",type:"address"},{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint32",name:"expiry",type:"uint32"}],internalType:"struct Entitlements.Entitlement",name:"entitlement",type:"tuple"}],name:"grantEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"this function call is signed by the sender per the EVM, so we know the entitlement is authentic",params:{entitlement:"The entitlement to impose onto the contract"},notice:"Allows the beneficial owner to grant an entitlement to an asset within the contract"},"imposeEntitlement(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"imposeEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset within the vault",expiry:"the duration of the entitlement",operator:"the operator to entitle",r:"sig r",s:"sig s",v:"sig v"},notice:"Add an entitlement claim to the asset held within the contract"},"setBeneficialOwner(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"newBeneficialOwner",type:"address"}],name:"setBeneficialOwner",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the subject asset to impose the entitlement",newBeneficialOwner:"the account of the person who is able to withdrawal when there are no entitlements."},notice:"setBeneficialOwner updates the current address that can claim the asset when it is free of entitlements."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."},"withdrawalAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"withdrawalAsset",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the asset to remove from the vault"},notice:"Withdrawal an unencumbered asset from this vault"}}},"src/interfaces/IInitializeableBeacon.sol:IInitializeableBeacon":{source:"src/interfaces/IInitializeableBeacon.sol",name:"IInitializeableBeacon",title:"Interface for a beacon with an initializer function",author:"Jake Nyquist-j@hook.xyz",details:"the Hook Beacons conform to this interface, and can be called with this initializer in order to start a beacon",methods:{"initializeBeacon(address,bytes)":{inputs:[{internalType:"address",name:"beacon",type:"address"},{internalType:"bytes",name:"data",type:"bytes"}],name:"initializeBeacon",outputs:[],stateMutability:"nonpayable",type:"function"}}},"src/interfaces/IWETH.sol:IWETH":{source:"src/interfaces/IWETH.sol",name:"IWETH",methods:{"deposit()":{inputs:[],name:"deposit",outputs:[],stateMutability:"payable",type:"function"},"transfer(address,uint256)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"value",type:"uint256"}],name:"transfer",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"nonpayable",type:"function"},"withdraw(uint256)":{inputs:[{internalType:"uint256",name:"wad",type:"uint256"}],name:"withdraw",outputs:[],stateMutability:"nonpayable",type:"function"}}},"src/lib/BeaconSalts.sol:BeaconSalts":{source:"src/lib/BeaconSalts.sol",name:"BeaconSalts"},"src/lib/Entitlements.sol:Entitlements":{source:"src/lib/Entitlements.sol",name:"Entitlements"},"src/lib/HookStrings.sol:HookStrings":{source:"src/lib/HookStrings.sol",name:"HookStrings"},"src/lib/Signatures.sol:Signatures":{source:"src/lib/Signatures.sol",name:"Signatures",details:"A library for validating signatures from ZeroEx"},"src/lib/TokenURI.sol:TokenURI":{source:"src/lib/TokenURI.sol",name:"TokenURI",details:"This contract implements some ERC721 / for hook instruments.",methods:{"tokenURIERC721(uint256,address,uint256,uint256,uint256,uint256)":{inputs:[{internalType:"uint256",name:"instrumentId",type:"uint256"},{internalType:"address",name:"underlyingAddress",type:"address"},{internalType:"uint256",name:"underlyingTokenId",type:"uint256"},{internalType:"uint256",name:"instrumentExpiration",type:"uint256"},{internalType:"uint256",name:"instrumentStrike",type:"uint256"},{internalType:"uint256",name:"transfers",type:"uint256"}],name:"tokenURIERC721",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"this is a basic tokenURI based on the loot contract for an ERC721"}}},"src/mixin/EIP712.sol:EIP712":{source:"src/mixin/EIP712.sol",name:"EIP712",details:"EIP712 helpers for features.",stateVariables:{"EIP712_DOMAIN_SEPARATOR()":{inputs:[],name:"EIP712_DOMAIN_SEPARATOR",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"stateVariable",details:"The domain hash separator for the entire call option protocol"}}},"src/mixin/HookInstrumentERC721.sol:HookInstrumentERC721":{source:"src/mixin/HookInstrumentERC721.sol",name:"HookInstrumentERC721",details:"This contract implements some ERC721 / for hook instruments.",events:{"Approval(address,address,uint256)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"owner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint256",name:"tokenId",type:"uint256"}],name:"Approval",type:"event"},"ApprovalForAll(address,address,bool)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"owner",type:"address"},{indexed:!0,internalType:"address",name:"operator",type:"address"},{indexed:!1,internalType:"bool",name:"approved",type:"bool"}],name:"ApprovalForAll",type:"event"},"Transfer(address,address,uint256)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"from",type:"address"},{indexed:!0,internalType:"address",name:"to",type:"address"},{indexed:!0,internalType:"uint256",name:"tokenId",type:"uint256"}],name:"Transfer",type:"event"}},stateVariables:{"_preApprovedMarketplace()":{inputs:[],name:"_preApprovedMarketplace",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"stateVariable",details:"the contact address for a marketplace to pre-approve"}},methods:{"approve(address,uint256)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"approve",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-approve}."},"balanceOf(address)":{inputs:[{internalType:"address",name:"owner",type:"address"}],name:"balanceOf",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"See {IERC721-balanceOf}."},"burn(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"burn",outputs:[],stateMutability:"nonpayable",type:"function",details:"Burns `tokenId`. See {ERC721-_burn}. Requirements: - The caller must own `tokenId` or be an approved operator."},"contractUri(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"contractUri",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"this is the OpenSea compatible collection - level metadata URI."},"getApproved(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"getApproved",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IERC721-getApproved}."},"getAssetId(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getAssetId",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",notice:"getter for the assetId of the underlying asset within a vault"},"getExpiration(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getExpiration",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",notice:"getter for the options expiration. After this time the option is invalid"},"getStrikePrice(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getStrikePrice",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",notice:"getter for the option strike price"},"getTransferCount(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getTransferCount",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"this count can be used by overbooks to invalidate orders after a token has been transferred, preventing stale order execution by malicious parties",notice:"the number of times the token has been transferred"},"getVaultAddress(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getVaultAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"getter for the address holding the underlying asset"},"isApprovedForAll(address,address)":{inputs:[{internalType:"address",name:"owner",type:"address"},{internalType:"address",name:"operator",type:"address"}],name:"isApprovedForAll",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC721-isApprovedForAll}. this extension ensures that any operator contract located at {_approvedMarketpace} is considered approved internally in the ERC721 contract"},"name()":{inputs:[],name:"name",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"See {IERC721Metadata-name}."},"ownerOf(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"ownerOf",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IERC721-ownerOf}."},"safeTransferFrom(address,address,uint256)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"safeTransferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-safeTransferFrom}."},"safeTransferFrom(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"_data",type:"bytes"}],name:"safeTransferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-safeTransferFrom}."},"setApprovalForAll(address,bool)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"bool",name:"approved",type:"bool"}],name:"setApprovalForAll",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-setApprovalForAll}."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC165-supportsInterface}."},"symbol()":{inputs:[],name:"symbol",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"See {IERC721Metadata-symbol}."},"tokenURI(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"tokenURI",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"See {IERC721-tokenURI}."},"transferFrom(address,address,uint256)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"transferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-transferFrom}."}}},"src/mixin/PermissionConstants.sol:PermissionConstants":{source:"src/mixin/PermissionConstants.sol",name:"PermissionConstants",details:"new roles here should be initialized in the constructor of the protocol",notice:"roles on the hook protocol that can be read by other contract",methods:{"ALLOWLISTER_ROLE()":{inputs:[],name:"ALLOWLISTER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the allowlister is able to enable and disable projects to mint instruments"},"CALL_UPGRADER()":{inputs:[],name:"CALL_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the call upgrader role is able to upgrade the implementation of the covered call options"},"COLLECTION_CONF()":{inputs:[],name:"COLLECTION_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the collection configuration role allows the actor to make changes the collection configs on the protocol contract"},"MARKET_CONF()":{inputs:[],name:"MARKET_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the market configuration role allows the actor to make changes to how the market operates"},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the pauser is able to start and pause various components of the protocol"},"VAULT_UPGRADER()":{inputs:[],name:"VAULT_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the vault upgrader role is able to upgrade the implementation for all vaults"}}}};new wo({el:"#app",router:new du({routes:[{path:"/",component:ju,props:()=>({json:Hu})},{path:"*",component:Su,props:e=>({json:Hu[e.path.slice(1)]})}]}),mounted(){document.dispatchEvent(new Event("render-event"))},render:e=>e(fu)})})()})(); \ No newline at end of file +(()=>{var e={268:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});var a=n(81),i=n.n(a),r=n(645),s=n.n(r)()(i());s.push([e.id,"@import url(https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@400;500;600;700&display=swap);"]),s.push([e.id,"\nhtml,\nbody {\n font-family: 'Source Code Pro', monospace;\n}\n",""]);const o=s},645:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n="",a=void 0!==t[5];return t[4]&&(n+="@supports (".concat(t[4],") {")),t[2]&&(n+="@media ".concat(t[2]," {")),a&&(n+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),n+=e(t),a&&(n+="}"),t[2]&&(n+="}"),t[4]&&(n+="}"),n})).join("")},t.i=function(e,n,a,i,r){"string"==typeof e&&(e=[[null,e,void 0]]);var s={};if(a)for(var o=0;o0?" ".concat(p[5]):""," {").concat(p[1],"}")),p[5]=r),n&&(p[2]?(p[1]="@media ".concat(p[2]," {").concat(p[1],"}"),p[2]=n):p[2]=n),i&&(p[4]?(p[1]="@supports (".concat(p[4],") {").concat(p[1],"}"),p[4]=i):p[4]="".concat(i)),t.push(p))}},t}},81:e=>{"use strict";e.exports=function(e){return e[1]}},387:(e,t,n)=>{var a=n(268);a.__esModule&&(a=a.default),"string"==typeof a&&(a=[[e.id,a,""]]),a.locals&&(e.exports=a.locals),(0,n(346).Z)("0b345cf4",a,!1,{})},346:(e,t,n)=>{"use strict";function a(e,t){for(var n=[],a={},i=0;im});var i="undefined"!=typeof document;if("undefined"!=typeof DEBUG&&DEBUG&&!i)throw new Error("vue-style-loader cannot be used in a non-browser environment. Use { target: 'node' } in your Webpack config to indicate a server-rendering environment.");var r={},s=i&&(document.head||document.getElementsByTagName("head")[0]),o=null,l=0,u=!1,p=function(){},d=null,c="data-vue-ssr-id",y="undefined"!=typeof navigator&&/msie [6-9]\b/.test(navigator.userAgent.toLowerCase());function m(e,t,n,i){u=n,d=i||{};var s=a(e,t);return f(s),function(t){for(var n=[],i=0;in.parts.length&&(a.parts.length=n.parts.length)}else{var s=[];for(i=0;i{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{"use strict";var e=Object.freeze({});function t(e){return null==e}function a(e){return null!=e}function i(e){return!0===e}function r(e){return"string"==typeof e||"number"==typeof e||"symbol"==typeof e||"boolean"==typeof e}function s(e){return null!==e&&"object"==typeof e}var o=Object.prototype.toString;function l(e){return"[object Object]"===o.call(e)}function u(e){var t=parseFloat(String(e));return t>=0&&Math.floor(t)===t&&isFinite(e)}function p(e){return a(e)&&"function"==typeof e.then&&"function"==typeof e.catch}function d(e){return null==e?"":Array.isArray(e)||l(e)&&e.toString===o?JSON.stringify(e,null,2):String(e)}function c(e){var t=parseFloat(e);return isNaN(t)?e:t}function y(e,t){for(var n=Object.create(null),a=e.split(","),i=0;i-1)return e.splice(n,1)}}var v=Object.prototype.hasOwnProperty;function b(e,t){return v.call(e,t)}function g(e){var t=Object.create(null);return function(n){return t[n]||(t[n]=e(n))}}var T=/-(\w)/g,w=g((function(e){return e.replace(T,(function(e,t){return t?t.toUpperCase():""}))})),k=g((function(e){return e.charAt(0).toUpperCase()+e.slice(1)})),I=/\B([A-Z])/g,C=g((function(e){return e.replace(I,"-$1").toLowerCase()})),_=Function.prototype.bind?function(e,t){return e.bind(t)}:function(e,t){function n(n){var a=arguments.length;return a?a>1?e.apply(t,arguments):e.call(t,n):e.call(t)}return n._length=e.length,n};function x(e,t){t=t||0;for(var n=e.length-t,a=new Array(n);n--;)a[n]=e[n+t];return a}function A(e,t){for(var n in t)e[n]=t[n];return e}function E(e){for(var t={},n=0;n0,X=J&&J.indexOf("edge/")>0,Y=(J&&J.indexOf("android"),J&&/iphone|ipad|ipod|ios/.test(J)||"ios"===G),Q=(J&&/chrome\/\d+/.test(J),J&&/phantomjs/.test(J),J&&J.match(/firefox\/(\d+)/)),ee={}.watch,te=!1;if(q)try{var ne={};Object.defineProperty(ne,"passive",{get:function(){te=!0}}),window.addEventListener("test-passive",null,ne)}catch(e){}var ae=function(){return void 0===B&&(B=!q&&!W&&void 0!==n.g&&n.g.process&&"server"===n.g.process.env.VUE_ENV),B},ie=q&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function re(e){return"function"==typeof e&&/native code/.test(e.toString())}var se,oe="undefined"!=typeof Symbol&&re(Symbol)&&"undefined"!=typeof Reflect&&re(Reflect.ownKeys);se="undefined"!=typeof Set&&re(Set)?Set:function(){function e(){this.set=Object.create(null)}return e.prototype.has=function(e){return!0===this.set[e]},e.prototype.add=function(e){this.set[e]=!0},e.prototype.clear=function(){this.set=Object.create(null)},e}();var le=R,ue=0,pe=function(){this.id=ue++,this.subs=[]};pe.prototype.addSub=function(e){this.subs.push(e)},pe.prototype.removeSub=function(e){h(this.subs,e)},pe.prototype.depend=function(){pe.target&&pe.target.addDep(this)},pe.prototype.notify=function(){for(var e=this.subs.slice(),t=0,n=e.length;t-1)if(r&&!b(i,"default"))s=!1;else if(""===s||s===C(e)){var l=Be(String,i.type);(l<0||o0&&(ct((o=yt(o,(n||"")+"_"+s))[0])&&ct(u)&&(p[l]=ve(u.text+o[0].text),o.shift()),p.push.apply(p,o)):r(o)?ct(u)?p[l]=ve(u.text+o):""!==o&&p.push(ve(o)):ct(o)&&ct(u)?p[l]=ve(u.text+o.text):(i(e._isVList)&&a(o.tag)&&t(o.key)&&a(n)&&(o.key="__vlist"+n+"_"+s+"__"),p.push(o)));return p}function mt(e,t){if(e){for(var n=Object.create(null),a=oe?Reflect.ownKeys(e):Object.keys(e),i=0;i0,s=t?!!t.$stable:!r,o=t&&t.$key;if(t){if(t._normalized)return t._normalized;if(s&&a&&a!==e&&o===a.$key&&!r&&!a.$hasNormal)return a;for(var l in i={},t)t[l]&&"$"!==l[0]&&(i[l]=gt(n,l,t[l]))}else i={};for(var u in n)u in i||(i[u]=Tt(n,u));return t&&Object.isExtensible(t)&&(t._normalized=i),D(i,"$stable",s),D(i,"$key",o),D(i,"$hasNormal",r),i}function gt(e,t,n){var a=function(){var e=arguments.length?n.apply(null,arguments):n({}),t=(e=e&&"object"==typeof e&&!Array.isArray(e)?[e]:dt(e))&&e[0];return e&&(!t||1===e.length&&t.isComment&&!vt(t))?void 0:e};return n.proxy&&Object.defineProperty(e,t,{get:a,enumerable:!0,configurable:!0}),a}function Tt(e,t){return function(){return e[t]}}function wt(e,t){var n,i,r,o,l;if(Array.isArray(e)||"string"==typeof e)for(n=new Array(e.length),i=0,r=e.length;idocument.createEvent("Event").timeStamp&&(fn=function(){return hn.now()})}function vn(){var e,t;for(mn=fn(),cn=!0,ln.sort((function(e,t){return e.id-t.id})),yn=0;ynyn&&ln[n].id>e.id;)n--;ln.splice(n+1,0,e)}else ln.push(e);dn||(dn=!0,nt(vn))}}(this)},gn.prototype.run=function(){if(this.active){var e=this.get();if(e!==this.value||s(e)||this.deep){var t=this.value;if(this.value=e,this.user){var n='callback for watcher "'+this.expression+'"';ze(this.cb,this.vm,[e,t],this.vm,n)}else this.cb.call(this.vm,e,t)}}},gn.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},gn.prototype.depend=function(){for(var e=this.deps.length;e--;)this.deps[e].depend()},gn.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||h(this.vm._watchers,this);for(var e=this.deps.length;e--;)this.deps[e].removeSub(this);this.active=!1}};var Tn={enumerable:!0,configurable:!0,get:R,set:R};function wn(e,t,n){Tn.get=function(){return this[t][n]},Tn.set=function(e){this[t][n]=e},Object.defineProperty(e,n,Tn)}var kn={lazy:!0};function In(e,t,n){var a=!ae();"function"==typeof n?(Tn.get=a?Cn(t):_n(n),Tn.set=R):(Tn.get=n.get?a&&!1!==n.cache?Cn(t):_n(n.get):R,Tn.set=n.set||R),Object.defineProperty(e,t,Tn)}function Cn(e){return function(){var t=this._computedWatchers&&this._computedWatchers[e];if(t)return t.dirty&&t.evaluate(),pe.target&&t.depend(),t.value}}function _n(e){return function(){return e.call(this,this)}}function xn(e,t,n,a){return l(n)&&(a=n,n=n.handler),"string"==typeof n&&(n=e[n]),e.$watch(t,n,a)}var An=0;function En(e){var t=e.options;if(e.super){var n=En(e.super);if(n!==e.superOptions){e.superOptions=n;var a=function(e){var t,n=e.options,a=e.sealedOptions;for(var i in n)n[i]!==a[i]&&(t||(t={}),t[i]=n[i]);return t}(e);a&&A(e.extendOptions,a),(t=e.options=Fe(n,e.extendOptions)).name&&(t.components[t.name]=e)}}return t}function Rn(e){this._init(e)}function On(e){return e&&(e.Ctor.options.name||e.tag)}function Mn(e,t){return Array.isArray(e)?e.indexOf(t)>-1:"string"==typeof e?e.split(",").indexOf(t)>-1:(n=e,!("[object RegExp]"!==o.call(n))&&e.test(t));var n}function Sn(e,t){var n=e.cache,a=e.keys,i=e._vnode;for(var r in n){var s=n[r];if(s){var o=s.name;o&&!t(o)&&Pn(n,r,a,i)}}}function Pn(e,t,n,a){var i=e[t];!i||a&&i.tag===a.tag||i.componentInstance.$destroy(),e[t]=null,h(n,t)}!function(t){t.prototype._init=function(t){var n=this;n._uid=An++,n._isVue=!0,t&&t._isComponent?function(e,t){var n=e.$options=Object.create(e.constructor.options),a=t._parentVnode;n.parent=t.parent,n._parentVnode=a;var i=a.componentOptions;n.propsData=i.propsData,n._parentListeners=i.listeners,n._renderChildren=i.children,n._componentTag=i.tag,t.render&&(n.render=t.render,n.staticRenderFns=t.staticRenderFns)}(n,t):n.$options=Fe(En(n.constructor),t||{},n),n._renderProxy=n,n._self=n,function(e){var t=e.$options,n=t.parent;if(n&&!t.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(e)}e.$parent=n,e.$root=n?n.$root:e,e.$children=[],e.$refs={},e._watcher=null,e._inactive=null,e._directInactive=!1,e._isMounted=!1,e._isDestroyed=!1,e._isBeingDestroyed=!1}(n),function(e){e._events=Object.create(null),e._hasHookEvent=!1;var t=e.$options._parentListeners;t&&en(e,t)}(n),function(t){t._vnode=null,t._staticTrees=null;var n=t.$options,a=t.$vnode=n._parentVnode,i=a&&a.context;t.$slots=ft(n._renderChildren,i),t.$scopedSlots=e,t._c=function(e,n,a,i){return qt(t,e,n,a,i,!1)},t.$createElement=function(e,n,a,i){return qt(t,e,n,a,i,!0)};var r=a&&a.data;xe(t,"$attrs",r&&r.attrs||e,null,!0),xe(t,"$listeners",n._parentListeners||e,null,!0)}(n),on(n,"beforeCreate"),function(e){var t=mt(e.$options.inject,e);t&&(Ie(!1),Object.keys(t).forEach((function(n){xe(e,n,t[n])})),Ie(!0))}(n),function(e){e._watchers=[];var t=e.$options;t.props&&function(e,t){var n=e.$options.propsData||{},a=e._props={},i=e.$options._propKeys=[];!e.$parent||Ie(!1);var r=function(r){i.push(r);var s=He(r,t,n,e);xe(a,r,s),r in e||wn(e,"_props",r)};for(var s in t)r(s);Ie(!0)}(e,t.props),t.methods&&function(e,t){for(var n in e.$options.props,t)e[n]="function"!=typeof t[n]?R:_(t[n],e)}(e,t.methods),t.data?function(e){var t=e.$options.data;l(t=e._data="function"==typeof t?function(e,t){ce();try{return e.call(t,t)}catch(e){return Ue(e,t,"data()"),{}}finally{ye()}}(t,e):t||{})||(t={});for(var n=Object.keys(t),a=e.$options.props,i=(e.$options.methods,n.length);i--;){var r=n[i];a&&b(a,r)||N(r)||wn(e,"_data",r)}_e(t,!0)}(e):_e(e._data={},!0),t.computed&&function(e,t){var n=e._computedWatchers=Object.create(null),a=ae();for(var i in t){var r=t[i],s="function"==typeof r?r:r.get;a||(n[i]=new gn(e,s||R,R,kn)),i in e||In(e,i,r)}}(e,t.computed),t.watch&&t.watch!==ee&&function(e,t){for(var n in t){var a=t[n];if(Array.isArray(a))for(var i=0;i1?x(n):n;for(var a=x(arguments,1),i='event handler for "'+e+'"',r=0,s=n.length;rparseInt(this.max)&&Pn(t,n[0],n,this._vnode),this.vnodeToCache=null}}},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){for(var e in this.cache)Pn(this.cache,e,this.keys)},mounted:function(){var e=this;this.cacheVNode(),this.$watch("include",(function(t){Sn(e,(function(e){return Mn(t,e)}))})),this.$watch("exclude",(function(t){Sn(e,(function(e){return!Mn(t,e)}))}))},updated:function(){this.cacheVNode()},render:function(){var e=this.$slots.default,t=Zt(e),n=t&&t.componentOptions;if(n){var a=On(n),i=this.include,r=this.exclude;if(i&&(!a||!Mn(i,a))||r&&a&&Mn(r,a))return t;var s=this.cache,o=this.keys,l=null==t.key?n.Ctor.cid+(n.tag?"::"+n.tag:""):t.key;s[l]?(t.componentInstance=s[l].componentInstance,h(o,l),o.push(l)):(this.vnodeToCache=t,this.keyToCache=l),t.data.keepAlive=!0}return t||e&&e[0]}},Fn={KeepAlive:Ln};!function(e){var t={get:function(){return H}};Object.defineProperty(e,"config",t),e.util={warn:le,extend:A,mergeOptions:Fe,defineReactive:xe},e.set=Ae,e.delete=Ee,e.nextTick=nt,e.observable=function(e){return _e(e),e},e.options=Object.create(null),F.forEach((function(t){e.options[t+"s"]=Object.create(null)})),e.options._base=e,A(e.options.components,Fn),function(e){e.use=function(e){var t=this._installedPlugins||(this._installedPlugins=[]);if(t.indexOf(e)>-1)return this;var n=x(arguments,1);return n.unshift(this),"function"==typeof e.install?e.install.apply(e,n):"function"==typeof e&&e.apply(null,n),t.push(e),this}}(e),function(e){e.mixin=function(e){return this.options=Fe(this.options,e),this}}(e),function(e){e.cid=0;var t=1;e.extend=function(e){e=e||{};var n=this,a=n.cid,i=e._Ctor||(e._Ctor={});if(i[a])return i[a];var r=e.name||n.options.name,s=function(e){this._init(e)};return(s.prototype=Object.create(n.prototype)).constructor=s,s.cid=t++,s.options=Fe(n.options,e),s.super=n,s.options.props&&function(e){var t=e.options.props;for(var n in t)wn(e.prototype,"_props",n)}(s),s.options.computed&&function(e){var t=e.options.computed;for(var n in t)In(e.prototype,n,t[n])}(s),s.extend=n.extend,s.mixin=n.mixin,s.use=n.use,F.forEach((function(e){s[e]=n[e]})),r&&(s.options.components[r]=s),s.superOptions=n.options,s.extendOptions=e,s.sealedOptions=A({},s.options),i[a]=s,s}}(e),function(e){F.forEach((function(t){e[t]=function(e,n){return n?("component"===t&&l(n)&&(n.name=n.name||e,n=this.options._base.extend(n)),"directive"===t&&"function"==typeof n&&(n={bind:n,update:n}),this.options[t+"s"][e]=n,n):this.options[t+"s"][e]}}))}(e)}(Rn),Object.defineProperty(Rn.prototype,"$isServer",{get:ae}),Object.defineProperty(Rn.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(Rn,"FunctionalRenderContext",{value:Ft}),Rn.version="2.6.14";var Vn=y("style,class"),Hn=y("input,textarea,option,select,progress"),jn=function(e,t,n){return"value"===n&&Hn(e)&&"button"!==t||"selected"===n&&"option"===e||"checked"===n&&"input"===e||"muted"===n&&"video"===e},Nn=y("contenteditable,draggable,spellcheck"),Dn=y("events,caret,typing,plaintext-only"),Bn=function(e,t){return Gn(t)||"false"===t?"false":"contenteditable"===e&&Dn(t)?t:"true"},Un=y("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,truespeed,typemustmatch,visible"),zn="http://www.w3.org/1999/xlink",qn=function(e){return":"===e.charAt(5)&&"xlink"===e.slice(0,5)},Wn=function(e){return qn(e)?e.slice(6,e.length):""},Gn=function(e){return null==e||!1===e};function Jn(e,t){return{staticClass:Kn(e.staticClass,t.staticClass),class:a(e.class)?[e.class,t.class]:t.class}}function Kn(e,t){return e?t?e+" "+t:e:t||""}function Zn(e){return Array.isArray(e)?function(e){for(var t,n="",i=0,r=e.length;i-1?wa(e,t,n):Un(t)?Gn(n)?e.removeAttribute(t):(n="allowfullscreen"===t&&"EMBED"===e.tagName?"true":t,e.setAttribute(t,n)):Nn(t)?e.setAttribute(t,Bn(t,n)):qn(t)?Gn(n)?e.removeAttributeNS(zn,Wn(t)):e.setAttributeNS(zn,t,n):wa(e,t,n)}function wa(e,t,n){if(Gn(n))e.removeAttribute(t);else{if(K&&!Z&&"TEXTAREA"===e.tagName&&"placeholder"===t&&""!==n&&!e.__ieph){var a=function(t){t.stopImmediatePropagation(),e.removeEventListener("input",a)};e.addEventListener("input",a),e.__ieph=!0}e.setAttribute(t,n)}}var ka={create:ga,update:ga};function Ia(e,n){var i=n.elm,r=n.data,s=e.data;if(!(t(r.staticClass)&&t(r.class)&&(t(s)||t(s.staticClass)&&t(s.class)))){var o=function(e){for(var t=e.data,n=e,i=e;a(i.componentInstance);)(i=i.componentInstance._vnode)&&i.data&&(t=Jn(i.data,t));for(;a(n=n.parent);)n&&n.data&&(t=Jn(t,n.data));return r=t.staticClass,s=t.class,a(r)||a(s)?Kn(r,Zn(s)):"";var r,s}(n),l=i._transitionClasses;a(l)&&(o=Kn(o,Zn(l))),o!==i._prevClass&&(i.setAttribute("class",o),i._prevClass=o)}}var Ca,_a,xa,Aa,Ea,Ra,Oa={create:Ia,update:Ia},Ma=/[\w).+\-_$\]]/;function Sa(e){var t,n,a,i,r,s=!1,o=!1,l=!1,u=!1,p=0,d=0,c=0,y=0;for(a=0;a=0&&" "===(f=e.charAt(m));m--);f&&Ma.test(f)||(u=!0)}}else void 0===i?(y=a+1,i=e.slice(0,a).trim()):h();function h(){(r||(r=[])).push(e.slice(y,a).trim()),y=a+1}if(void 0===i?i=e.slice(0,a).trim():0!==y&&h(),r)for(a=0;a-1?{exp:e.slice(0,Aa),key:'"'+e.slice(Aa+1)+'"'}:{exp:e,key:null};for(_a=e,Aa=Ea=Ra=0;!Ka();)Za(xa=Ja())?Ya(xa):91===xa&&Xa(xa);return{exp:e.slice(0,Ea),key:e.slice(Ea+1,Ra)}}(e);return null===n.key?e+"="+t:"$set("+n.exp+", "+n.key+", "+t+")"}function Ja(){return _a.charCodeAt(++Aa)}function Ka(){return Aa>=Ca}function Za(e){return 34===e||39===e}function Xa(e){var t=1;for(Ea=Aa;!Ka();)if(Za(e=Ja()))Ya(e);else if(91===e&&t++,93===e&&t--,0===t){Ra=Aa;break}}function Ya(e){for(var t=e;!Ka()&&(e=Ja())!==t;);}var Qa,ei="__r",ti="__c";function ni(e,t,n){var a=Qa;return function i(){null!==t.apply(null,arguments)&&ri(e,i,n,a)}}var ai=Je&&!(Q&&Number(Q[1])<=53);function ii(e,t,n,a){if(ai){var i=mn,r=t;t=r._wrapper=function(e){if(e.target===e.currentTarget||e.timeStamp>=i||e.timeStamp<=0||e.target.ownerDocument!==document)return r.apply(this,arguments)}}Qa.addEventListener(e,t,te?{capture:n,passive:a}:n)}function ri(e,t,n,a){(a||Qa).removeEventListener(e,t._wrapper||t,n)}function si(e,n){if(!t(e.data.on)||!t(n.data.on)){var i=n.data.on||{},r=e.data.on||{};Qa=n.elm,function(e){if(a(e[ei])){var t=K?"change":"input";e[t]=[].concat(e[ei],e[t]||[]),delete e[ei]}a(e[ti])&&(e.change=[].concat(e[ti],e.change||[]),delete e[ti])}(i),lt(i,r,ii,ri,ni,n.context),Qa=void 0}}var oi,li={create:si,update:si};function ui(e,n){if(!t(e.data.domProps)||!t(n.data.domProps)){var i,r,s=n.elm,o=e.data.domProps||{},l=n.data.domProps||{};for(i in a(l.__ob__)&&(l=n.data.domProps=A({},l)),o)i in l||(s[i]="");for(i in l){if(r=l[i],"textContent"===i||"innerHTML"===i){if(n.children&&(n.children.length=0),r===o[i])continue;1===s.childNodes.length&&s.removeChild(s.childNodes[0])}if("value"===i&&"PROGRESS"!==s.tagName){s._value=r;var u=t(r)?"":String(r);pi(s,u)&&(s.value=u)}else if("innerHTML"===i&&Qn(s.tagName)&&t(s.innerHTML)){(oi=oi||document.createElement("div")).innerHTML=""+r+"";for(var p=oi.firstChild;s.firstChild;)s.removeChild(s.firstChild);for(;p.firstChild;)s.appendChild(p.firstChild)}else if(r!==o[i])try{s[i]=r}catch(e){}}}}function pi(e,t){return!e.composing&&("OPTION"===e.tagName||function(e,t){var n=!0;try{n=document.activeElement!==e}catch(e){}return n&&e.value!==t}(e,t)||function(e,t){var n=e.value,i=e._vModifiers;if(a(i)){if(i.number)return c(n)!==c(t);if(i.trim)return n.trim()!==t.trim()}return n!==t}(e,t))}var di={create:ui,update:ui},ci=g((function(e){var t={},n=/:(.+)/;return e.split(/;(?![^(]*\))/g).forEach((function(e){if(e){var a=e.split(n);a.length>1&&(t[a[0].trim()]=a[1].trim())}})),t}));function yi(e){var t=mi(e.style);return e.staticStyle?A(e.staticStyle,t):t}function mi(e){return Array.isArray(e)?E(e):"string"==typeof e?ci(e):e}var fi,hi=/^--/,vi=/\s*!important$/,bi=function(e,t,n){if(hi.test(t))e.style.setProperty(t,n);else if(vi.test(n))e.style.setProperty(C(t),n.replace(vi,""),"important");else{var a=Ti(t);if(Array.isArray(n))for(var i=0,r=n.length;i-1?t.split(Ii).forEach((function(t){return e.classList.add(t)})):e.classList.add(t);else{var n=" "+(e.getAttribute("class")||"")+" ";n.indexOf(" "+t+" ")<0&&e.setAttribute("class",(n+t).trim())}}function _i(e,t){if(t&&(t=t.trim()))if(e.classList)t.indexOf(" ")>-1?t.split(Ii).forEach((function(t){return e.classList.remove(t)})):e.classList.remove(t),e.classList.length||e.removeAttribute("class");else{for(var n=" "+(e.getAttribute("class")||"")+" ",a=" "+t+" ";n.indexOf(a)>=0;)n=n.replace(a," ");(n=n.trim())?e.setAttribute("class",n):e.removeAttribute("class")}}function xi(e){if(e){if("object"==typeof e){var t={};return!1!==e.css&&A(t,Ai(e.name||"v")),A(t,e),t}return"string"==typeof e?Ai(e):void 0}}var Ai=g((function(e){return{enterClass:e+"-enter",enterToClass:e+"-enter-to",enterActiveClass:e+"-enter-active",leaveClass:e+"-leave",leaveToClass:e+"-leave-to",leaveActiveClass:e+"-leave-active"}})),Ei=q&&!Z,Ri="transition",Oi="animation",Mi="transition",Si="transitionend",Pi="animation",$i="animationend";Ei&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(Mi="WebkitTransition",Si="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(Pi="WebkitAnimation",$i="webkitAnimationEnd"));var Li=q?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(e){return e()};function Fi(e){Li((function(){Li(e)}))}function Vi(e,t){var n=e._transitionClasses||(e._transitionClasses=[]);n.indexOf(t)<0&&(n.push(t),Ci(e,t))}function Hi(e,t){e._transitionClasses&&h(e._transitionClasses,t),_i(e,t)}function ji(e,t,n){var a=Di(e,t),i=a.type,r=a.timeout,s=a.propCount;if(!i)return n();var o=i===Ri?Si:$i,l=0,u=function(){e.removeEventListener(o,p),n()},p=function(t){t.target===e&&++l>=s&&u()};setTimeout((function(){l0&&(n=Ri,p=s,d=r.length):t===Oi?u>0&&(n=Oi,p=u,d=l.length):d=(n=(p=Math.max(s,u))>0?s>u?Ri:Oi:null)?n===Ri?r.length:l.length:0,{type:n,timeout:p,propCount:d,hasTransform:n===Ri&&Ni.test(a[Mi+"Property"])}}function Bi(e,t){for(;e.length1}function Ji(e,t){!0!==t.data.show&&zi(t)}var Ki=function(e){var n,s,o={},l=e.modules,u=e.nodeOps;for(n=0;nm?g(e,t(i[v+1])?null:i[v+1].elm,i,y,v,r):y>v&&w(n,c,m)}(c,f,v,r,p):a(v)?(a(e.text)&&u.setTextContent(c,""),g(c,null,v,0,v.length-1,r)):a(f)?w(f,0,f.length-1):a(e.text)&&u.setTextContent(c,""):e.text!==n.text&&u.setTextContent(c,n.text),a(m)&&a(y=m.hook)&&a(y=y.postpatch)&&y(e,n)}}}function _(e,t,n){if(i(n)&&a(e.parent))e.parent.data.pendingInsert=t;else for(var r=0;r-1,s.selected!==r&&(s.selected=r);else if(S(er(s),a))return void(e.selectedIndex!==o&&(e.selectedIndex=o));i||(e.selectedIndex=-1)}}function Qi(e,t){return t.every((function(t){return!S(t,e)}))}function er(e){return"_value"in e?e._value:e.value}function tr(e){e.target.composing=!0}function nr(e){e.target.composing&&(e.target.composing=!1,ar(e.target,"input"))}function ar(e,t){var n=document.createEvent("HTMLEvents");n.initEvent(t,!0,!0),e.dispatchEvent(n)}function ir(e){return!e.componentInstance||e.data&&e.data.transition?e:ir(e.componentInstance._vnode)}var rr={bind:function(e,t,n){var a=t.value,i=(n=ir(n)).data&&n.data.transition,r=e.__vOriginalDisplay="none"===e.style.display?"":e.style.display;a&&i?(n.data.show=!0,zi(n,(function(){e.style.display=r}))):e.style.display=a?r:"none"},update:function(e,t,n){var a=t.value;!a!=!t.oldValue&&((n=ir(n)).data&&n.data.transition?(n.data.show=!0,a?zi(n,(function(){e.style.display=e.__vOriginalDisplay})):qi(n,(function(){e.style.display="none"}))):e.style.display=a?e.__vOriginalDisplay:"none")},unbind:function(e,t,n,a,i){i||(e.style.display=e.__vOriginalDisplay)}},sr={model:Zi,show:rr},or={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function lr(e){var t=e&&e.componentOptions;return t&&t.Ctor.options.abstract?lr(Zt(t.children)):e}function ur(e){var t={},n=e.$options;for(var a in n.propsData)t[a]=e[a];var i=n._parentListeners;for(var r in i)t[w(r)]=i[r];return t}function pr(e,t){if(/\d-keep-alive$/.test(t.tag))return e("keep-alive",{props:t.componentOptions.propsData})}var dr=function(e){return e.tag||vt(e)},cr=function(e){return"show"===e.name},yr={name:"transition",props:or,abstract:!0,render:function(e){var t=this,n=this.$slots.default;if(n&&(n=n.filter(dr)).length){var a=this.mode,i=n[0];if(function(e){for(;e=e.parent;)if(e.data.transition)return!0}(this.$vnode))return i;var s=lr(i);if(!s)return i;if(this._leaving)return pr(e,i);var o="__transition-"+this._uid+"-";s.key=null==s.key?s.isComment?o+"comment":o+s.tag:r(s.key)?0===String(s.key).indexOf(o)?s.key:o+s.key:s.key;var l=(s.data||(s.data={})).transition=ur(this),u=this._vnode,p=lr(u);if(s.data.directives&&s.data.directives.some(cr)&&(s.data.show=!0),p&&p.data&&!function(e,t){return t.key===e.key&&t.tag===e.tag}(s,p)&&!vt(p)&&(!p.componentInstance||!p.componentInstance._vnode.isComment)){var d=p.data.transition=A({},l);if("out-in"===a)return this._leaving=!0,ut(d,"afterLeave",(function(){t._leaving=!1,t.$forceUpdate()})),pr(e,i);if("in-out"===a){if(vt(s))return u;var c,y=function(){c()};ut(l,"afterEnter",y),ut(l,"enterCancelled",y),ut(d,"delayLeave",(function(e){c=e}))}}return i}}},mr=A({tag:String,moveClass:String},or);delete mr.mode;var fr={props:mr,beforeMount:function(){var e=this,t=this._update;this._update=function(n,a){var i=nn(e);e.__patch__(e._vnode,e.kept,!1,!0),e._vnode=e.kept,i(),t.call(e,n,a)}},render:function(e){for(var t=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),a=this.prevChildren=this.children,i=this.$slots.default||[],r=this.children=[],s=ur(this),o=0;o-1?na[e]=t.constructor===window.HTMLUnknownElement||t.constructor===window.HTMLElement:na[e]=/HTMLUnknownElement/.test(t.toString())},A(Rn.options.directives,sr),A(Rn.options.components,gr),Rn.prototype.__patch__=q?Ki:R,Rn.prototype.$mount=function(e,t){return function(e,t,n){var a;return e.$el=t,e.$options.render||(e.$options.render=he),on(e,"beforeMount"),a=function(){e._update(e._render(),n)},new gn(e,a,R,{before:function(){e._isMounted&&!e._isDestroyed&&on(e,"beforeUpdate")}},!0),n=!1,null==e.$vnode&&(e._isMounted=!0,on(e,"mounted")),e}(this,e=e&&q?ia(e):void 0,t)},q&&setTimeout((function(){H.devtools&&ie&&ie.emit("init",Rn)}),0);var Tr,wr=/\{\{((?:.|\r?\n)+?)\}\}/g,kr=/[-.*+?^${}()|[\]\/\\]/g,Ir=g((function(e){var t=e[0].replace(kr,"\\$&"),n=e[1].replace(kr,"\\$&");return new RegExp(t+"((?:.|\\n)+?)"+n,"g")})),Cr={staticKeys:["staticClass"],transformNode:function(e,t){t.warn;var n=Ua(e,"class");n&&(e.staticClass=JSON.stringify(n));var a=Ba(e,"class",!1);a&&(e.classBinding=a)},genData:function(e){var t="";return e.staticClass&&(t+="staticClass:"+e.staticClass+","),e.classBinding&&(t+="class:"+e.classBinding+","),t}},_r={staticKeys:["staticStyle"],transformNode:function(e,t){t.warn;var n=Ua(e,"style");n&&(e.staticStyle=JSON.stringify(ci(n)));var a=Ba(e,"style",!1);a&&(e.styleBinding=a)},genData:function(e){var t="";return e.staticStyle&&(t+="staticStyle:"+e.staticStyle+","),e.styleBinding&&(t+="style:("+e.styleBinding+"),"),t}},xr=y("area,base,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),Ar=y("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),Er=y("address,article,aside,base,blockquote,body,caption,col,colgroup,dd,details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,title,tr,track"),Rr=/^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,Or=/^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+?\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,Mr="[a-zA-Z_][\\-\\.0-9_a-zA-Z"+j.source+"]*",Sr="((?:"+Mr+"\\:)?"+Mr+")",Pr=new RegExp("^<"+Sr),$r=/^\s*(\/?)>/,Lr=new RegExp("^<\\/"+Sr+"[^>]*>"),Fr=/^]+>/i,Vr=/^",""":'"',"&":"&"," ":"\n"," ":"\t","'":"'"},Br=/&(?:lt|gt|quot|amp|#39);/g,Ur=/&(?:lt|gt|quot|amp|#39|#10|#9);/g,zr=y("pre,textarea",!0),qr=function(e,t){return e&&zr(e)&&"\n"===t[0]};function Wr(e,t){var n=t?Ur:Br;return e.replace(n,(function(e){return Dr[e]}))}var Gr,Jr,Kr,Zr,Xr,Yr,Qr,es,ts=/^@|^v-on:/,ns=/^v-|^@|^:|^#/,as=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,is=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,rs=/^\(|\)$/g,ss=/^\[.*\]$/,os=/:(.*)$/,ls=/^:|^\.|^v-bind:/,us=/\.[^.\]]+(?=[^\]]*$)/g,ps=/^v-slot(:|$)|^#/,ds=/[\r\n]/,cs=/[ \f\t\r\n]+/g,ys=g((function(e){return(Tr=Tr||document.createElement("div")).innerHTML=e,Tr.textContent})),ms="_empty_";function fs(e,t,n){return{type:1,tag:e,attrsList:t,attrsMap:ws(t),rawAttrsMap:{},parent:n,children:[]}}function hs(e,t){var n;!function(e){var t=Ba(e,"key");t&&(e.key=t)}(e),e.plain=!e.key&&!e.scopedSlots&&!e.attrsList.length,function(e){var t=Ba(e,"ref");t&&(e.ref=t,e.refInFor=function(e){for(var t=e;t;){if(void 0!==t.for)return!0;t=t.parent}return!1}(e))}(e),function(e){var t;"template"===e.tag?(t=Ua(e,"scope"),e.slotScope=t||Ua(e,"slot-scope")):(t=Ua(e,"slot-scope"))&&(e.slotScope=t);var n=Ba(e,"slot");if(n&&(e.slotTarget='""'===n?'"default"':n,e.slotTargetDynamic=!(!e.attrsMap[":slot"]&&!e.attrsMap["v-bind:slot"]),"template"===e.tag||e.slotScope||Va(e,"slot",n,function(e,t){return e.rawAttrsMap[":"+t]||e.rawAttrsMap["v-bind:"+t]||e.rawAttrsMap[t]}(e,"slot"))),"template"===e.tag){var a=za(e,ps);if(a){var i=gs(a),r=i.name,s=i.dynamic;e.slotTarget=r,e.slotTargetDynamic=s,e.slotScope=a.value||ms}}else{var o=za(e,ps);if(o){var l=e.scopedSlots||(e.scopedSlots={}),u=gs(o),p=u.name,d=u.dynamic,c=l[p]=fs("template",[],e);c.slotTarget=p,c.slotTargetDynamic=d,c.children=e.children.filter((function(e){if(!e.slotScope)return e.parent=c,!0})),c.slotScope=o.value||ms,e.children=[],e.plain=!1}}}(e),"slot"===(n=e).tag&&(n.slotName=Ba(n,"name")),function(e){var t;(t=Ba(e,"is"))&&(e.component=t),null!=Ua(e,"inline-template")&&(e.inlineTemplate=!0)}(e);for(var a=0;a-1"+("true"===r?":("+t+")":":_q("+t+","+r+")")),Da(e,"change","var $$a="+t+",$$el=$event.target,$$c=$$el.checked?("+r+"):("+s+");if(Array.isArray($$a)){var $$v="+(a?"_n("+i+")":i)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+Ga(t,"$$a.concat([$$v])")+")}else{$$i>-1&&("+Ga(t,"$$a.slice(0,$$i).concat($$a.slice($$i+1))")+")}}else{"+Ga(t,"$$c")+"}",null,!0)}(e,a,i);else if("input"===r&&"radio"===s)!function(e,t,n){var a=n&&n.number,i=Ba(e,"value")||"null";Fa(e,"checked","_q("+t+","+(i=a?"_n("+i+")":i)+")"),Da(e,"change",Ga(t,i),null,!0)}(e,a,i);else if("input"===r||"textarea"===r)!function(e,t,n){var a=e.attrsMap.type,i=n||{},r=i.lazy,s=i.number,o=i.trim,l=!r&&"range"!==a,u=r?"change":"range"===a?ei:"input",p="$event.target.value";o&&(p="$event.target.value.trim()"),s&&(p="_n("+p+")");var d=Ga(t,p);l&&(d="if($event.target.composing)return;"+d),Fa(e,"value","("+t+")"),Da(e,u,d,null,!0),(o||s)&&Da(e,"blur","$forceUpdate()")}(e,a,i);else if(!H.isReservedTag(r))return Wa(e,a,i),!1;return!0},text:function(e,t){t.value&&Fa(e,"textContent","_s("+t.value+")",t)},html:function(e,t){t.value&&Fa(e,"innerHTML","_s("+t.value+")",t)}},Os={expectHTML:!0,modules:Es,directives:Rs,isPreTag:function(e){return"pre"===e},isUnaryTag:xr,mustUseProp:jn,canBeLeftOpenTag:Ar,isReservedTag:ea,getTagNamespace:ta,staticKeys:(As=Es,As.reduce((function(e,t){return e.concat(t.staticKeys||[])}),[]).join(","))},Ms=g((function(e){return y("type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap"+(e?","+e:""))}));function Ss(e,t){e&&(_s=Ms(t.staticKeys||""),xs=t.isReservedTag||O,Ps(e),$s(e,!1))}function Ps(e){if(e.static=function(e){return 2!==e.type&&(3===e.type||!(!e.pre&&(e.hasBindings||e.if||e.for||m(e.tag)||!xs(e.tag)||function(e){for(;e.parent;){if("template"!==(e=e.parent).tag)return!1;if(e.for)return!0}return!1}(e)||!Object.keys(e).every(_s))))}(e),1===e.type){if(!xs(e.tag)&&"slot"!==e.tag&&null==e.attrsMap["inline-template"])return;for(var t=0,n=e.children.length;t|^function(?:\s+[\w$]+)?\s*\(/,Fs=/\([^)]*?\);*$/,Vs=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,Hs={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},js={esc:["Esc","Escape"],tab:"Tab",enter:"Enter",space:[" ","Spacebar"],up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete","Del"]},Ns=function(e){return"if("+e+")return null;"},Ds={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:Ns("$event.target !== $event.currentTarget"),ctrl:Ns("!$event.ctrlKey"),shift:Ns("!$event.shiftKey"),alt:Ns("!$event.altKey"),meta:Ns("!$event.metaKey"),left:Ns("'button' in $event && $event.button !== 0"),middle:Ns("'button' in $event && $event.button !== 1"),right:Ns("'button' in $event && $event.button !== 2")};function Bs(e,t){var n=t?"nativeOn:":"on:",a="",i="";for(var r in e){var s=Us(e[r]);e[r]&&e[r].dynamic?i+=r+","+s+",":a+='"'+r+'":'+s+","}return a="{"+a.slice(0,-1)+"}",i?n+"_d("+a+",["+i.slice(0,-1)+"])":n+a}function Us(e){if(!e)return"function(){}";if(Array.isArray(e))return"["+e.map((function(e){return Us(e)})).join(",")+"]";var t=Vs.test(e.value),n=Ls.test(e.value),a=Vs.test(e.value.replace(Fs,""));if(e.modifiers){var i="",r="",s=[];for(var o in e.modifiers)if(Ds[o])r+=Ds[o],Hs[o]&&s.push(o);else if("exact"===o){var l=e.modifiers;r+=Ns(["ctrl","shift","alt","meta"].filter((function(e){return!l[e]})).map((function(e){return"$event."+e+"Key"})).join("||"))}else s.push(o);return s.length&&(i+=function(e){return"if(!$event.type.indexOf('key')&&"+e.map(zs).join("&&")+")return null;"}(s)),r&&(i+=r),"function($event){"+i+(t?"return "+e.value+".apply(null, arguments)":n?"return ("+e.value+").apply(null, arguments)":a?"return "+e.value:e.value)+"}"}return t||n?e.value:"function($event){"+(a?"return "+e.value:e.value)+"}"}function zs(e){var t=parseInt(e,10);if(t)return"$event.keyCode!=="+t;var n=Hs[e],a=js[e];return"_k($event.keyCode,"+JSON.stringify(e)+","+JSON.stringify(n)+",$event.key,"+JSON.stringify(a)+")"}var qs={on:function(e,t){e.wrapListeners=function(e){return"_g("+e+","+t.value+")"}},bind:function(e,t){e.wrapData=function(n){return"_b("+n+",'"+e.tag+"',"+t.value+","+(t.modifiers&&t.modifiers.prop?"true":"false")+(t.modifiers&&t.modifiers.sync?",true":"")+")"}},cloak:R},Ws=function(e){this.options=e,this.warn=e.warn||$a,this.transforms=La(e.modules,"transformCode"),this.dataGenFns=La(e.modules,"genData"),this.directives=A(A({},qs),e.directives);var t=e.isReservedTag||O;this.maybeComponent=function(e){return!!e.component||!t(e.tag)},this.onceId=0,this.staticRenderFns=[],this.pre=!1};function Gs(e,t){var n=new Ws(t);return{render:"with(this){return "+(e?"script"===e.tag?"null":Js(e,n):'_c("div")')+"}",staticRenderFns:n.staticRenderFns}}function Js(e,t){if(e.parent&&(e.pre=e.pre||e.parent.pre),e.staticRoot&&!e.staticProcessed)return Ks(e,t);if(e.once&&!e.onceProcessed)return Zs(e,t);if(e.for&&!e.forProcessed)return Qs(e,t);if(e.if&&!e.ifProcessed)return Xs(e,t);if("template"!==e.tag||e.slotTarget||t.pre){if("slot"===e.tag)return function(e,t){var n=e.slotName||'"default"',a=ao(e,t),i="_t("+n+(a?",function(){return "+a+"}":""),r=e.attrs||e.dynamicAttrs?so((e.attrs||[]).concat(e.dynamicAttrs||[]).map((function(e){return{name:w(e.name),value:e.value,dynamic:e.dynamic}}))):null,s=e.attrsMap["v-bind"];return!r&&!s||a||(i+=",null"),r&&(i+=","+r),s&&(i+=(r?"":",null")+","+s),i+")"}(e,t);var n;if(e.component)n=function(e,t,n){var a=t.inlineTemplate?null:ao(t,n,!0);return"_c("+e+","+eo(t,n)+(a?","+a:"")+")"}(e.component,e,t);else{var a;(!e.plain||e.pre&&t.maybeComponent(e))&&(a=eo(e,t));var i=e.inlineTemplate?null:ao(e,t,!0);n="_c('"+e.tag+"'"+(a?","+a:"")+(i?","+i:"")+")"}for(var r=0;r>>0}(s):"")+")"}(e,e.scopedSlots,t)+","),e.model&&(n+="model:{value:"+e.model.value+",callback:"+e.model.callback+",expression:"+e.model.expression+"},"),e.inlineTemplate){var r=function(e,t){var n=e.children[0];if(n&&1===n.type){var a=Gs(n,t.options);return"inlineTemplate:{render:function(){"+a.render+"},staticRenderFns:["+a.staticRenderFns.map((function(e){return"function(){"+e+"}"})).join(",")+"]}"}}(e,t);r&&(n+=r+",")}return n=n.replace(/,$/,"")+"}",e.dynamicAttrs&&(n="_b("+n+',"'+e.tag+'",'+so(e.dynamicAttrs)+")"),e.wrapData&&(n=e.wrapData(n)),e.wrapListeners&&(n=e.wrapListeners(n)),n}function to(e){return 1===e.type&&("slot"===e.tag||e.children.some(to))}function no(e,t){var n=e.attrsMap["slot-scope"];if(e.if&&!e.ifProcessed&&!n)return Xs(e,t,no,"null");if(e.for&&!e.forProcessed)return Qs(e,t,no);var a=e.slotScope===ms?"":String(e.slotScope),i="function("+a+"){return "+("template"===e.tag?e.if&&n?"("+e.if+")?"+(ao(e,t)||"undefined")+":undefined":ao(e,t)||"undefined":Js(e,t))+"}",r=a?"":",proxy:true";return"{key:"+(e.slotTarget||'"default"')+",fn:"+i+r+"}"}function ao(e,t,n,a,i){var r=e.children;if(r.length){var s=r[0];if(1===r.length&&s.for&&"template"!==s.tag&&"slot"!==s.tag){var o=n?t.maybeComponent(s)?",1":",0":"";return""+(a||Js)(s,t)+o}var l=n?function(e,t){for(var n=0,a=0;a]*>)","i")),c=e.replace(d,(function(e,n,a){return u=a.length,jr(p)||"noscript"===p||(n=n.replace(//g,"$1").replace(//g,"$1")),qr(p,n)&&(n=n.slice(1)),t.chars&&t.chars(n),""}));l+=e.length-c.length,e=c,x(p,l-u,l)}else{var y=e.indexOf("<");if(0===y){if(Vr.test(e)){var m=e.indexOf("--\x3e");if(m>=0){t.shouldKeepComment&&t.comment(e.substring(4,m),l,l+m+3),I(m+3);continue}}if(Hr.test(e)){var f=e.indexOf("]>");if(f>=0){I(f+2);continue}}var h=e.match(Fr);if(h){I(h[0].length);continue}var v=e.match(Lr);if(v){var b=l;I(v[0].length),x(v[1],b,l);continue}var g=C();if(g){_(g),qr(g.tagName,e)&&I(1);continue}}var T=void 0,w=void 0,k=void 0;if(y>=0){for(w=e.slice(y);!(Lr.test(w)||Pr.test(w)||Vr.test(w)||Hr.test(w)||(k=w.indexOf("<",1))<0);)y+=k,w=e.slice(y);T=e.substring(0,y)}y<0&&(T=e),T&&I(T.length),t.chars&&T&&t.chars(T,l-T.length,l)}if(e===n){t.chars&&t.chars(e);break}}function I(t){l+=t,e=e.substring(t)}function C(){var t=e.match(Pr);if(t){var n,a,i={tagName:t[1],attrs:[],start:l};for(I(t[0].length);!(n=e.match($r))&&(a=e.match(Or)||e.match(Rr));)a.start=l,I(a[0].length),a.end=l,i.attrs.push(a);if(n)return i.unarySlash=n[1],I(n[0].length),i.end=l,i}}function _(e){var n=e.tagName,l=e.unarySlash;r&&("p"===a&&Er(n)&&x(a),o(n)&&a===n&&x(n));for(var u=s(n)||!!l,p=e.attrs.length,d=new Array(p),c=0;c=0&&i[s].lowerCasedTag!==o;s--);else s=0;if(s>=0){for(var u=i.length-1;u>=s;u--)t.end&&t.end(i[u].tag,n,r);i.length=s,a=s&&i[s-1].tag}else"br"===o?t.start&&t.start(e,[],!0,n,r):"p"===o&&(t.start&&t.start(e,[],!1,n,r),t.end&&t.end(e,n,r))}x()}(e,{warn:Gr,expectHTML:t.expectHTML,isUnaryTag:t.isUnaryTag,canBeLeftOpenTag:t.canBeLeftOpenTag,shouldDecodeNewlines:t.shouldDecodeNewlines,shouldDecodeNewlinesForHref:t.shouldDecodeNewlinesForHref,shouldKeepComment:t.comments,outputSourceRange:t.outputSourceRange,start:function(e,r,s,p,d){var c=a&&a.ns||es(e);K&&"svg"===c&&(r=function(e){for(var t=[],n=0;nl&&(o.push(r=e.slice(l,i)),s.push(JSON.stringify(r)));var u=Sa(a[1].trim());s.push("_s("+u+")"),o.push({"@binding":u}),l=i+a[0].length}return l':'
',co.innerHTML.indexOf(" ")>0}var vo=!!q&&ho(!1),bo=!!q&&ho(!0),go=g((function(e){var t=ia(e);return t&&t.innerHTML})),To=Rn.prototype.$mount;Rn.prototype.$mount=function(e,t){if((e=e&&ia(e))===document.body||e===document.documentElement)return this;var n=this.$options;if(!n.render){var a=n.template;if(a)if("string"==typeof a)"#"===a.charAt(0)&&(a=go(a));else{if(!a.nodeType)return this;a=a.innerHTML}else e&&(a=function(e){if(e.outerHTML)return e.outerHTML;var t=document.createElement("div");return t.appendChild(e.cloneNode(!0)),t.innerHTML}(e));if(a){var i=fo(a,{outputSourceRange:!1,shouldDecodeNewlines:vo,shouldDecodeNewlinesForHref:bo,delimiters:n.delimiters,comments:n.comments},this),r=i.render,s=i.staticRenderFns;n.render=r,n.staticRenderFns=s}}return To.call(this,e,t)},Rn.compile=fo;const wo=Rn;function ko(e,t){for(var n in t)e[n]=t[n];return e}var Io=/[!'()*]/g,Co=function(e){return"%"+e.charCodeAt(0).toString(16)},_o=/%2C/g,xo=function(e){return encodeURIComponent(e).replace(Io,Co).replace(_o,",")};function Ao(e){try{return decodeURIComponent(e)}catch(e){}return e}var Eo=function(e){return null==e||"object"==typeof e?e:String(e)};function Ro(e){var t={};return(e=e.trim().replace(/^(\?|#|&)/,""))?(e.split("&").forEach((function(e){var n=e.replace(/\+/g," ").split("="),a=Ao(n.shift()),i=n.length>0?Ao(n.join("=")):null;void 0===t[a]?t[a]=i:Array.isArray(t[a])?t[a].push(i):t[a]=[t[a],i]})),t):t}function Oo(e){var t=e?Object.keys(e).map((function(t){var n=e[t];if(void 0===n)return"";if(null===n)return xo(t);if(Array.isArray(n)){var a=[];return n.forEach((function(e){void 0!==e&&(null===e?a.push(xo(t)):a.push(xo(t)+"="+xo(e)))})),a.join("&")}return xo(t)+"="+xo(n)})).filter((function(e){return e.length>0})).join("&"):null;return t?"?"+t:""}var Mo=/\/?$/;function So(e,t,n,a){var i=a&&a.options.stringifyQuery,r=t.query||{};try{r=Po(r)}catch(e){}var s={name:t.name||e&&e.name,meta:e&&e.meta||{},path:t.path||"/",hash:t.hash||"",query:r,params:t.params||{},fullPath:Fo(t,i),matched:e?Lo(e):[]};return n&&(s.redirectedFrom=Fo(n,i)),Object.freeze(s)}function Po(e){if(Array.isArray(e))return e.map(Po);if(e&&"object"==typeof e){var t={};for(var n in e)t[n]=Po(e[n]);return t}return e}var $o=So(null,{path:"/"});function Lo(e){for(var t=[];e;)t.unshift(e),e=e.parent;return t}function Fo(e,t){var n=e.path,a=e.query;void 0===a&&(a={});var i=e.hash;return void 0===i&&(i=""),(n||"/")+(t||Oo)(a)+i}function Vo(e,t,n){return t===$o?e===t:!!t&&(e.path&&t.path?e.path.replace(Mo,"")===t.path.replace(Mo,"")&&(n||e.hash===t.hash&&Ho(e.query,t.query)):!(!e.name||!t.name)&&e.name===t.name&&(n||e.hash===t.hash&&Ho(e.query,t.query)&&Ho(e.params,t.params)))}function Ho(e,t){if(void 0===e&&(e={}),void 0===t&&(t={}),!e||!t)return e===t;var n=Object.keys(e).sort(),a=Object.keys(t).sort();return n.length===a.length&&n.every((function(n,i){var r=e[n];if(a[i]!==n)return!1;var s=t[n];return null==r||null==s?r===s:"object"==typeof r&&"object"==typeof s?Ho(r,s):String(r)===String(s)}))}function jo(e){for(var t=0;t=0&&(t=e.slice(a),e=e.slice(0,a));var i=e.indexOf("?");return i>=0&&(n=e.slice(i+1),e=e.slice(0,i)),{path:e,query:n,hash:t}}(i.path||""),u=t&&t.path||"/",p=l.path?Bo(l.path,u,n||i.append):u,d=function(e,t,n){void 0===t&&(t={});var a,i=n||Ro;try{a=i(e||"")}catch(e){a={}}for(var r in t){var s=t[r];a[r]=Array.isArray(s)?s.map(Eo):Eo(s)}return a}(l.query,i.query,a&&a.options.parseQuery),c=i.hash||l.hash;return c&&"#"!==c.charAt(0)&&(c="#"+c),{_normalized:!0,path:p,query:d,hash:c}}var ll,ul=function(){},pl={name:"RouterLink",props:{to:{type:[String,Object],required:!0},tag:{type:String,default:"a"},custom:Boolean,exact:Boolean,exactPath:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,ariaCurrentValue:{type:String,default:"page"},event:{type:[String,Array],default:"click"}},render:function(e){var t=this,n=this.$router,a=this.$route,i=n.resolve(this.to,a,this.append),r=i.location,s=i.route,o=i.href,l={},u=n.options.linkActiveClass,p=n.options.linkExactActiveClass,d=null==u?"router-link-active":u,c=null==p?"router-link-exact-active":p,y=null==this.activeClass?d:this.activeClass,m=null==this.exactActiveClass?c:this.exactActiveClass,f=s.redirectedFrom?So(null,ol(s.redirectedFrom),null,n):s;l[m]=Vo(a,f,this.exactPath),l[y]=this.exact||this.exactPath?l[m]:function(e,t){return 0===e.path.replace(Mo,"/").indexOf(t.path.replace(Mo,"/"))&&(!t.hash||e.hash===t.hash)&&function(e,t){for(var n in t)if(!(n in e))return!1;return!0}(e.query,t.query)}(a,f);var h=l[m]?this.ariaCurrentValue:null,v=function(e){dl(e)&&(t.replace?n.replace(r,ul):n.push(r,ul))},b={click:dl};Array.isArray(this.event)?this.event.forEach((function(e){b[e]=v})):b[this.event]=v;var g={class:l},T=!this.$scopedSlots.$hasNormal&&this.$scopedSlots.default&&this.$scopedSlots.default({href:o,route:s,navigate:v,isActive:l[y],isExactActive:l[m]});if(T){if(1===T.length)return T[0];if(T.length>1||!T.length)return 0===T.length?e():e("span",{},T)}if("a"===this.tag)g.on=b,g.attrs={href:o,"aria-current":h};else{var w=cl(this.$slots.default);if(w){w.isStatic=!1;var k=w.data=ko({},w.data);for(var I in k.on=k.on||{},k.on){var C=k.on[I];I in b&&(k.on[I]=Array.isArray(C)?C:[C])}for(var _ in b)_ in k.on?k.on[_].push(b[_]):k.on[_]=v;var x=w.data.attrs=ko({},w.data.attrs);x.href=o,x["aria-current"]=h}else g.on=b}return e(this.tag,g,this.$slots.default)}};function dl(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey||e.defaultPrevented||void 0!==e.button&&0!==e.button)){if(e.currentTarget&&e.currentTarget.getAttribute){var t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function cl(e){if(e)for(var t,n=0;n-1&&(l.params[c]=n.params[c]);return l.path=sl(p.path,l.params),o(p,l,s)}if(l.path){l.params={};for(var y=0;y=e.length?n():e[i]?t(e[i],(function(){a(i+1)})):a(i+1)};a(0)}var jl={redirected:2,aborted:4,cancelled:8,duplicated:16};function Nl(e,t){return Dl(e,t,jl.cancelled,'Navigation cancelled from "'+e.fullPath+'" to "'+t.fullPath+'" with a new navigation.')}function Dl(e,t,n,a){var i=new Error(a);return i._isRouter=!0,i.from=e,i.to=t,i.type=n,i}var Bl=["params","query","hash"];function Ul(e){return Object.prototype.toString.call(e).indexOf("Error")>-1}function zl(e,t){return Ul(e)&&e._isRouter&&(null==t||e.type===t)}function ql(e,t){return Wl(e.map((function(e){return Object.keys(e.components).map((function(n){return t(e.components[n],e.instances[n],e,n)}))})))}function Wl(e){return Array.prototype.concat.apply([],e)}var Gl="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag;function Jl(e){var t=!1;return function(){for(var n=[],a=arguments.length;a--;)n[a]=arguments[a];if(!t)return t=!0,e.apply(this,n)}}var Kl=function(e,t){this.router=e,this.base=function(e){if(!e)if(yl){var t=document.querySelector("base");e=(e=t&&t.getAttribute("href")||"/").replace(/^https?:\/\/[^\/]+/,"")}else e="/";return"/"!==e.charAt(0)&&(e="/"+e),e.replace(/\/$/,"")}(t),this.current=$o,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[],this.listeners=[]};function Zl(e,t,n,a){var i=ql(e,(function(e,a,i,r){var s=function(e,t){return"function"!=typeof e&&(e=ll.extend(e)),e.options[t]}(e,t);if(s)return Array.isArray(s)?s.map((function(e){return n(e,a,i,r)})):n(s,a,i,r)}));return Wl(a?i.reverse():i)}function Xl(e,t){if(t)return function(){return e.apply(t,arguments)}}Kl.prototype.listen=function(e){this.cb=e},Kl.prototype.onReady=function(e,t){this.ready?e():(this.readyCbs.push(e),t&&this.readyErrorCbs.push(t))},Kl.prototype.onError=function(e){this.errorCbs.push(e)},Kl.prototype.transitionTo=function(e,t,n){var a,i=this;try{a=this.router.match(e,this.current)}catch(e){throw this.errorCbs.forEach((function(t){t(e)})),e}var r=this.current;this.confirmTransition(a,(function(){i.updateRoute(a),t&&t(a),i.ensureURL(),i.router.afterHooks.forEach((function(e){e&&e(a,r)})),i.ready||(i.ready=!0,i.readyCbs.forEach((function(e){e(a)})))}),(function(e){n&&n(e),e&&!i.ready&&(zl(e,jl.redirected)&&r===$o||(i.ready=!0,i.readyErrorCbs.forEach((function(t){t(e)}))))}))},Kl.prototype.confirmTransition=function(e,t,n){var a=this,i=this.current;this.pending=e;var r,s,o=function(e){!zl(e)&&Ul(e)&&(a.errorCbs.length?a.errorCbs.forEach((function(t){t(e)})):console.error(e)),n&&n(e)},l=e.matched.length-1,u=i.matched.length-1;if(Vo(e,i)&&l===u&&e.matched[l]===i.matched[u])return this.ensureURL(),e.hash&&xl(this.router,i,e,!1),o(((s=Dl(r=i,e,jl.duplicated,'Avoided redundant navigation to current location: "'+r.fullPath+'".')).name="NavigationDuplicated",s));var p,d=function(e,t){var n,a=Math.max(e.length,t.length);for(n=0;n0)){var t=this.router,n=t.options.scrollBehavior,a=Ll&&n;a&&this.listeners.push(_l());var i=function(){var n=e.current,i=Ql(e.base);e.current===$o&&i===e._startLocation||e.transitionTo(i,(function(e){a&&xl(t,e,n,!0)}))};window.addEventListener("popstate",i),this.listeners.push((function(){window.removeEventListener("popstate",i)}))}},t.prototype.go=function(e){window.history.go(e)},t.prototype.push=function(e,t,n){var a=this,i=this.current;this.transitionTo(e,(function(e){Fl(Uo(a.base+e.fullPath)),xl(a.router,e,i,!1),t&&t(e)}),n)},t.prototype.replace=function(e,t,n){var a=this,i=this.current;this.transitionTo(e,(function(e){Vl(Uo(a.base+e.fullPath)),xl(a.router,e,i,!1),t&&t(e)}),n)},t.prototype.ensureURL=function(e){if(Ql(this.base)!==this.current.fullPath){var t=Uo(this.base+this.current.fullPath);e?Fl(t):Vl(t)}},t.prototype.getCurrentLocation=function(){return Ql(this.base)},t}(Kl);function Ql(e){var t=window.location.pathname,n=t.toLowerCase(),a=e.toLowerCase();return!e||n!==a&&0!==n.indexOf(Uo(a+"/"))||(t=t.slice(e.length)),(t||"/")+window.location.search+window.location.hash}var eu=function(e){function t(t,n,a){e.call(this,t,n),a&&function(e){var t=Ql(e);if(!/^\/#/.test(t))return window.location.replace(Uo(e+"/#"+t)),!0}(this.base)||tu()}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.setupListeners=function(){var e=this;if(!(this.listeners.length>0)){var t=this.router.options.scrollBehavior,n=Ll&&t;n&&this.listeners.push(_l());var a=function(){var t=e.current;tu()&&e.transitionTo(nu(),(function(a){n&&xl(e.router,a,t,!0),Ll||ru(a.fullPath)}))},i=Ll?"popstate":"hashchange";window.addEventListener(i,a),this.listeners.push((function(){window.removeEventListener(i,a)}))}},t.prototype.push=function(e,t,n){var a=this,i=this.current;this.transitionTo(e,(function(e){iu(e.fullPath),xl(a.router,e,i,!1),t&&t(e)}),n)},t.prototype.replace=function(e,t,n){var a=this,i=this.current;this.transitionTo(e,(function(e){ru(e.fullPath),xl(a.router,e,i,!1),t&&t(e)}),n)},t.prototype.go=function(e){window.history.go(e)},t.prototype.ensureURL=function(e){var t=this.current.fullPath;nu()!==t&&(e?iu(t):ru(t))},t.prototype.getCurrentLocation=function(){return nu()},t}(Kl);function tu(){var e=nu();return"/"===e.charAt(0)||(ru("/"+e),!1)}function nu(){var e=window.location.href,t=e.indexOf("#");return t<0?"":e=e.slice(t+1)}function au(e){var t=window.location.href,n=t.indexOf("#");return(n>=0?t.slice(0,n):t)+"#"+e}function iu(e){Ll?Fl(au(e)):window.location.hash=e}function ru(e){Ll?Vl(au(e)):window.location.replace(au(e))}var su=function(e){function t(t,n){e.call(this,t,n),this.stack=[],this.index=-1}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.push=function(e,t,n){var a=this;this.transitionTo(e,(function(e){a.stack=a.stack.slice(0,a.index+1).concat(e),a.index++,t&&t(e)}),n)},t.prototype.replace=function(e,t,n){var a=this;this.transitionTo(e,(function(e){a.stack=a.stack.slice(0,a.index).concat(e),t&&t(e)}),n)},t.prototype.go=function(e){var t=this,n=this.index+e;if(!(n<0||n>=this.stack.length)){var a=this.stack[n];this.confirmTransition(a,(function(){var e=t.current;t.index=n,t.updateRoute(a),t.router.afterHooks.forEach((function(t){t&&t(a,e)}))}),(function(e){zl(e,jl.duplicated)&&(t.index=n)}))}},t.prototype.getCurrentLocation=function(){var e=this.stack[this.stack.length-1];return e?e.fullPath:"/"},t.prototype.ensureURL=function(){},t}(Kl),ou=function(e){void 0===e&&(e={}),this.app=null,this.apps=[],this.options=e,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=vl(e.routes||[],this);var t=e.mode||"hash";switch(this.fallback="history"===t&&!Ll&&!1!==e.fallback,this.fallback&&(t="hash"),yl||(t="abstract"),this.mode=t,t){case"history":this.history=new Yl(this,e.base);break;case"hash":this.history=new eu(this,e.base,this.fallback);break;case"abstract":this.history=new su(this,e.base)}},lu={currentRoute:{configurable:!0}};function uu(e,t){return e.push(t),function(){var n=e.indexOf(t);n>-1&&e.splice(n,1)}}ou.prototype.match=function(e,t,n){return this.matcher.match(e,t,n)},lu.currentRoute.get=function(){return this.history&&this.history.current},ou.prototype.init=function(e){var t=this;if(this.apps.push(e),e.$once("hook:destroyed",(function(){var n=t.apps.indexOf(e);n>-1&&t.apps.splice(n,1),t.app===e&&(t.app=t.apps[0]||null),t.app||t.history.teardown()})),!this.app){this.app=e;var n=this.history;if(n instanceof Yl||n instanceof eu){var a=function(e){n.setupListeners(),function(e){var a=n.current,i=t.options.scrollBehavior;Ll&&i&&"fullPath"in e&&xl(t,e,a,!1)}(e)};n.transitionTo(n.getCurrentLocation(),a,a)}n.listen((function(e){t.apps.forEach((function(t){t._route=e}))}))}},ou.prototype.beforeEach=function(e){return uu(this.beforeHooks,e)},ou.prototype.beforeResolve=function(e){return uu(this.resolveHooks,e)},ou.prototype.afterEach=function(e){return uu(this.afterHooks,e)},ou.prototype.onReady=function(e,t){this.history.onReady(e,t)},ou.prototype.onError=function(e){this.history.onError(e)},ou.prototype.push=function(e,t,n){var a=this;if(!t&&!n&&"undefined"!=typeof Promise)return new Promise((function(t,n){a.history.push(e,t,n)}));this.history.push(e,t,n)},ou.prototype.replace=function(e,t,n){var a=this;if(!t&&!n&&"undefined"!=typeof Promise)return new Promise((function(t,n){a.history.replace(e,t,n)}));this.history.replace(e,t,n)},ou.prototype.go=function(e){this.history.go(e)},ou.prototype.back=function(){this.go(-1)},ou.prototype.forward=function(){this.go(1)},ou.prototype.getMatchedComponents=function(e){var t=e?e.matched?e:this.resolve(e).route:this.currentRoute;return t?[].concat.apply([],t.matched.map((function(e){return Object.keys(e.components).map((function(t){return e.components[t]}))}))):[]},ou.prototype.resolve=function(e,t,n){var a=ol(e,t=t||this.history.current,n,this),i=this.match(a,t),r=i.redirectedFrom||i.fullPath,s=function(e,t,n){var a="hash"===n?"#"+t:t;return e?Uo(e+"/"+a):a}(this.history.base,r,this.mode);return{location:a,route:i,href:s,normalizedTo:a,resolved:i}},ou.prototype.getRoutes=function(){return this.matcher.getRoutes()},ou.prototype.addRoute=function(e,t){this.matcher.addRoute(e,t),this.history.current!==$o&&this.history.transitionTo(this.history.getCurrentLocation())},ou.prototype.addRoutes=function(e){this.matcher.addRoutes(e),this.history.current!==$o&&this.history.transitionTo(this.history.getCurrentLocation())},Object.defineProperties(ou.prototype,lu),ou.install=function e(t){if(!e.installed||ll!==t){e.installed=!0,ll=t;var n=function(e){return void 0!==e},a=function(e,t){var a=e.$options._parentVnode;n(a)&&n(a=a.data)&&n(a=a.registerRouteInstance)&&a(e,t)};t.mixin({beforeCreate:function(){n(this.$options.router)?(this._routerRoot=this,this._router=this.$options.router,this._router.init(this),t.util.defineReactive(this,"_route",this._router.history.current)):this._routerRoot=this.$parent&&this.$parent._routerRoot||this,a(this,this)},destroyed:function(){a(this)}}),Object.defineProperty(t.prototype,"$router",{get:function(){return this._routerRoot._router}}),Object.defineProperty(t.prototype,"$route",{get:function(){return this._routerRoot._route}}),t.component("RouterView",No),t.component("RouterLink",pl);var i=t.config.optionMergeStrategies;i.beforeRouteEnter=i.beforeRouteLeave=i.beforeRouteUpdate=i.created}},ou.version="3.5.4",ou.isNavigationFailure=zl,ou.NavigationFailureType=jl,ou.START_LOCATION=$o,yl&&window.Vue&&window.Vue.use(ou);const pu=ou;var du=function(){var e=this.$createElement,t=this._self._c||e;return t("div",{staticClass:"min-h-screen bg-gray-100 px-4 pt-6"},[t("router-view")],1)};function cu(e,t,n,a,i,r,s,o){var l,u="function"==typeof e?e.options:e;if(t&&(u.render=t,u.staticRenderFns=n,u._compiled=!0),a&&(u.functional=!0),r&&(u._scopeId="data-v-"+r),s?(l=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),i&&i.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(s)},u._ssrRegister=l):i&&(l=o?function(){i.call(this,(u.functional?this.parent:this).$root.$options.shadowRoot)}:i),l)if(u.functional){u._injectStyles=l;var p=u.render;u.render=function(e,t){return l.call(t),p(e,t)}}else{var d=u.beforeCreate;u.beforeCreate=d?[].concat(d,l):[l]}return{exports:e,options:u}}du._withStripped=!0,n(387);var yu=cu({},du,[],!1,null,null,null);yu.options.__file="node_modules/hardhat-docgen/src/App.vue";const mu=yu.exports;var fu=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"w-full space-y-10 md:max-w-screen-sm lg:max-w-screen-md mx-auto"},[n("HeaderBar"),e._v(" "),n("div",{staticClass:"pb-32"},[n("div",{staticClass:"space-y-4"},[n("span",{staticClass:"text-lg"},[e._v("\n "+e._s(e.json.source)+"\n ")]),e._v(" "),n("h1",{staticClass:"text-xl"},[e._v("\n "+e._s(e.json.name)+"\n ")]),e._v(" "),n("h2",{staticClass:"text-lg"},[e._v("\n "+e._s(e.json.title)+"\n ")]),e._v(" "),n("h2",{staticClass:"text-lg"},[e._v("\n "+e._s(e.json.author)+"\n ")]),e._v(" "),n("p",[e._v(e._s(e.json.notice))]),e._v(" "),n("p",[e._v(e._s(e.json.details))])]),e._v(" "),n("div",{staticClass:"mt-8"},[e.json.hasOwnProperty("constructor")?n("Member",{attrs:{json:e.json.constructor}}):e._e()],1),e._v(" "),n("div",{staticClass:"mt-8"},[e.json.receive?n("Member",{attrs:{json:e.json.receive}}):e._e()],1),e._v(" "),n("div",{staticClass:"mt-8"},[e.json.fallback?n("Member",{attrs:{json:e.json.fallback}}):e._e()],1),e._v(" "),e.json.events?n("MemberSet",{attrs:{title:"Events",json:e.json.events}}):e._e(),e._v(" "),e.json.stateVariables?n("MemberSet",{attrs:{title:"State Variables",json:e.json.stateVariables}}):e._e(),e._v(" "),e.json.methods?n("MemberSet",{attrs:{title:"Methods",json:e.json.methods}}):e._e()],1),e._v(" "),n("FooterBar")],1)};fu._withStripped=!0;var hu=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"bg-gray-100 fixed bottom-0 right-0 w-full border-t border-dashed border-gray-300"},[n("div",{staticClass:"w-full text-center py-2 md:max-w-screen-sm lg:max-w-screen-md mx-auto"},[n("button",{staticClass:"py-1 px-2 text-gray-500",on:{click:function(t){return e.openLink(e.repository)}}},[e._v("\n built with "+e._s(e.name)+"\n ")])])])};hu._withStripped=!0;const vu=JSON.parse('{"u2":"hardhat-docgen","cj":"https://github.com/ItsNickBarry/hardhat-docgen"}');var bu=cu({data:function(){return{repository:vu.cj,name:vu.u2}},methods:{openLink(e){window.open(e,"_blank")}}},hu,[],!1,null,null,null);bu.options.__file="node_modules/hardhat-docgen/src/components/FooterBar.vue";const gu=bu.exports;var Tu=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"w-full border-b border-dashed py-2 border-gray-300"},[n("router-link",{staticClass:"py-2 text-gray-500",attrs:{to:"/"}},[e._v("\n <- Go back\n ")])],1)};Tu._withStripped=!0;var wu=cu({},Tu,[],!1,null,null,null);wu.options.__file="node_modules/hardhat-docgen/src/components/HeaderBar.vue";const ku=wu.exports;var Iu=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"border-2 border-gray-400 border-dashed w-full p-2"},[n("h3",{staticClass:"text-lg pb-2 mb-2 border-b-2 border-gray-400 border-dashed"},[e._v("\n "+e._s(e.name)+" "+e._s(e.keywords)+" "+e._s(e.inputSignature)+"\n ")]),e._v(" "),n("div",{staticClass:"space-y-3"},[n("p",[e._v(e._s(e.json.notice))]),e._v(" "),n("p",[e._v(e._s(e.json.details))]),e._v(" "),n("MemberSection",{attrs:{name:"Parameters",items:e.inputs}}),e._v(" "),n("MemberSection",{attrs:{name:"Return Values",items:e.outputs}})],1)])};Iu._withStripped=!0;var Cu=function(){var e=this,t=e.$createElement,n=e._self._c||t;return e.items.length>0?n("ul",[n("h4",{staticClass:"text-lg"},[e._v("\n "+e._s(e.name)+"\n ")]),e._v(" "),e._l(e.items,(function(t,a){return n("li",{key:a},[n("span",{staticClass:"bg-gray-300"},[e._v(e._s(t.type))]),e._v(" "),n("b",[e._v(e._s(t.name||"_"+a))]),t.desc?n("span",[e._v(": "),n("i",[e._v(e._s(t.desc))])]):e._e()])}))],2):e._e()};Cu._withStripped=!0;var _u=cu({props:{name:{type:String,default:""},items:{type:Array,default:()=>new Array}}},Cu,[],!1,null,null,null);_u.options.__file="node_modules/hardhat-docgen/src/components/MemberSection.vue";const xu={components:{MemberSection:_u.exports},props:{json:{type:Object,default:()=>new Object}},computed:{name:function(){return this.json.name||this.json.type},keywords:function(){let e=[];return this.json.stateMutability&&e.push(this.json.stateMutability),"true"===this.json.anonymous&&e.push("anonymous"),e.join(" ")},params:function(){return this.json.params||{}},returns:function(){return this.json.returns||{}},inputs:function(){return(this.json.inputs||[]).map((e=>({...e,desc:this.params[e.name]})))},inputSignature:function(){return`(${this.inputs.map((e=>e.type)).join(",")})`},outputs:function(){return(this.json.outputs||[]).map(((e,t)=>({...e,desc:this.returns[e.name||`_${t}`]})))},outputSignature:function(){return`(${this.outputs.map((e=>e.type)).join(",")})`}}};var Au=cu(xu,Iu,[],!1,null,null,null);Au.options.__file="node_modules/hardhat-docgen/src/components/Member.vue";const Eu=Au.exports;var Ru=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"w-full mt-8"},[n("h2",{staticClass:"text-lg"},[e._v(e._s(e.title))]),e._v(" "),e._l(Object.keys(e.json),(function(t){return n("Member",{key:t,staticClass:"mt-3",attrs:{json:e.json[t]}})}))],2)};Ru._withStripped=!0;var Ou=cu({components:{Member:Eu},props:{title:{type:String,default:""},json:{type:Object,default:()=>new Object}}},Ru,[],!1,null,null,null);Ou.options.__file="node_modules/hardhat-docgen/src/components/MemberSet.vue";var Mu=cu({components:{Member:Eu,MemberSet:Ou.exports,HeaderBar:ku,FooterBar:gu},props:{json:{type:Object,default:()=>new Object}}},fu,[],!1,null,null,null);Mu.options.__file="node_modules/hardhat-docgen/src/components/Contract.vue";const Su=Mu.exports;var Pu=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"w-full space-y-10 md:max-w-screen-sm lg:max-w-screen-md mx-auto pb-32"},[n("Branch",{attrs:{json:e.trees,name:"Sources:"}}),e._v(" "),n("FooterBar",{staticClass:"mt-20"})],1)};Pu._withStripped=!0;var $u=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",[e._v("\n "+e._s(e.name)+"\n "),Array.isArray(e.json)?n("div",{staticClass:"pl-5"},e._l(e.json,(function(t,a){return n("div",{key:a},[n("router-link",{attrs:{to:t.source+":"+t.name}},[e._v("\n "+e._s(t.name)+"\n ")])],1)})),0):n("div",{staticClass:"pl-5"},e._l(Object.keys(e.json),(function(t){return n("div",{key:t},[n("Branch",{attrs:{json:e.json[t],name:t}})],1)})),0)])};$u._withStripped=!0;var Lu=cu({name:"Branch",props:{name:{type:String,default:null},json:{type:[Object,Array],default:()=>new Object}}},$u,[],!1,null,null,null);Lu.options.__file="node_modules/hardhat-docgen/src/components/Branch.vue";var Fu=cu({components:{Branch:Lu.exports,FooterBar:gu},props:{json:{type:Object,default:()=>new Object}},computed:{trees:function(){let e={};for(let t in this.json)t.replace("/","//").split(/\/(?=[^\/])/).reduce(function(e,n){if(!n.includes(":"))return e[n]=e[n]||{},e[n];{let[a]=n.split(":");e[a]=e[a]||[],e[a].push(this.json[t])}}.bind(this),e);return e}}},Pu,[],!1,null,null,null);Fu.options.__file="node_modules/hardhat-docgen/src/components/Index.vue";const Vu=Fu.exports;wo.use(pu);const Hu={"src/HookBeaconProxy.sol:HookBeaconProxy":{source:"src/HookBeaconProxy.sol",name:"HookBeaconProxy",title:"HookBeaconProxy a proxy contract that points to an implementation provided by a Beacon",details:"This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}. The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't conflict with the storage layout of the implementation behind the proxy. This is an extension of the OpenZeppelin beacon proxy, however differs in that it is initializeable, which means it is usable with Create2.",constructor:{inputs:[],stateMutability:"nonpayable",type:"constructor"},fallback:{stateMutability:"payable",type:"fallback"},receive:{stateMutability:"payable",type:"receive"},events:{"AdminChanged(address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"previousAdmin",type:"address"},{indexed:!1,internalType:"address",name:"newAdmin",type:"address"}],name:"AdminChanged",type:"event"},"BeaconUpgraded(address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"beacon",type:"address"}],name:"BeaconUpgraded",type:"event"},"Initialized(uint8)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint8",name:"version",type:"uint8"}],name:"Initialized",type:"event",details:"Triggered when the contract has been initialized or reinitialized."},"Upgraded(address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"implementation",type:"address"}],name:"Upgraded",type:"event"}},methods:{"initializeBeacon(address,bytes)":{inputs:[{internalType:"address",name:"beacon",type:"address"},{internalType:"bytes",name:"data",type:"bytes"}],name:"initializeBeacon",outputs:[],stateMutability:"nonpayable",type:"function",details:"Initializes the proxy with `beacon`. If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. Requirements: - `beacon` must be a contract with the interface {IBeacon}."}}},"src/HookBidPool.sol:HookBidPool":{source:"src/HookBidPool.sol",name:"HookBidPool",title:"HookBidPool",author:"Jake Nyquist-j@hook.xyz",details:"This contract is directly interacted with by users, and holds approvals for ERC-20 tokens. In order for an order to be filled, it must be signed by the maker and the maker must have enough balance to provide the order proceeds and relevant fees. The maximum bid the order maker has offered is computed using the volatiliy and risk-free rate signed into the order. This information is combined with the NFT floor price provided by the off-chain oracle to compute the maximum bid price. If the amount of consideration requested by the seller + the protocol fees is less than the maximum bid, the order can then be filled. The seller will receive their requested proceeds, the protocol will receive their fees, and the buyer receives their option nft. The order must also be signed by the off-chain order validity oracle. This oracle is responsible for allowing the user to make gasless cancellations which take effect as soon as the last outstanding order validity signature expires. Alternatively, the user can make a calculation directly on the contract with their order hash to immediately cancel their order.",notice:"HookBidPools allows users to make off-chain orders in terms of an implied volatility which can later be filled by an option seller. The price of the sell will be computed using the Black-Scholes model at bid time.",constructor:{inputs:[{internalType:"address",name:"_weth",type:"address"},{internalType:"address",name:"_initialAdmin",type:"address"},{internalType:"address",name:"_priceOracleSigner",type:"address"},{internalType:"address",name:"_orderValidityOracleSigner",type:"address"},{internalType:"uint64",name:"_feeBips",type:"uint64"},{internalType:"address",name:"_feeRecipient",type:"address"},{internalType:"address",name:"_protocol",type:"address"}],stateMutability:"nonpayable",type:"constructor"},events:{"FeesUpdated(uint64)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint64",name:"feeBips",type:"uint64"}],name:"FeesUpdated",type:"event",params:{feeBips:"the new fee take rate in bips"},notice:"event emitted when the fee take rate is updated"},"OrderCancelled(address,bytes32)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"maker",type:"address"},{indexed:!1,internalType:"bytes32",name:"orderHash",type:"bytes32"}],name:"OrderCancelled",type:"event",params:{maker:"the signer who made the order initially",orderHash:"the eip-712 hash of the order"},notice:"event emitted when an order is canceled"},"OrderFilled(address,address,bytes32,uint256,uint256,address,uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"maker",type:"address"},{indexed:!1,internalType:"address",name:"taker",type:"address"},{indexed:!1,internalType:"bytes32",name:"orderHash",type:"bytes32"},{indexed:!1,internalType:"uint256",name:"proceeds",type:"uint256"},{indexed:!1,internalType:"uint256",name:"fees",type:"uint256"},{indexed:!1,internalType:"address",name:"optionContract",type:"address"},{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"}],name:"OrderFilled",type:"event",params:{fees:"the fees the buyer paid, in addition to the proceeds to the sellers",maker:"the signer who made the order initially",optionContract:"the contract address of the Hook option instrument",optionId:"the id of the option within the optionContract",orderHash:"the eip-712 hash of the order",proceeds:"the proceeds the seller receives",taker:"the caller who filled the order"},notice:"event emitted when an option is sold"},"OrderValidityOracleSignerUpdated(address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"oracle",type:"address"}],name:"OrderValidityOracleSignerUpdated",type:"event",params:{oracle:"the new order validity oracle"},notice:"event emitted when the order validity oracle is updated"},"PauseUpdated(bool)":{anonymous:!1,inputs:[{indexed:!1,internalType:"bool",name:"newState",type:"bool"}],name:"PauseUpdated",type:"event",params:{newState:"the new paused state of the contract"},notice:"event emitted when the paused state of the contract changes\\"},"PriceOracleSignerUpdated(address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"oracle",type:"address"}],name:"PriceOracleSignerUpdated",type:"event",params:{oracle:"the new oracle address"},notice:"event emitted when the oracle address is updated"},"ProtocolAddressSet(address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"protocol",type:"address"}],name:"ProtocolAddressSet",type:"event",params:{protocol:"the new protocol address"},notice:"event emitted when the protocol address is updated"},"ProtocolFeeRecipientUpdated(address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"recipient",type:"address"}],name:"ProtocolFeeRecipientUpdated",type:"event",params:{recipient:"the new protocol fee recipient"},notice:"event emitted when the protocol fee recipient is updated"},"RoleAdminChanged(bytes32,bytes32,bytes32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"bytes32",name:"previousAdminRole",type:"bytes32"},{indexed:!0,internalType:"bytes32",name:"newAdminRole",type:"bytes32"}],name:"RoleAdminChanged",type:"event"},"RoleGranted(bytes32,address,address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"address",name:"account",type:"address"},{indexed:!0,internalType:"address",name:"sender",type:"address"}],name:"RoleGranted",type:"event"},"RoleRevoked(bytes32,address,address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"address",name:"account",type:"address"},{indexed:!0,internalType:"address",name:"sender",type:"address"}],name:"RoleRevoked",type:"event"}},methods:{"DEFAULT_ADMIN_ROLE()":{inputs:[],name:"DEFAULT_ADMIN_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function"},"EIP712_DOMAIN_SEPARATOR()":{inputs:[],name:"EIP712_DOMAIN_SEPARATOR",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function"},"FEES_ROLE()":{inputs:[],name:"FEES_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the role that can update the fee amount and recipient, should be held by a timelock"},"ORACLE_ROLE()":{inputs:[],name:"ORACLE_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the role that can update the price oracle signer, should be held by a timelock If an oracle is compromised, the pool should be paused immediately, a new oracle nominated via the timelock, and the pool unpaused after the timelock delay has passed."},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the role that can pause the contract - should be held by a mulitsig"},"PROTOCOL_ROLE()":{inputs:[],name:"PROTOCOL_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the role that can update the protocol address - should be held by a multisig"},"cancelOrder((uint8,address,uint256,uint256,uint8,uint8,uint256,uint64,uint64,uint64,(address,bytes)[],address,uint64,uint256,uint64))":{inputs:[{components:[{internalType:"enum PoolOrders.OrderDirection",name:"direction",type:"uint8"},{internalType:"address",name:"maker",type:"address"},{internalType:"uint256",name:"orderExpiry",type:"uint256"},{internalType:"uint256",name:"nonce",type:"uint256"},{internalType:"uint8",name:"size",type:"uint8"},{internalType:"enum PoolOrders.OptionType",name:"optionType",type:"uint8"},{internalType:"uint256",name:"maxStrikePriceMultiple",type:"uint256"},{internalType:"uint64",name:"minOptionDuration",type:"uint64"},{internalType:"uint64",name:"maxOptionDuration",type:"uint64"},{internalType:"uint64",name:"maxPriceSignalAge",type:"uint64"},{components:[{internalType:"contract IPropertyValidator",name:"propertyValidator",type:"address"},{internalType:"bytes",name:"propertyData",type:"bytes"}],internalType:"struct PoolOrders.Property[]",name:"nftProperties",type:"tuple[]"},{internalType:"address",name:"optionMarketAddress",type:"address"},{internalType:"uint64",name:"impliedVolBips",type:"uint64"},{internalType:"uint256",name:"skewDecimal",type:"uint256"},{internalType:"uint64",name:"riskFreeRateBips",type:"uint64"}],internalType:"struct PoolOrders.Order",name:"order",type:"tuple"}],name:"cancelOrder",outputs:[],stateMutability:"nonpayable",type:"function",details:"this function is available even when the pool is paused in case makers want to cancel orders as a result of the event that motivated the pause.",params:{order:"the order struct that should no longer be fillable."},notice:"Function to allow a maker to cancel all examples of an order that they've already signed. If an order has already been filled, but support more than one fill, calling this function cancels future fills of the order (but not current ones)."},"getRoleAdmin(bytes32)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"}],name:"getRoleAdmin",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",details:"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"grantRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"hasRole",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"renounceRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`."},"revokeRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"revokeRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."},"sellOption((uint8,address,uint256,uint256,uint8,uint8,uint256,uint64,uint64,uint64,(address,bytes)[],address,uint64,uint256,uint64),(uint8,uint8,bytes32,bytes32),(uint256,uint256,uint256,uint8,bytes32,bytes32),(bytes32,uint256,uint8,bytes32,bytes32),uint256,address,uint256)":{inputs:[{components:[{internalType:"enum PoolOrders.OrderDirection",name:"direction",type:"uint8"},{internalType:"address",name:"maker",type:"address"},{internalType:"uint256",name:"orderExpiry",type:"uint256"},{internalType:"uint256",name:"nonce",type:"uint256"},{internalType:"uint8",name:"size",type:"uint8"},{internalType:"enum PoolOrders.OptionType",name:"optionType",type:"uint8"},{internalType:"uint256",name:"maxStrikePriceMultiple",type:"uint256"},{internalType:"uint64",name:"minOptionDuration",type:"uint64"},{internalType:"uint64",name:"maxOptionDuration",type:"uint64"},{internalType:"uint64",name:"maxPriceSignalAge",type:"uint64"},{components:[{internalType:"contract IPropertyValidator",name:"propertyValidator",type:"address"},{internalType:"bytes",name:"propertyData",type:"bytes"}],internalType:"struct PoolOrders.Property[]",name:"nftProperties",type:"tuple[]"},{internalType:"address",name:"optionMarketAddress",type:"address"},{internalType:"uint64",name:"impliedVolBips",type:"uint64"},{internalType:"uint256",name:"skewDecimal",type:"uint256"},{internalType:"uint64",name:"riskFreeRateBips",type:"uint64"}],internalType:"struct PoolOrders.Order",name:"order",type:"tuple"},{components:[{internalType:"enum Signatures.SignatureType",name:"signatureType",type:"uint8"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],internalType:"struct Signatures.Signature",name:"orderSignature",type:"tuple"},{components:[{internalType:"uint256",name:"assetPriceInWei",type:"uint256"},{internalType:"uint256",name:"priceObservedTimestamp",type:"uint256"},{internalType:"uint256",name:"goodTilTimestamp",type:"uint256"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],internalType:"struct HookBidPool.AssetPriceClaim",name:"assetPrice",type:"tuple"},{components:[{internalType:"bytes32",name:"orderHash",type:"bytes32"},{internalType:"uint256",name:"goodTilTimestamp",type:"uint256"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],internalType:"struct HookBidPool.OrderValidityOracleClaim",name:"orderValidityOracleClaim",type:"tuple"},{internalType:"uint256",name:"saleProceeds",type:"uint256"},{internalType:"address",name:"optionInstrumentAddress",type:"address"},{internalType:"uint256",name:"optionId",type:"uint256"}],name:"sellOption",outputs:[],stateMutability:"nonpayable",type:"function",details:'the optionInstrumentAddress must be trusted by the orderer (maker) when signing to be related to their desired market / option terms (i.e. the option must be a european call option on the correct underlying asset). If the option instrument/market supports many different sub-collections, as in the case with artblocks or a foundation shared contract, then a corresponding property validator should be included in the order as to ensure that the underlying asset for the option is the one that the maker intended. The value of the "bid" for a specific order changes (decreases) with each block because the time until the option expires decreases. Instead of computing the highest possible sale proceeds at the time of the order, an implementer can compute a slightly lower sale proceeds, perhaps at a time a few blocks into the future, to ensure that the transaction is still successful. If they do this, the protocol won\'t earn extra fees -- that savings is passed on to the buyer.',params:{assetPrice:"the price of the underlying asset, signed off-chain by the oracle",optionId:"the id of the option token",optionInstrumentAddress:"the address of the Hook option instrument contract",order:"the order struct from the off-chain orderbook",orderSignature:"the signature of the order struct signed by the maker",orderValidityOracleClaim:"the claim that the order is still valid, signed off-chain by the oracle",saleProceeds:"the proceeds from the sale desired by the filler/caller, denominated in the quote asset"},notice:"sells a european call option to a bidder"},"setFeeBips(uint64)":{inputs:[{internalType:"uint64",name:"_feeBips",type:"uint64"}],name:"setFeeBips",outputs:[],stateMutability:"nonpayable",type:"function"},"setFeeRecipient(address)":{inputs:[{internalType:"address",name:"_feeRecipient",type:"address"}],name:"setFeeRecipient",outputs:[],stateMutability:"nonpayable",type:"function"},"setOrderValidityOracleSigner(address)":{inputs:[{internalType:"address",name:"_orderValidityOracleSigner",type:"address"}],name:"setOrderValidityOracleSigner",outputs:[],stateMutability:"nonpayable",type:"function"},"setPoolPaused(bool)":{inputs:[{internalType:"bool",name:"_paused",type:"bool"}],name:"setPoolPaused",outputs:[],stateMutability:"nonpayable",type:"function",details:"sets a paused / unpaused state for this bid pool",params:{_paused:"should the bid pool be set to paused?"}},"setPriceOracleSigner(address)":{inputs:[{internalType:"address",name:"_priceOracleSigner",type:"address"}],name:"setPriceOracleSigner",outputs:[],stateMutability:"nonpayable",type:"function"},"setProtocol(address)":{inputs:[{internalType:"address",name:"_protocol",type:"address"}],name:"setProtocol",outputs:[],stateMutability:"nonpayable",type:"function",notice:"EXTERNAL ACCESS-CONTROLLED FUNCTIONS ///"},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC165-supportsInterface}."}}},"src/HookCoveredCallFactory.sol:HookCoveredCallFactory":{source:"src/HookCoveredCallFactory.sol",name:"HookCoveredCallFactory",title:"Hook Covered Call Factory",author:"Jake Nyquist-j@hook.xyz",details:"See {IHookCoveredCallFactory}.The factory looks up certain roles by calling the {IHookProtocol} to verify",constructor:{inputs:[{internalType:"address",name:"hookProtocolAddress",type:"address"},{internalType:"address",name:"beaconAddress",type:"address"},{internalType:"address",name:"preApprovedMarketplace",type:"address"}],stateMutability:"nonpayable",type:"constructor"},events:{"CoveredCallInstrumentCreated(address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"assetAddress",type:"address"},{indexed:!1,internalType:"address",name:"instrumentAddress",type:"address"}],name:"CoveredCallInstrumentCreated",type:"event"}},methods:{"ALLOWLISTER_ROLE()":{inputs:[],name:"ALLOWLISTER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the allowlister is able to enable and disable projects to mint instruments"},"CALL_UPGRADER()":{inputs:[],name:"CALL_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the call upgrader role is able to upgrade the implementation of the covered call options"},"COLLECTION_CONF()":{inputs:[],name:"COLLECTION_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the collection configuration role allows the actor to make changes the collection configs on the protocol contract"},"MARKET_CONF()":{inputs:[],name:"MARKET_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the market configuration role allows the actor to make changes to how the market operates"},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the pauser is able to start and pause various components of the protocol"},"VAULT_UPGRADER()":{inputs:[],name:"VAULT_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the vault upgrader role is able to upgrade the implementation for all vaults"},"getCallInstrument(address)":{inputs:[{internalType:"address",name:"",type:"address"}],name:"getCallInstrument",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"Registry of all of the active markets projects with supported call instruments"},"makeCallInstrument(address)":{inputs:[{internalType:"address",name:"assetAddress",type:"address"}],name:"makeCallInstrument",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCallFactory-makeCallInstrument}.Only holders of the ALLOWLISTER_ROLE on the {IHookProtocol} can create these addresses."}}},"src/HookCoveredCallImplV1.sol:HookCoveredCallImplV1":{source:"src/HookCoveredCallImplV1.sol",name:"HookCoveredCallImplV1",title:"HookCoveredCallImplV1 an implementation of covered calls on Hook",author:"Jake Nyquist-j@hook.xyz",details:"In the context of a single call option, the role of the writer is non-transferrable.This contract is intended to be an implementation referenced by a proxy",notice:"See {IHookCoveredCall}.",constructor:{inputs:[],stateMutability:"nonpayable",type:"constructor"},events:{"Approval(address,address,uint256)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"owner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint256",name:"tokenId",type:"uint256"}],name:"Approval",type:"event"},"ApprovalForAll(address,address,bool)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"owner",type:"address"},{indexed:!0,internalType:"address",name:"operator",type:"address"},{indexed:!1,internalType:"bool",name:"approved",type:"bool"}],name:"ApprovalForAll",type:"event"},"Bid(uint256,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"uint256",name:"bidAmount",type:"uint256"},{indexed:!1,internalType:"address",name:"bidder",type:"address"}],name:"Bid",type:"event",notice:"emitted when a call option settlement auction gets and accepts a new bid"},"CallCreated(address,address,uint256,uint256,uint256,uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"writer",type:"address"},{indexed:!1,internalType:"address",name:"vaultAddress",type:"address"},{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"uint256",name:"strikePrice",type:"uint256"},{indexed:!1,internalType:"uint256",name:"expiration",type:"uint256"}],name:"CallCreated",type:"event",notice:"emitted when a new call option is successfully minted with a specific underlying vault"},"CallProceedsDistributed(uint256,address,uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"uint256",name:"amount",type:"uint256"}],name:"CallProceedsDistributed",type:"event",notice:"emitted when an option owner claims their proceeds"},"CallReclaimed(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"}],name:"CallReclaimed",type:"event",notice:"emitted when a call option is reclaimed"},"CallSettled(uint256,bool)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"bool",name:"claimable",type:"bool"}],name:"CallSettled",type:"event",notice:"emitted when a call option is settled"},"ExpiredCallBurned(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"}],name:"ExpiredCallBurned",type:"event",notice:"emitted when a expired call option is burned"},"Initialized(uint8)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint8",name:"version",type:"uint8"}],name:"Initialized",type:"event"},"MarketPauseUpdated(bool)":{anonymous:!1,inputs:[{indexed:!1,internalType:"bool",name:"paused",type:"bool"}],name:"MarketPauseUpdated",type:"event",details:"Emitted when the market is paused or unpaused",params:{paused:"true if paused false otherwise"}},"MinBidIncrementUpdated(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"bidIncrementBips",type:"uint256"}],name:"MinBidIncrementUpdated",type:"event",details:"Emitted when the bid increment is updated",params:{bidIncrementBips:"the new bid increment amount in bips"}},"MinOptionDurationUpdated(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionDuration",type:"uint256"}],name:"MinOptionDurationUpdated",type:"event",details:"emitted when the minimum duration for an option is changed",params:{optionDuration:"new minimum length of an option in seconds."}},"SettlementAuctionStartOffsetUpdated(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"startOffset",type:"uint256"}],name:"SettlementAuctionStartOffsetUpdated",type:"event",details:"emitted when the settlement auction start offset is updated",params:{startOffset:"new number of seconds from expiration when the start offset begins"}},"Transfer(address,address,uint256)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"from",type:"address"},{indexed:!0,internalType:"address",name:"to",type:"address"},{indexed:!0,internalType:"uint256",name:"tokenId",type:"uint256"}],name:"Transfer",type:"event"}},stateVariables:{"allowedUnderlyingAddress()":{inputs:[],name:"allowedUnderlyingAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"stateVariable",details:"the address of the token contract permitted to serve as underlying assets for this instrument."},"marketPaused()":{inputs:[],name:"marketPaused",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"stateVariable",details:"this is a flag that can be set to pause this particular instance of the call option contract. NOTE: settlement auctions are still enabled in this case because pausing the market should not change the financial situation for the holder of the options."},"minBidIncrementBips()":{inputs:[],name:"minBidIncrementBips",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"stateVariable",details:"this is the minimum amount of the current bid that the new bid must exceed the current bid by in order to be considered valid. This amount is expressed in basis points (i.e. 1/100th of 1%)"},"minimumOptionDuration()":{inputs:[],name:"minimumOptionDuration",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"stateVariable",details:"this is the minimum duration of an option created in this contract instance"},"settlementAuctionStartOffset()":{inputs:[],name:"settlementAuctionStartOffset",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"stateVariable",details:"this is the amount of time before the expiration of the option that the settlement auction will begin."},"weth()":{inputs:[],name:"weth",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"stateVariable",details:"the address of WETH on the chain where this contract is deployed"}},methods:{"ALLOWLISTER_ROLE()":{inputs:[],name:"ALLOWLISTER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the allowlister is able to enable and disable projects to mint instruments"},"CALL_UPGRADER()":{inputs:[],name:"CALL_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the call upgrader role is able to upgrade the implementation of the covered call options"},"COLLECTION_CONF()":{inputs:[],name:"COLLECTION_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the collection configuration role allows the actor to make changes the collection configs on the protocol contract"},"MARKET_CONF()":{inputs:[],name:"MARKET_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the market configuration role allows the actor to make changes to how the market operates"},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the pauser is able to start and pause various components of the protocol"},"VAULT_UPGRADER()":{inputs:[],name:"VAULT_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the vault upgrader role is able to upgrade the implementation for all vaults"},"_preApprovedMarketplace()":{inputs:[],name:"_preApprovedMarketplace",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function"},"approve(address,uint256)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"approve",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-approve}."},"assetOptions(address,uint32)":{inputs:[{internalType:"contract IHookVault",name:"",type:"address"},{internalType:"uint32",name:"",type:"uint32"}],name:"assetOptions",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"},"balanceOf(address)":{inputs:[{internalType:"address",name:"owner",type:"address"}],name:"balanceOf",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"See {IERC721-balanceOf}."},"bid(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"bid",outputs:[],stateMutability:"payable",type:"function",details:"See {IHookCoveredCall-bid}."},"burn(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"burn",outputs:[],stateMutability:"nonpayable",type:"function",details:"Burns `tokenId`. See {ERC721-_burn}. Requirements: - The caller must own `tokenId` or be an approved operator."},"burnExpiredOption(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"burnExpiredOption",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-burnExpiredOption}."},"claimOptionProceeds(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"claimOptionProceeds",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-claimOptionProceeds}"},"contractUri(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"contractUri",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"this is the OpenSea compatible collection - level metadata URI."},"currentBid(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"currentBid",outputs:[{internalType:"uint128",name:"",type:"uint128"}],stateMutability:"view",type:"function",details:"See {IHookCoveredCall-currentBid}."},"currentBidder(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"currentBidder",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IHookCoveredCall-currentBidder}."},"getApproved(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"getApproved",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IERC721-getApproved}."},"getAssetId(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getAssetId",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",details:"see {IHookCoveredCall-getAssetId}."},"getExpiration(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getExpiration",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"see {IHookCoveredCall-getExpiration}."},"getOptionIdForAsset(address,uint32)":{inputs:[{internalType:"address",name:"vault",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getOptionIdForAsset",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"see {IHookCoveredCall-getOptionIdForAsset}"},"getStrikePrice(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getStrikePrice",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"see {IHookCoveredCall-getStrikePrice}."},"getTransferCount(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getTransferCount",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"this count can be used by overbooks to invalidate orders after a token has been transferred, preventing stale order execution by malicious parties",notice:"the number of times the token has been transferred"},"getVaultAddress(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getVaultAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"see {IHookCoveredCall-getVaultAddress}."},"initialize(address,address,address,address)":{inputs:[{internalType:"address",name:"protocol",type:"address"},{internalType:"address",name:"nftContract",type:"address"},{internalType:"address",name:"hookVaultFactory",type:"address"},{internalType:"address",name:"preApprovedMarketplace",type:"address"}],name:"initialize",outputs:[],stateMutability:"nonpayable",type:"function",details:"Because the deployed contract is proxied, arguments unique to each deployment must be passed in an individual initializer. This function is like a constructor.",params:{hookVaultFactory:"the address of the ERC-721 vault registry",nftContract:"the address for the ERC-721 contract that can serve as underlying instruments",preApprovedMarketplace:"the address of the contract which will automatically approved to transfer option ERC721s owned by any account when they're minted",protocol:"the address of the Hook protocol (which contains configurations)"},notice:"Initializes the specific instance of the instrument contract."},"isApprovedForAll(address,address)":{inputs:[{internalType:"address",name:"owner",type:"address"},{internalType:"address",name:"operator",type:"address"}],name:"isApprovedForAll",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC721-isApprovedForAll}. this extension ensures that any operator contract located at {_approvedMarketpace} is considered approved internally in the ERC721 contract"},"mintWithEntitledVault(address,uint32,uint128,uint32)":{inputs:[{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint128",name:"strikePrice",type:"uint128"},{internalType:"uint32",name:"expirationTime",type:"uint32"}],name:"mintWithEntitledVault",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-mintWithEntitledVault}."},"mintWithErc721(address,uint256,uint128,uint32)":{inputs:[{internalType:"address",name:"tokenAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"uint128",name:"strikePrice",type:"uint128"},{internalType:"uint32",name:"expirationTime",type:"uint32"}],name:"mintWithErc721",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-mintWithErc721}."},"mintWithVault(address,uint32,uint128,uint32,(uint8,uint8,bytes32,bytes32))":{inputs:[{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint128",name:"strikePrice",type:"uint128"},{internalType:"uint32",name:"expirationTime",type:"uint32"},{components:[{internalType:"enum Signatures.SignatureType",name:"signatureType",type:"uint8"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],internalType:"struct Signatures.Signature",name:"signature",type:"tuple"}],name:"mintWithVault",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-mintWithVault}."},"name()":{inputs:[],name:"name",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"See {IERC721Metadata-name}."},"optionClaims(uint256)":{inputs:[{internalType:"uint256",name:"",type:"uint256"}],name:"optionClaims",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"},"optionParams(uint256)":{inputs:[{internalType:"uint256",name:"",type:"uint256"}],name:"optionParams",outputs:[{internalType:"address",name:"writer",type:"address"},{internalType:"uint32",name:"expiration",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint128",name:"strike",type:"uint128"},{internalType:"uint128",name:"bid",type:"uint128"},{internalType:"address",name:"highBidder",type:"address"},{internalType:"bool",name:"settled",type:"bool"}],stateMutability:"view",type:"function"},"ownerOf(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"ownerOf",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IERC721-ownerOf}."},"reclaimAsset(uint256,bool)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"},{internalType:"bool",name:"returnNft",type:"bool"}],name:"reclaimAsset",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-reclaimAsset}."},"safeTransferFrom(address,address,uint256)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"safeTransferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-safeTransferFrom}."},"safeTransferFrom(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"_data",type:"bytes"}],name:"safeTransferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-safeTransferFrom}."},"setApprovalForAll(address,bool)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"bool",name:"approved",type:"bool"}],name:"setApprovalForAll",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-setApprovalForAll}."},"setBidIncrement(uint256)":{inputs:[{internalType:"uint256",name:"newBidIncrement",type:"uint256"}],name:"setBidIncrement",outputs:[],stateMutability:"nonpayable",type:"function",details:"set the minimum overage, in bips, for a new bid compared to the current bid.",params:{newBidIncrement:"the minimum bid increment in basis points (1/100th of 1%)"}},"setMarketPaused(bool)":{inputs:[{internalType:"bool",name:"paused",type:"bool"}],name:"setMarketPaused",outputs:[],stateMutability:"nonpayable",type:"function",details:"sets a paused / unpaused state for the market corresponding to this contract",params:{paused:"should the market be set to paused or unpaused"}},"setMinOptionDuration(uint256)":{inputs:[{internalType:"uint256",name:"newMinDuration",type:"uint256"}],name:"setMinOptionDuration",outputs:[],stateMutability:"nonpayable",type:"function",details:"configures the minimum duration for a newly minted option. Options must be at least this far away in the future.",params:{newMinDuration:"is the minimum option duration in seconds"}},"setSettlementAuctionStartOffset(uint256)":{inputs:[{internalType:"uint256",name:"newSettlementStartOffset",type:"uint256"}],name:"setSettlementAuctionStartOffset",outputs:[],stateMutability:"nonpayable",type:"function",details:"set the settlement auction start offset. Settlement auctions begin at this time prior to expiration.",params:{newSettlementStartOffset:"in seconds (i.e. block.timestamp increments)"}},"settleOption(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"settleOption",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookCoveredCall-settleOption}."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC165-supportsInterface}."},"symbol()":{inputs:[],name:"symbol",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"See {IERC721Metadata-symbol}."},"tokenURI(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"tokenURI",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"See {IERC721-tokenURI}."},"transferFrom(address,address,uint256)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"transferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-transferFrom}."}}},"src/HookERC721MultiVaultImplV1.sol:HookERC721MultiVaultImplV1":{source:"src/HookERC721MultiVaultImplV1.sol",name:"HookERC721MultiVaultImplV1",title:"HookMultiVault-implementation of a Vault for multiple assets within a NFT collection, with entitlements.",author:"Jake Nyquist - j@hook.xyz",details:"This contract implements ERC721Receiver This contract views the tokenId for the asset on the ERC721 contract as the corresponding assetId for that asset when deposited into the vault",notice:'HookVault holds a multiple NFT asset in escrow on behalf of multiple beneficial owners. Other contracts are able to register "entitlements" for a fixed period of time on the asset, which give them the ability to change the vault\'s owner.',constructor:{inputs:[],stateMutability:"nonpayable",type:"constructor"},events:{"Approval(address,address,uint32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint32",name:"assetId",type:"uint32"}],name:"Approval",type:"event",notice:"Emitted when `beneficialOwner` enables `approved` to manage the `assetId` asset."},"AssetFlashLoaned(address,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"uint256",name:"tokenId",type:"uint256"},{indexed:!1,internalType:"address",name:"flashLoanImpl",type:"address"}],name:"AssetFlashLoaned",type:"event",notice:"emitted after an asset is flash loaned by its beneficial owner."},"AssetReceived(address,address,address,uint32)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"address",name:"sender",type:"address"},{indexed:!1,internalType:"address",name:"contractAddress",type:"address"},{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"}],name:"AssetReceived",type:"event",notice:"emitted when an asset is added into the vault"},"AssetWithdrawn(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"AssetWithdrawn",type:"event",notice:"emitted when an asset is withdrawn from the vault"},"BeneficialOwnerSet(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!1,internalType:"address",name:"setBy",type:"address"}],name:"BeneficialOwnerSet",type:"event",notice:"emitted when the beneficial owner of an asset changes"},"EntitlementCleared(uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementCleared",type:"event",notice:"emitted when an entitlement is cleared from an asset"},"EntitlementImposed(uint32,address,uint32,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"entitledAccount",type:"address"},{indexed:!1,internalType:"uint32",name:"expiry",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementImposed",type:"event",notice:"emitted when an entitlement is placed on an asset"},"Initialized(uint8)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint8",name:"version",type:"uint8"}],name:"Initialized",type:"event"}},methods:{"EIP712_DOMAIN_SEPARATOR()":{inputs:[],name:"EIP712_DOMAIN_SEPARATOR",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function"},"approveOperator(address,uint32)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"approveOperator",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookVault-approveOperator}."},"assetAddress(uint32)":{inputs:[{internalType:"uint32",name:"",type:"uint32"}],name:"assetAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function"},"assetTokenId(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetTokenId",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"returns the underlying token ID for a given asset. In this case the tokenId == the assetId"},"clearEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"clearEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-clearEntitlement}.This can only be called if an entitlement currently exists, otherwise it would be a no-op"},"clearEntitlementAndDistribute(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiver",type:"address"}],name:"clearEntitlementAndDistribute",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-clearEntitlementAndDistribute}.The entitlement must be exist, and must be called by the {operator}. The operator can specify a intended receiver, which should match the beneficialOwner. The function will throw if the receiver and owner do not match.",params:{assetId:"the id of the specific vaulted asset",receiver:"the intended receiver of the asset"}},"entitlementExpiration(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"entitlementExpiration",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",details:"See {IHookVault-entitlementExpiration}."},"flashLoan(uint32,address,bytes)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiverAddress",type:"address"},{internalType:"bytes",name:"params",type:"bytes"}],name:"flashLoan",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-flashLoan}."},"getApprovedOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getApprovedOperator",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IHookVault-getApprovedOperator}."},"getBeneficialOwner(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getBeneficialOwner",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IHookERC721Vault-getBeneficialOwner}."},"getCurrentEntitlementOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getCurrentEntitlementOperator",outputs:[{internalType:"bool",name:"",type:"bool"},{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the id of the underlying asset"},notice:"looks up the current operator of an entitlement on an asset"},"getHoldsAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getHoldsAsset",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IHookERC721Vault-getHoldsAsset}."},"grantEntitlement((address,address,address,uint32,uint32))":{inputs:[{components:[{internalType:"address",name:"beneficialOwner",type:"address"},{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint32",name:"expiry",type:"uint32"}],internalType:"struct Entitlements.Entitlement",name:"entitlement",type:"tuple"}],name:"grantEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-grantEntitlement}.The entitlement must be sent by the current beneficial owner"},"hasActiveEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"hasActiveEntitlement",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function"},"imposeEntitlement(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"imposeEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-imposeEntitlement}.The entitlement must be signed by the current beneficial owner of the contract. Anyone can submit the entitlement"},"initialize(address,address)":{inputs:[{internalType:"address",name:"nftContract",type:"address"},{internalType:"address",name:"hookAddress",type:"address"}],name:"initialize",outputs:[],stateMutability:"nonpayable",type:"function",notice:"-constructor"},"onERC721Received(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"from",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"data",type:"bytes"}],name:"onERC721Received",outputs:[{internalType:"bytes4",name:"",type:"bytes4"}],stateMutability:"nonpayable",type:"function",details:"See {IERC721Receiver-onERC721Received}. Always returns `IERC721Receiver.onERC721Received.selector`."},"setBeneficialOwner(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"newBeneficialOwner",type:"address"}],name:"setBeneficialOwner",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-setBeneficialOwner}. setBeneficialOwner can only be called by the entitlementContract if there is an activeEntitlement."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC165-supportsInterface}."},"validateEntitlementSignature(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"validateEntitlementSignature",outputs:[],stateMutability:"view",type:"function",details:"Validates that a specific signature is actually the entitlement EIP-712 signed by the beneficial owner specified in the entitlement."},"withdrawalAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"withdrawalAsset",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-withdrawalAsset}.withdrawals can only be performed to the beneficial owner if there are no entitlements"}}},"src/HookERC721VaultFactory.sol:HookERC721VaultFactory":{source:"src/HookERC721VaultFactory.sol",name:"HookERC721VaultFactory",title:"Hook Vault Factory",author:"Jake Nyquist-j@hook.xyz",details:"See {IHookERC721VaultFactory}.The factory itself is non-upgradeable; however, each vault is upgradeable (i.e. all vaults) created by this factory can be upgraded at one time via the beacon pattern.",constructor:{inputs:[{internalType:"address",name:"hookProtocolAddress",type:"address"},{internalType:"address",name:"beaconAddress",type:"address"},{internalType:"address",name:"multiBeaconAddress",type:"address"}],stateMutability:"nonpayable",type:"constructor"},events:{"ERC721MultiVaultCreated(address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"nftAddress",type:"address"},{indexed:!1,internalType:"address",name:"vaultAddress",type:"address"}],name:"ERC721MultiVaultCreated",type:"event",notice:"emitted when a new MultiVault is deployed by the protocol"},"ERC721VaultCreated(address,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"nftAddress",type:"address"},{indexed:!1,internalType:"uint256",name:"tokenId",type:"uint256"},{indexed:!1,internalType:"address",name:"vaultAddress",type:"address"}],name:"ERC721VaultCreated",type:"event"}},methods:{"ALLOWLISTER_ROLE()":{inputs:[],name:"ALLOWLISTER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the allowlister is able to enable and disable projects to mint instruments"},"CALL_UPGRADER()":{inputs:[],name:"CALL_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the call upgrader role is able to upgrade the implementation of the covered call options"},"COLLECTION_CONF()":{inputs:[],name:"COLLECTION_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the collection configuration role allows the actor to make changes the collection configs on the protocol contract"},"MARKET_CONF()":{inputs:[],name:"MARKET_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the market configuration role allows the actor to make changes to how the market operates"},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the pauser is able to start and pause various components of the protocol"},"VAULT_UPGRADER()":{inputs:[],name:"VAULT_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the vault upgrader role is able to upgrade the implementation for all vaults"},"findOrCreateVault(address,uint256)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"findOrCreateVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",notice:"See {IHookERC721VaultFactory-findOrCreateVault}."},"getMultiVault(address)":{inputs:[{internalType:"address",name:"",type:"address"}],name:"getMultiVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"Registry of all of the active multi-vaults within the protocol"},"getVault(address,uint256)":{inputs:[{internalType:"address",name:"",type:"address"},{internalType:"uint256",name:"",type:"uint256"}],name:"getVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"Registry of all of the active vaults within the protocol, allowing users to find vaults by project address and tokenId;"},"makeMultiVault(address)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"}],name:"makeMultiVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",notice:"See {IHookERC721VaultFactory-makeMultiVault}."},"makeSoloVault(address,uint256)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"makeSoloVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",notice:"See {IHookERC721VaultFactory-makeSoloVault}."}}},"src/HookERC721VaultImplV1.sol:HookERC721VaultImplV1":{source:"src/HookERC721VaultImplV1.sol",name:"HookERC721VaultImplV1",title:"HookVault-implementation of a Vault for a single NFT asset, with entitlements.",author:"Jake Nyquist - j@hook.xyz",details:"This contract implements ERC721Receiver and extends the MultiVault, simply treating the stored asset as assetId 0 in all cases. SEND TRANSACTION - (1) owners are able to forward transactions to this vault to other wallets (2) calls to the ERC-721 address are blocked to prevent approvals from being set on the NFT while in escrow, which could allow for theft (3) At the end of each transaction, the ownerOf the vaulted token must still be the vault",notice:'HookVault holds a single NFT asset in escrow on behalf of a user. Other contracts are able to register "entitlements" for a fixed period of time on the asset, which give them the ability to change the vault\'s owner.',constructor:{inputs:[],stateMutability:"nonpayable",type:"constructor"},events:{"Approval(address,address,uint32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint32",name:"assetId",type:"uint32"}],name:"Approval",type:"event",notice:"Emitted when `beneficialOwner` enables `approved` to manage the `assetId` asset."},"AssetFlashLoaned(address,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"uint256",name:"tokenId",type:"uint256"},{indexed:!1,internalType:"address",name:"flashLoanImpl",type:"address"}],name:"AssetFlashLoaned",type:"event",notice:"emitted after an asset is flash loaned by its beneficial owner."},"AssetReceived(address,address,address,uint32)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"address",name:"sender",type:"address"},{indexed:!1,internalType:"address",name:"contractAddress",type:"address"},{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"}],name:"AssetReceived",type:"event",notice:"emitted when an asset is added into the vault"},"AssetWithdrawn(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"AssetWithdrawn",type:"event",notice:"emitted when an asset is withdrawn from the vault"},"BeneficialOwnerSet(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!1,internalType:"address",name:"setBy",type:"address"}],name:"BeneficialOwnerSet",type:"event",notice:"emitted when the beneficial owner of an asset changes"},"EntitlementCleared(uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementCleared",type:"event",notice:"emitted when an entitlement is cleared from an asset"},"EntitlementImposed(uint32,address,uint32,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"entitledAccount",type:"address"},{indexed:!1,internalType:"uint32",name:"expiry",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementImposed",type:"event",notice:"emitted when an entitlement is placed on an asset"},"Initialized(uint8)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint8",name:"version",type:"uint8"}],name:"Initialized",type:"event"}},methods:{"EIP712_DOMAIN_SEPARATOR()":{inputs:[],name:"EIP712_DOMAIN_SEPARATOR",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function"},"approveOperator(address,uint32)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"approveOperator",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookVault-approveOperator}."},"assetAddress(uint32)":{inputs:[{internalType:"uint32",name:"",type:"uint32"}],name:"assetAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function"},"assetTokenId(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetTokenId",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"returns the underlying token ID for a given asset. In this case the tokenId == the assetId"},"clearEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"clearEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-clearEntitlement}.This can only be called if an entitlement currently exists, otherwise it would be a no-op"},"clearEntitlementAndDistribute(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiver",type:"address"}],name:"clearEntitlementAndDistribute",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-clearEntitlementAndDistribute}.The entitlement must be exist, and must be called by the {operator}. The operator can specify a intended receiver, which should match the beneficialOwner. The function will throw if the receiver and owner do not match.",params:{assetId:"the id of the specific vaulted asset",receiver:"the intended receiver of the asset"}},"entitlementExpiration(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"entitlementExpiration",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",details:"See {IHookVault-entitlementExpiration}."},"execTransaction(address,bytes)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"bytes",name:"data",type:"bytes"}],name:"execTransaction",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"payable",type:"function",details:"See {IHookERC721Vault-execTransaction}.Allows a beneficial owner to send an arbitrary call from this wallet as long as the underlying NFT is still owned by us after the transaction. The ether value sent is forwarded. Return value is suppressed. Because this contract holds only a single asset owned by a single address, it supports calling exec transaction from this address because such calls are unlikely to impact other owner's assets."},"flashLoan(uint32,address,bytes)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiverAddress",type:"address"},{internalType:"bytes",name:"params",type:"bytes"}],name:"flashLoan",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-flashLoan}."},"getApprovedOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getApprovedOperator",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IHookVault-getApprovedOperator}."},"getBeneficialOwner(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getBeneficialOwner",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IHookERC721Vault-getBeneficialOwner}."},"getCurrentEntitlementOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getCurrentEntitlementOperator",outputs:[{internalType:"bool",name:"",type:"bool"},{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the id of the underlying asset"},notice:"looks up the current operator of an entitlement on an asset"},"getHoldsAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getHoldsAsset",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IHookERC721Vault-getHoldsAsset}."},"grantEntitlement((address,address,address,uint32,uint32))":{inputs:[{components:[{internalType:"address",name:"beneficialOwner",type:"address"},{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint32",name:"expiry",type:"uint32"}],internalType:"struct Entitlements.Entitlement",name:"entitlement",type:"tuple"}],name:"grantEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-grantEntitlement}.The entitlement must be sent by the current beneficial owner"},"hasActiveEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"hasActiveEntitlement",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function"},"imposeEntitlement(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"imposeEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-imposeEntitlement}.The entitlement must be signed by the current beneficial owner of the contract. Anyone may call this function and successfully impose the entitlement as long as the signature is valid."},"initialize(address,address)":{inputs:[{internalType:"address",name:"nftContract",type:"address"},{internalType:"address",name:"hookAddress",type:"address"}],name:"initialize",outputs:[],stateMutability:"nonpayable",type:"function",notice:"-constructor"},"initialize(address,uint256,address)":{inputs:[{internalType:"address",name:"nftContract",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"address",name:"hookAddress",type:"address"}],name:"initialize",outputs:[],stateMutability:"nonpayable",type:"function",notice:"-constructor"},"onERC721Received(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"from",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"data",type:"bytes"}],name:"onERC721Received",outputs:[{internalType:"bytes4",name:"",type:"bytes4"}],stateMutability:"nonpayable",type:"function",details:"See {IERC721Receiver-onERC721Received}. Always returns `IERC721Receiver.onERC721Received.selector`. This method requires an override implementation because the the arguments must be embedded in the body of the function"},"setBeneficialOwner(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"newBeneficialOwner",type:"address"}],name:"setBeneficialOwner",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-setBeneficialOwner}."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC165-supportsInterface}."},"validateEntitlementSignature(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"validateEntitlementSignature",outputs:[],stateMutability:"view",type:"function",details:"Validates that a specific signature is actually the entitlement EIP-712 signed by the beneficial owner specified in the entitlement."},"withdrawalAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"withdrawalAsset",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IHookERC721Vault-withdrawalAsset}.withdrawals can only be performed by the beneficial owner if there are no entitlements"}}},"src/HookProtocol.sol:HookProtocol":{source:"src/HookProtocol.sol",name:"HookProtocol",details:"Other contracts in the protocol refer to this one to get configuration and pausing issues. to reduce attack surface area, this contract cannot be upgraded; however, additional roles can be added. This contract does not implement any specific timelocks or other safety measures. The roles are granted with the principal of least privilege. As the protocol matures, these additional measures can be layered by granting these roles to other contracts. In the extreme, the upgrade and other roles can be burned, which would effectively make the protocol static and non-upgradeable.",constructor:{inputs:[{internalType:"address",name:"allowlister",type:"address"},{internalType:"address",name:"pauser",type:"address"},{internalType:"address",name:"vaultUpgrader",type:"address"},{internalType:"address",name:"callUpgrader",type:"address"},{internalType:"address",name:"marketConf",type:"address"},{internalType:"address",name:"collectionConf",type:"address"},{internalType:"address",name:"weth",type:"address"}],stateMutability:"nonpayable",type:"constructor"},events:{"Paused(address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"account",type:"address"}],name:"Paused",type:"event"},"RoleAdminChanged(bytes32,bytes32,bytes32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"bytes32",name:"previousAdminRole",type:"bytes32"},{indexed:!0,internalType:"bytes32",name:"newAdminRole",type:"bytes32"}],name:"RoleAdminChanged",type:"event"},"RoleGranted(bytes32,address,address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"address",name:"account",type:"address"},{indexed:!0,internalType:"address",name:"sender",type:"address"}],name:"RoleGranted",type:"event"},"RoleRevoked(bytes32,address,address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"address",name:"account",type:"address"},{indexed:!0,internalType:"address",name:"sender",type:"address"}],name:"RoleRevoked",type:"event"},"Unpaused(address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"account",type:"address"}],name:"Unpaused",type:"event"}},stateVariables:{"getWETHAddress()":{inputs:[],name:"getWETHAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"stateVariable",details:"these are values for popular chains: mainnet: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 kovan: 0xd0a1e359811322d97991e03f863a0c30c2cf029c ropsten: 0xc778417e063141139fce010982780140aa0cd5ab rinkeby: 0xc778417e063141139fce010982780140aa0cd5ab",return:"the weth address",returns:{_0:"the weth address"},notice:"the standard weth address on this chain"}},methods:{"ALLOWLISTER_ROLE()":{inputs:[],name:"ALLOWLISTER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the allowlister is able to enable and disable projects to mint instruments"},"CALL_UPGRADER()":{inputs:[],name:"CALL_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the call upgrader role is able to upgrade the implementation of the covered call options"},"COLLECTION_CONF()":{inputs:[],name:"COLLECTION_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the collection configuration role allows the actor to make changes the collection configs on the protocol contract"},"DEFAULT_ADMIN_ROLE()":{inputs:[],name:"DEFAULT_ADMIN_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function"},"MARKET_CONF()":{inputs:[],name:"MARKET_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the market configuration role allows the actor to make changes to how the market operates"},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the pauser is able to start and pause various components of the protocol"},"VAULT_UPGRADER()":{inputs:[],name:"VAULT_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the vault upgrader role is able to upgrade the implementation for all vaults"},"coveredCallContract()":{inputs:[],name:"coveredCallContract",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"the address of the deployed CoveredCallFactory used by the protocol"},"getCollectionConfig(address,bytes32)":{inputs:[{internalType:"address",name:"collectionAddress",type:"address"},{internalType:"bytes32",name:"conf",type:"bytes32"}],name:"getCollectionConfig",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IHookProtocol-getCollectionConfig}."},"getRoleAdmin(bytes32)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"}],name:"getRoleAdmin",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",details:"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"grantRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"hasRole",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns `true` if `account` has been granted `role`."},"pause()":{inputs:[],name:"pause",outputs:[],stateMutability:"nonpayable",type:"function",notice:"pauses the protocol if the protocol is currently unpaused"},"paused()":{inputs:[],name:"paused",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns true if the contract is paused, and false otherwise."},"renounceRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"renounceRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`."},"revokeRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"revokeRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."},"setCollectionConfig(address,bytes32,bool)":{inputs:[{internalType:"address",name:"collectionAddress",type:"address"},{internalType:"bytes32",name:"config",type:"bytes32"},{internalType:"bool",name:"value",type:"bool"}],name:"setCollectionConfig",outputs:[],stateMutability:"nonpayable",type:"function",details:"the conf value can be read with getCollectionConfig",params:{collectionAddress:"the address for the collection",config:"the configuration field to set",value:"the value to set for the configuration"},notice:"allows an account with the COLLECTION_CONF role to set a boolean config value for a collection"},"setCoveredCallFactory(address)":{inputs:[{internalType:"address",name:"coveredCallFactoryContract",type:"address"}],name:"setCoveredCallFactory",outputs:[],stateMutability:"nonpayable",type:"function",details:"This address is used by other protocols searching for the registry of protocols.",params:{coveredCallFactoryContract:"the address of the deployed covered call contract"},notice:"Allows an admin to set the address of the deployed covered call factory"},"setVaultFactory(address)":{inputs:[{internalType:"address",name:"vaultFactoryContract",type:"address"}],name:"setVaultFactory",outputs:[],stateMutability:"nonpayable",type:"function",details:"allows all protocol components, including the call factory, to look up the vault factory.",params:{vaultFactoryContract:"the deployed vault factory"},notice:"Allows an admin to set the address of the deployed vault factory"},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC165-supportsInterface}."},"throwWhenPaused()":{inputs:[],name:"throwWhenPaused",outputs:[],stateMutability:"view",type:"function",notice:"throws an exception when the protocol is paused"},"unpause()":{inputs:[],name:"unpause",outputs:[],stateMutability:"nonpayable",type:"function",notice:"unpauses the protocol if the protocol is already paused"},"vaultContract()":{inputs:[],name:"vaultContract",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"the address of the deployed VaultFactory used by the protocol"}}},"src/HookUpgradeableBeacon.sol:HookUpgradeableBeacon":{source:"src/HookUpgradeableBeacon.sol",name:"HookUpgradeableBeacon",details:"This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their implementation contract, which is where they will delegate all function calls. An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon. Ownership is managed centrally on the Hook protocol level, where the owner is the holder of a specific permission. This permission should be used only for the purpose of upgrading the particular contract (i.e., the permissions should not be reused). This contract is deliberately simple and only has one non-view method - `upgrade`. Timelocks or other upgrade conditions will be managed by the owner of this contract. This contract is based on the UpgradeableBeaconContract from OZ and DharmaUpgradeBeaconController from Dharma",constructor:{inputs:[{internalType:"address",name:"implementation_",type:"address"},{internalType:"address",name:"hookProtocol",type:"address"},{internalType:"bytes32",name:"upgraderRole",type:"bytes32"}],stateMutability:"nonpayable",type:"constructor"},events:{"Upgraded(address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"implementation",type:"address"}],name:"Upgraded",type:"event",details:"Emitted when the implementation returned by the beacon is changed."}},methods:{"ALLOWLISTER_ROLE()":{inputs:[],name:"ALLOWLISTER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the allowlister is able to enable and disable projects to mint instruments"},"CALL_UPGRADER()":{inputs:[],name:"CALL_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the call upgrader role is able to upgrade the implementation of the covered call options"},"COLLECTION_CONF()":{inputs:[],name:"COLLECTION_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the collection configuration role allows the actor to make changes the collection configs on the protocol contract"},"MARKET_CONF()":{inputs:[],name:"MARKET_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the market configuration role allows the actor to make changes to how the market operates"},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the pauser is able to start and pause various components of the protocol"},"VAULT_UPGRADER()":{inputs:[],name:"VAULT_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the vault upgrader role is able to upgrade the implementation for all vaults"},"implementation()":{inputs:[],name:"implementation",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"Returns the current implementation address."},"upgradeTo(address)":{inputs:[{internalType:"address",name:"newImplementation",type:"address"}],name:"upgradeTo",outputs:[],stateMutability:"nonpayable",type:"function",details:"Upgrades the beacon to a new implementation. Emits an {Upgraded} event. Requirements: - msg.sender must be the owner of the contract. - `newImplementation` must be a contract."}}},"src/interfaces/IERC721FlashLoanReceiver.sol:IERC721FlashLoanReceiver":{source:"src/interfaces/IERC721FlashLoanReceiver.sol",name:"IERC721FlashLoanReceiver",title:"Flash Loan Operator Interface (ERC-721)",author:"Jake Nyquist-j@hook.xyz",details:"contracts that will utilize vaulted assets in flash loans should implement this interface in order to receive the asset. Users may want to receive the asset within a single block to claim airdrops, participate in governance, and other things with their assets. The implementer may do whatever they like with the vaulted NFT within the executeOperation method, so long as they approve the vault (passed as a param) to operate the underlying NFT. The Vault will move the asset back into the vault after executionOperation returns, and also validate that it is the owner of the asset. The flashloan receiver is able to abort a flashloan by returning false from the executeOperation method.",methods:{"executeOperation(address,uint256,address,address,bytes)":{inputs:[{internalType:"address",name:"nftContract",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"address",name:"beneficialOwner",type:"address"},{internalType:"address",name:"vault",type:"address"},{internalType:"bytes",name:"params",type:"bytes"}],name:"executeOperation",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"nonpayable",type:"function",details:"executeOperation is called immediately after the asset is transferred to this contract. After return, the asset is returned to the vault by the vault contract. The executeOperation implementation MUST approve the {vault} to operate the transferred NFT i.e. `IERC721(nftContract).setApprovalForAll(vault, true);`",params:{beneficialOwner:"the current beneficialOwner of the vault, who initialized the flashLoan",nftContract:"the address of the underlying erc-721 asset",params:"additional params passed by the caller into the flashloan",tokenId:"the address of the received erc-721 asset",vault:"the address of the vault performing the flashloan (in most cases, equal to msg.sender)"},notice:"the method that contains the operations to be performed with the loaned asset"},"onERC721Received(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"from",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"data",type:"bytes"}],name:"onERC721Received",outputs:[{internalType:"bytes4",name:"",type:"bytes4"}],stateMutability:"nonpayable",type:"function",details:"Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} by `operator` from `from`, this function is called. It must return its Solidity selector to confirm the token transfer. If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`."}}},"src/interfaces/IHookCoveredCall.sol:IHookCoveredCall":{source:"src/interfaces/IHookCoveredCall.sol",name:"IHookCoveredCall",title:"A covered call instrument",author:"Jake Nyquist-j@hook.xyz",notice:'This contract implements a "Covered Call Option". A call option gives the holder the right, but not the obligation to purchase an asset at a fixed time in the future (the expiry) for a fixed price (the strike). This call option implementation here is similar to a "european" call option because the asset can only be purchased at the expiration. The call option is "covered" because the underlying asset, must be held in escrow within a IHookVault for the entire duration of the option. There are three phases to the call option: (1) WRITING: The owner of the NFT can mint an option by calling the "mint" function using the parameters of the subject ERC-721; specifying additionally their preferred strike price and expiration. An "instrument nft" is minted to the writer\'s address, where the holder of this ERC-721 will receive the economic benefit of holding the option. (2) SALE: The sale occurs outside of the context of this contract; however, the ZeroEx market contracts are pre-approved to transfer the tokens. By Selling the instrument NFT, the writer earns a "premium" for selling their option. The option may be sold and re-sold multiple times. (3) SETTLEMENT: One day prior to the expiration, and auction begins. People are able to call bid() for more than the strike price to place a bid. If, at settlement, the high bid is greater than the strike, (b-strike) is transferred to the holder of the instrument NFT, the strike price is transferred to the writer. The high bid is transferred to the holder of the option.',events:{"Approval(address,address,uint256)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"owner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint256",name:"tokenId",type:"uint256"}],name:"Approval",type:"event"},"ApprovalForAll(address,address,bool)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"owner",type:"address"},{indexed:!0,internalType:"address",name:"operator",type:"address"},{indexed:!1,internalType:"bool",name:"approved",type:"bool"}],name:"ApprovalForAll",type:"event"},"Bid(uint256,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"uint256",name:"bidAmount",type:"uint256"},{indexed:!1,internalType:"address",name:"bidder",type:"address"}],name:"Bid",type:"event",params:{bidAmount:"the amount of wei bid",bidder:"the account placing the bid that is now the high bidder",optionId:"the option for the underlying that was bid on"},notice:"emitted when a call option settlement auction gets and accepts a new bid"},"CallCreated(address,address,uint256,uint256,uint256,uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"writer",type:"address"},{indexed:!1,internalType:"address",name:"vaultAddress",type:"address"},{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"uint256",name:"strikePrice",type:"uint256"},{indexed:!1,internalType:"uint256",name:"expiration",type:"uint256"}],name:"CallCreated",type:"event",notice:"emitted when a new call option is successfully minted with a specific underlying vault"},"CallProceedsDistributed(uint256,address,uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"uint256",name:"amount",type:"uint256"}],name:"CallProceedsDistributed",type:"event",params:{amount:"the amount of the claim distributed",optionId:"the option the claim is on",to:"the option owner making the claim"},notice:"emitted when an option owner claims their proceeds"},"CallReclaimed(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"}],name:"CallReclaimed",type:"event",notice:"emitted when a call option is reclaimed"},"CallSettled(uint256,bool)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"},{indexed:!1,internalType:"bool",name:"claimable",type:"bool"}],name:"CallSettled",type:"event",notice:"emitted when a call option is settled"},"ExpiredCallBurned(uint256)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"optionId",type:"uint256"}],name:"ExpiredCallBurned",type:"event",notice:"emitted when a expired call option is burned"},"Transfer(address,address,uint256)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"from",type:"address"},{indexed:!0,internalType:"address",name:"to",type:"address"},{indexed:!0,internalType:"uint256",name:"tokenId",type:"uint256"}],name:"Transfer",type:"event"}},methods:{"approve(address,uint256)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"approve",outputs:[],stateMutability:"nonpayable",type:"function",details:"Gives permission to `to` to transfer `tokenId` token to another account. The approval is cleared when the token is transferred. Only a single account can be approved at a time, so approving the zero address clears previous approvals. Requirements: - The caller must own the token or be an approved operator. - `tokenId` must exist. Emits an {Approval} event."},"balanceOf(address)":{inputs:[{internalType:"address",name:"owner",type:"address"}],name:"balanceOf",outputs:[{internalType:"uint256",name:"balance",type:"uint256"}],stateMutability:"view",type:"function",details:"Returns the number of tokens in ``owner``'s account."},"bid(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"bid",outputs:[],stateMutability:"payable",type:"function",params:{optionId:"the optionId corresponding to the settlement to bid on."},notice:"Bid in the settlement auction for an option. The paid amount is the bid, and the bidder is required to escrow this amount until either the auction ends or another bidder bids higher The bid must be greater than the strike price"},"burnExpiredOption(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"burnExpiredOption",outputs:[],stateMutability:"nonpayable",type:"function",params:{optionId:"of the option to burn."},notice:"Allows anyone to burn the instrument NFT for an expired option."},"claimOptionProceeds(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"claimOptionProceeds",outputs:[],stateMutability:"nonpayable",type:"function",details:"this mechanism prevents the proceeds from being sent to an account temporarily custodying the option asset.",params:{optionId:"the option to claim and burn."},notice:"allows the option owner to claim proceeds if the option was settled by another account. The option NFT is burned after settlement."},"currentBid(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"currentBid",outputs:[{internalType:"uint128",name:"",type:"uint128"}],stateMutability:"view",type:"function",params:{optionId:"of the option to check"},notice:"view function to get the current high settlement bid of an option, or 0 if there is no high bid"},"currentBidder(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"currentBidder",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{optionId:"of the option to check"},returns:{_0:"address of the account for the current high bidder, or the null address if there is none"},notice:"view function to get the current high bidder for an option settlement auction, or the null address if no high bidder exists"},"getApproved(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"getApproved",outputs:[{internalType:"address",name:"operator",type:"address"}],stateMutability:"view",type:"function",details:"Returns the account approved for `tokenId` token. Requirements: - `tokenId` must exist."},"getOptionIdForAsset(address,uint32)":{inputs:[{internalType:"address",name:"vault",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getOptionIdForAsset",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"getOptionIdForAsset",params:{assetId:"the id of the asset to check",vault:"the address of the hook vault that holds the covered asset"},returns:{_0:"the optionId, if one exists or 0 otherwise"},notice:"Looks up the latest optionId that covers a particular asset, if one exists. This option may be already settled."},"isApprovedForAll(address,address)":{inputs:[{internalType:"address",name:"owner",type:"address"},{internalType:"address",name:"operator",type:"address"}],name:"isApprovedForAll",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns if the `operator` is allowed to manage all of the assets of `owner`. See {setApprovalForAll}"},"mintWithEntitledVault(address,uint32,uint128,uint32)":{inputs:[{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint128",name:"strikePrice",type:"uint128"},{internalType:"uint32",name:"expirationTime",type:"uint32"}],name:"mintWithEntitledVault",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset within the vault",expirationTime:"time the timestamp after which the option will be expired",strikePrice:"the strike price for the call option being written",vaultAddress:"the contract address of the vault currently holding the call option"},notice:"Mints a new call option for the assets deposited in a particular vault given strike price and expiration. That vault must already have a registered entitlement for this contract with the an expiration equal to {expirationTime}"},"mintWithErc721(address,uint256,uint128,uint32)":{inputs:[{internalType:"address",name:"tokenAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"uint128",name:"strikePrice",type:"uint128"},{internalType:"uint32",name:"expirationTime",type:"uint32"}],name:"mintWithErc721",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"nonpayable",type:"function",params:{expirationTime:"time the timestamp after which the option will be expired",strikePrice:"the strike price for the call option being written",tokenAddress:"the contract address of the ERC-721 token that serves as the underlying asset for the call option",tokenId:"the tokenId of the underlying ERC-721 token"},notice:'Mints a new call option for a particular "underlying" ERC-721 NFT with a given strike price and expiration'},"mintWithVault(address,uint32,uint128,uint32,(uint8,uint8,bytes32,bytes32))":{inputs:[{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint128",name:"strikePrice",type:"uint128"},{internalType:"uint32",name:"expirationTime",type:"uint32"},{components:[{internalType:"enum Signatures.SignatureType",name:"signatureType",type:"uint8"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],internalType:"struct Signatures.Signature",name:"signature",type:"tuple"}],name:"mintWithVault",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset within the vault",expirationTime:"time the timestamp after which the option will be expired",signature:"the signature used to place the entitlement onto the vault",strikePrice:"the strike price for the call option being written",vaultAddress:"the contract address of the vault currently holding the call option"},notice:"Mints a new call option for the assets deposited in a particular vault given strike price and expiration."},"name()":{inputs:[],name:"name",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"Returns the token collection name."},"ownerOf(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"ownerOf",outputs:[{internalType:"address",name:"owner",type:"address"}],stateMutability:"view",type:"function",details:"Returns the owner of the `tokenId` token. Requirements: - `tokenId` must exist."},"reclaimAsset(uint256,bool)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"},{internalType:"bool",name:"returnNft",type:"bool"}],name:"reclaimAsset",outputs:[],stateMutability:"nonpayable",type:"function",details:"Allows the writer to reclaim a NFT if they also hold the option NFT.",params:{optionId:"the option being reclaimed.",returnNft:"true if token should be withdrawn from vault, false to leave token in the vault."},notice:"Allows the writer to reclaim an entitled asset. This is only possible when the writer holds the option nft and calls this function."},"safeTransferFrom(address,address,uint256)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"safeTransferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients are aware of the ERC721 protocol to prevent tokens from being forever locked. Requirements: - `from` cannot be the zero address. - `to` cannot be the zero address. - `tokenId` token must exist and be owned by `from`. - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. Emits a {Transfer} event."},"safeTransferFrom(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"data",type:"bytes"}],name:"safeTransferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"Safely transfers `tokenId` token from `from` to `to`. Requirements: - `from` cannot be the zero address. - `to` cannot be the zero address. - `tokenId` token must exist and be owned by `from`. - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. Emits a {Transfer} event."},"setApprovalForAll(address,bool)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"bool",name:"_approved",type:"bool"}],name:"setApprovalForAll",outputs:[],stateMutability:"nonpayable",type:"function",details:"Approve or remove `operator` as an operator for the caller. Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. Requirements: - The `operator` cannot be the caller. Emits an {ApprovalForAll} event."},"settleOption(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"settleOption",outputs:[],stateMutability:"nonpayable",type:"function",details:"the return nft param allows the underlying asset to remain in its vault. This saves gas compared to first distributing it and then re-depositing it. No royalties or other payments are subtracted from the distribution amounts.",params:{optionId:"of the option to settle."},notice:"Permissionlessly settle an expired option when the option expires in the money, distributing the proceeds to the Writer, Holder, and Bidder as follows: WRITER (who originally called mint() and owned underlying asset) - receives the `strike` HOLDER (ownerOf(optionId)) - receives `b-strike` HIGH BIDDER (call.highBidder) - becomes ownerOf NFT, pays `bid`."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."},"symbol()":{inputs:[],name:"symbol",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"Returns the token collection symbol."},"tokenURI(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"tokenURI",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"Returns the Uniform Resource Identifier (URI) for `tokenId` token."},"transferFrom(address,address,uint256)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"transferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"Transfers `tokenId` token from `from` to `to`. WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. Requirements: - `from` cannot be the zero address. - `to` cannot be the zero address. - `tokenId` token must be owned by `from`. - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. Emits a {Transfer} event."}}},"src/interfaces/IHookCoveredCallFactory.sol:IHookCoveredCallFactory":{source:"src/interfaces/IHookCoveredCallFactory.sol",name:"IHookCoveredCallFactory",title:"HookCoveredCallFactory-factory for instances of the Covered Call contract",author:"Jake Nyquist-j@hook.xyz",notice:"The Factory creates covered call instruments that support specific ERC-721 contracts, and also tracks all of the existing active markets.",events:{"CoveredCallInstrumentCreated(address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"assetAddress",type:"address"},{indexed:!1,internalType:"address",name:"instrumentAddress",type:"address"}],name:"CoveredCallInstrumentCreated",type:"event",details:"emitted whenever a new call instrument instance is created",params:{assetAddress:"the address of the asset underlying the covered call",instrumentAddress:"the address of the covered call instrument"}}},methods:{"getCallInstrument(address)":{inputs:[{internalType:"address",name:"assetAddress",type:"address"}],name:"getCallInstrument",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetAddress:"the contract address for the underlying asset"},returns:{_0:"the address of the instrument contract or the null address if one does not exist"},notice:"Lookup the call instrument contract based on the asset address"},"makeCallInstrument(address)":{inputs:[{internalType:"address",name:"assetAddress",type:"address"}],name:"makeCallInstrument",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",params:{assetAddress:"the address for the underling asset"},returns:{_0:"the address of the call option instrument contract (upgradeable)"},notice:"Create a call option instrument for a specific underlying asset address"}}},"src/interfaces/IHookERC20Vault.sol:IHookERC20Vault":{source:"src/interfaces/IHookERC20Vault.sol",name:"IHookERC20Vault",title:"Hook ERC-20 Vault interface",author:"Jake Nyquist-j@hook.xyz",details:"the IHookERC20 vault is an extension of the standard IHookVault specifically designed to hold and receive ERC20 Tokens.",events:{"Approval(address,address,uint32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint32",name:"assetId",type:"uint32"}],name:"Approval",type:"event",notice:"Emitted when `beneficialOwner` enables `approved` to manage the `assetId` asset."},"AssetReceived(address,address,address,uint32)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"address",name:"sender",type:"address"},{indexed:!1,internalType:"address",name:"contractAddress",type:"address"},{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"}],name:"AssetReceived",type:"event",notice:"emitted when an asset is added into the vault"},"AssetWithdrawn(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"AssetWithdrawn",type:"event",notice:"emitted when an asset is withdrawn from the vault"},"BeneficialOwnerSet(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!1,internalType:"address",name:"setBy",type:"address"}],name:"BeneficialOwnerSet",type:"event",notice:"emitted when the beneficial owner of an asset changes"},"EntitlementCleared(uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementCleared",type:"event",notice:"emitted when an entitlement is cleared from an asset"},"EntitlementImposed(uint32,address,uint32,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"entitledAccount",type:"address"},{indexed:!1,internalType:"uint32",name:"expiry",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementImposed",type:"event",notice:"emitted when an entitlement is placed on an asset"}},methods:{"approveOperator(address,uint32)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"approveOperator",outputs:[],stateMutability:"nonpayable",type:"function",details:"Only a single account can be approved at a time, so approving the zero address clears previous approvals. * Requirements: - The caller must be the beneficial owner - `tokenId` must exist. Emits an {Approval} event.",notice:"Gives permission to `to` to impose an entitlement upon `assetId`"},"assetAddress(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"the contract address of the vaulted asset"},notice:"the contract address of the vaulted asset"},"assetBalance(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetBalance",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",notice:"returns the balance of the underlying ERC20 token"},"clearEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"clearEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset to clear"},notice:"Allows the entitled address to release their claim on the asset"},"clearEntitlementAndDistribute(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiver",type:"address"}],name:"clearEntitlementAndDistribute",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the Id of the asset to clear",receiver:"the intended receiver of the asset"},notice:"Removes the active entitlement from a vault and returns the asset to the beneficial owner"},"entitlementExpiration(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"entitlementExpiration",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",details:"returns the 0 if no entitlement is set",returns:{_0:"the block timestamp after which the entitlement expires"},notice:"Looks up the expiration timestamp of the current entitlement"},"getApprovedOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getApprovedOperator",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"Returns the account approved for `tokenId` token. Requirements: - `assetId` must exist."},"getBeneficialOwner(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getBeneficialOwner",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"the address of the beneficial owner of the asset"},notice:"looks up the current beneficial owner of the asset"},"getCurrentEntitlementOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getCurrentEntitlementOperator",outputs:[{internalType:"bool",name:"",type:"bool"},{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the id of the underlying asset"},notice:"looks up the current operator of an entitlement on an asset"},"getHoldsAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getHoldsAsset",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"true if the asset is currently within the vault, false otherwise"},notice:"checks if the asset is currently stored in the vault"},"grantEntitlement((address,address,address,uint32,uint32))":{inputs:[{components:[{internalType:"address",name:"beneficialOwner",type:"address"},{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint32",name:"expiry",type:"uint32"}],internalType:"struct Entitlements.Entitlement",name:"entitlement",type:"tuple"}],name:"grantEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"this function call is signed by the sender per the EVM, so we know the entitlement is authentic",params:{entitlement:"The entitlement to impose onto the contract"},notice:"Allows the beneficial owner to grant an entitlement to an asset within the contract"},"imposeEntitlement(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"imposeEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset within the vault",expiry:"the duration of the entitlement",operator:"the operator to entitle",r:"sig r",s:"sig s",v:"sig v"},notice:"Add an entitlement claim to the asset held within the contract"},"setBeneficialOwner(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"newBeneficialOwner",type:"address"}],name:"setBeneficialOwner",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the subject asset to impose the entitlement",newBeneficialOwner:"the account of the person who is able to withdrawal when there are no entitlements."},notice:"setBeneficialOwner updates the current address that can claim the asset when it is free of entitlements."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."},"withdrawalAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"withdrawalAsset",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the asset to remove from the vault"},notice:"Withdrawal an unencumbered asset from this vault"}}},"src/interfaces/IHookERC721Vault.sol:IHookERC721Vault":{source:"src/interfaces/IHookERC721Vault.sol",name:"IHookERC721Vault",title:"Hook ERC-721 Vault interface",author:"Jake Nyquist-j@hook.xyz",details:"the IHookERC721 vault is an extension of the standard IHookVault specifically designed to hold and receive ERC721 Tokens. FLASH LOAN - (1) beneficial owners are able to borrow the vaulted asset for a single function call (2) to borrow the asset, they must implement and deploy a {IERC721FlashLoanReceiver} contract, and then call the flashLoan method. (3) At the end of the flashLoan, we ensure the asset is still owned by the vault.",events:{"Approval(address,address,uint32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint32",name:"assetId",type:"uint32"}],name:"Approval",type:"event",notice:"Emitted when `beneficialOwner` enables `approved` to manage the `assetId` asset."},"AssetFlashLoaned(address,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"uint256",name:"tokenId",type:"uint256"},{indexed:!1,internalType:"address",name:"flashLoanImpl",type:"address"}],name:"AssetFlashLoaned",type:"event",details:"only one asset can be flash loaned at a time, and that asset is denoted by the tokenId emitted.",notice:"emitted after an asset is flash loaned by its beneficial owner."},"AssetReceived(address,address,address,uint32)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"address",name:"sender",type:"address"},{indexed:!1,internalType:"address",name:"contractAddress",type:"address"},{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"}],name:"AssetReceived",type:"event",notice:"emitted when an asset is added into the vault"},"AssetWithdrawn(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"AssetWithdrawn",type:"event",notice:"emitted when an asset is withdrawn from the vault"},"BeneficialOwnerSet(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!1,internalType:"address",name:"setBy",type:"address"}],name:"BeneficialOwnerSet",type:"event",notice:"emitted when the beneficial owner of an asset changes"},"EntitlementCleared(uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementCleared",type:"event",notice:"emitted when an entitlement is cleared from an asset"},"EntitlementImposed(uint32,address,uint32,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"entitledAccount",type:"address"},{indexed:!1,internalType:"uint32",name:"expiry",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementImposed",type:"event",notice:"emitted when an entitlement is placed on an asset"}},methods:{"approveOperator(address,uint32)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"approveOperator",outputs:[],stateMutability:"nonpayable",type:"function",details:"Only a single account can be approved at a time, so approving the zero address clears previous approvals. * Requirements: - The caller must be the beneficial owner - `tokenId` must exist. Emits an {Approval} event.",notice:"Gives permission to `to` to impose an entitlement upon `assetId`"},"assetAddress(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"the contract address of the vaulted asset"},notice:"the contract address of the vaulted asset"},"assetTokenId(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetTokenId",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",notice:"the tokenID of the underlying ERC721 token;"},"clearEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"clearEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset to clear"},notice:"Allows the entitled address to release their claim on the asset"},"clearEntitlementAndDistribute(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiver",type:"address"}],name:"clearEntitlementAndDistribute",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the Id of the asset to clear",receiver:"the intended receiver of the asset"},notice:"Removes the active entitlement from a vault and returns the asset to the beneficial owner"},"entitlementExpiration(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"entitlementExpiration",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",details:"returns the 0 if no entitlement is set",returns:{_0:"the block timestamp after which the entitlement expires"},notice:"Looks up the expiration timestamp of the current entitlement"},"flashLoan(uint32,address,bytes)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiverAddress",type:"address"},{internalType:"bytes",name:"params",type:"bytes"}],name:"flashLoan",outputs:[],stateMutability:"nonpayable",type:"function",details:"the flashloan receiver can perform arbitrary logic, but must approve the vault as an operator before returning.",params:{params:"calldata params to forward to the receiver",receiverAddress:"the contract which implements the {IERC721FlashLoanReceiver} interface to utilize the asset while it is loaned out"},notice:"flashLoans the vaulted asset to another contract for use and return to the vault. Only the owner may perform the flashloan"},"getApprovedOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getApprovedOperator",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"Returns the account approved for `tokenId` token. Requirements: - `assetId` must exist."},"getBeneficialOwner(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getBeneficialOwner",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"the address of the beneficial owner of the asset"},notice:"looks up the current beneficial owner of the asset"},"getCurrentEntitlementOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getCurrentEntitlementOperator",outputs:[{internalType:"bool",name:"",type:"bool"},{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the id of the underlying asset"},notice:"looks up the current operator of an entitlement on an asset"},"getHoldsAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getHoldsAsset",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"true if the asset is currently within the vault, false otherwise"},notice:"checks if the asset is currently stored in the vault"},"grantEntitlement((address,address,address,uint32,uint32))":{inputs:[{components:[{internalType:"address",name:"beneficialOwner",type:"address"},{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint32",name:"expiry",type:"uint32"}],internalType:"struct Entitlements.Entitlement",name:"entitlement",type:"tuple"}],name:"grantEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"this function call is signed by the sender per the EVM, so we know the entitlement is authentic",params:{entitlement:"The entitlement to impose onto the contract"},notice:"Allows the beneficial owner to grant an entitlement to an asset within the contract"},"imposeEntitlement(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"imposeEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset within the vault",expiry:"the duration of the entitlement",operator:"the operator to entitle",r:"sig r",s:"sig s",v:"sig v"},notice:"Add an entitlement claim to the asset held within the contract"},"onERC721Received(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"from",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"data",type:"bytes"}],name:"onERC721Received",outputs:[{internalType:"bytes4",name:"",type:"bytes4"}],stateMutability:"nonpayable",type:"function",details:"Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} by `operator` from `from`, this function is called. It must return its Solidity selector to confirm the token transfer. If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`."},"setBeneficialOwner(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"newBeneficialOwner",type:"address"}],name:"setBeneficialOwner",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the subject asset to impose the entitlement",newBeneficialOwner:"the account of the person who is able to withdrawal when there are no entitlements."},notice:"setBeneficialOwner updates the current address that can claim the asset when it is free of entitlements."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."},"withdrawalAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"withdrawalAsset",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the asset to remove from the vault"},notice:"Withdrawal an unencumbered asset from this vault"}}},"src/interfaces/IHookERC721VaultFactory.sol:IHookERC721VaultFactory":{source:"src/interfaces/IHookERC721VaultFactory.sol",name:"IHookERC721VaultFactory",title:"HookERC721Factory-factory for instances of the hook vault",author:"Jake Nyquist-j@hook.xyz",notice:"The Factory creates a specific vault for ERC721s.",events:{"ERC721MultiVaultCreated(address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"nftAddress",type:"address"},{indexed:!1,internalType:"address",name:"vaultAddress",type:"address"}],name:"ERC721MultiVaultCreated",type:"event",params:{nftAddress:"the address of the nft contract that may be deposited into the new vault",vaultAddress:"address of the newly deployed vault"},notice:"emitted when a new MultiVault is deployed by the protocol"},"ERC721VaultCreated(address,uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"nftAddress",type:"address"},{indexed:!1,internalType:"uint256",name:"tokenId",type:"uint256"},{indexed:!1,internalType:"address",name:"vaultAddress",type:"address"}],name:"ERC721VaultCreated",type:"event"}},methods:{"findOrCreateVault(address,uint256)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"findOrCreateVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",params:{nftAddress:"the contract address for the ERC-721",tokenId:"the tokenId for the ERC-721"},notice:"creates a vault for a specific tokenId. If there is a multi-vault in existence which supports that address the address for that vault is returned as a new one does not need to be made."},"getMultiVault(address)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"}],name:"getMultiVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"view",type:"function",params:{nftAddress:"the contract address for the ERC-721"},returns:{_0:"the address of the {IERC721Vault} multi asset vault, or the null address if one does not exist"},notice:"gets the address of a multi-asset vault for a particular ERC-721 contract, if one exists"},"getVault(address,uint256)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"getVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"view",type:"function",params:{nftAddress:"the contract address for the ERC-721",tokenId:"the tokenId for the ERC-721"},returns:{_0:"the address of a {IERC721Vault} if one exists that supports the particular ERC-721, or the null address otherwise"},notice:"gets the address of a vault for a particular ERC-721 token"},"makeMultiVault(address)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"}],name:"makeMultiVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",params:{nftAddress:"the contract address for the ERC-721 to be supported by the vault"},returns:{_0:"the address of the newly deployed {IERC721Vault} multi asset vault"},notice:"deploy a multi-asset vault if one has not already been deployed"},"makeSoloVault(address,uint256)":{inputs:[{internalType:"address",name:"nftAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"makeSoloVault",outputs:[{internalType:"contract IHookERC721Vault",name:"",type:"address"}],stateMutability:"nonpayable",type:"function",details:"the only valid asset id in this vault is = 0",params:{nftAddress:"the address of the underlying nft contract",tokenId:"the individual token that can be deposited into this vault"},notice:"make a new vault that can contain a single asset only"}}},"src/interfaces/IHookOption.sol:IHookOption":{source:"src/interfaces/IHookOption.sol",name:"IHookOption",methods:{"getExpiration(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getExpiration",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"},"getStrikePrice(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getStrikePrice",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"}}},"src/interfaces/IHookProtocol.sol:IHookProtocol":{source:"src/interfaces/IHookProtocol.sol",name:"IHookProtocol",title:"HookProtocol configuration and access control repository",author:"Jake Nyquist-j@hook.xyz",details:"it is critically important that the particular protocol implementation is correct as, if it is not, all assets contained within protocol contracts can be easily compromised.",events:{"RoleAdminChanged(bytes32,bytes32,bytes32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"bytes32",name:"previousAdminRole",type:"bytes32"},{indexed:!0,internalType:"bytes32",name:"newAdminRole",type:"bytes32"}],name:"RoleAdminChanged",type:"event"},"RoleGranted(bytes32,address,address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"address",name:"account",type:"address"},{indexed:!0,internalType:"address",name:"sender",type:"address"}],name:"RoleGranted",type:"event"},"RoleRevoked(bytes32,address,address)":{anonymous:!1,inputs:[{indexed:!0,internalType:"bytes32",name:"role",type:"bytes32"},{indexed:!0,internalType:"address",name:"account",type:"address"},{indexed:!0,internalType:"address",name:"sender",type:"address"}],name:"RoleRevoked",type:"event"}},methods:{"coveredCallContract()":{inputs:[],name:"coveredCallContract",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"the address of the deployed CoveredCallFactory used by the protocol"},"getCollectionConfig(address,bytes32)":{inputs:[{internalType:"address",name:"collectionAddress",type:"address"},{internalType:"bytes32",name:"conf",type:"bytes32"}],name:"getCollectionConfig",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",params:{collectionAddress:"the collection for which to lookup a configuration flag",conf:"the config identifier for the configuration flag"},returns:{_0:"the true or false value of the config"},notice:"get a configuration flag with a specific key for a collection"},"getRoleAdmin(bytes32)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"}],name:"getRoleAdmin",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",details:"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getWETHAddress()":{inputs:[],name:"getWETHAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"these are values for popular chains: mainnet: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 kovan: 0xd0a1e359811322d97991e03f863a0c30c2cf029c ropsten: 0xc778417e063141139fce010982780140aa0cd5ab rinkeby: 0xc778417e063141139fce010982780140aa0cd5ab",returns:{_0:"the weth address"},notice:"the standard weth address on this chain"},"grantRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"grantRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"hasRole",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"renounceRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`."},"revokeRole(bytes32,address)":{inputs:[{internalType:"bytes32",name:"role",type:"bytes32"},{internalType:"address",name:"account",type:"address"}],name:"revokeRole",outputs:[],stateMutability:"nonpayable",type:"function",details:"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."},"throwWhenPaused()":{inputs:[],name:"throwWhenPaused",outputs:[],stateMutability:"nonpayable",type:"function",notice:"callable function that reverts when the protocol is paused"},"vaultContract()":{inputs:[],name:"vaultContract",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"the address of the deployed VaultFactory used by the protocol"}}},"src/interfaces/IHookVault.sol:IHookVault":{source:"src/interfaces/IHookVault.sol",name:"IHookVault",title:"Generic Hook Vault-a vault designed to contain a single asset to be used as escrow.",author:"Jake Nyquist-j@hook.xyz",notice:'The Vault holds an asset on behalf of the owner. The owner is able to post this asset as collateral to other protocols by signing a message, called an "entitlement", that gives a specific account the ability to change the owner. The vault can work with multiple assets via the assetId, where the asset or set of assets covered by each segment is granted an individual id. Every asset must be identified by an assetId to comply with this interface, even if the vault only contains one asset. ENTITLEMENTS - (1) only one entitlement can be placed at a time. (2) entitlements must expire, but can also be cleared by the entitled party (3) if an entitlement expires, the current beneficial owner gains immediate sole control over the asset (4) the entitled entity can modify the beneficial owner of the asset, but cannot withdrawal. (5) the beneficial owner cannot modify the beneficial owner while an entitlement is in place',events:{"Approval(address,address,uint32)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint32",name:"assetId",type:"uint32"}],name:"Approval",type:"event",notice:"Emitted when `beneficialOwner` enables `approved` to manage the `assetId` asset."},"AssetReceived(address,address,address,uint32)":{anonymous:!1,inputs:[{indexed:!1,internalType:"address",name:"owner",type:"address"},{indexed:!1,internalType:"address",name:"sender",type:"address"},{indexed:!1,internalType:"address",name:"contractAddress",type:"address"},{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"}],name:"AssetReceived",type:"event",notice:"emitted when an asset is added into the vault"},"AssetWithdrawn(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"to",type:"address"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"AssetWithdrawn",type:"event",notice:"emitted when an asset is withdrawn from the vault"},"BeneficialOwnerSet(uint32,address,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"},{indexed:!1,internalType:"address",name:"setBy",type:"address"}],name:"BeneficialOwnerSet",type:"event",details:"it is not required that this event is emitted when an entitlement is imposed that also modifies the beneficial owner.",notice:"emitted when the beneficial owner of an asset changes"},"EntitlementCleared(uint256,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint256",name:"assetId",type:"uint256"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementCleared",type:"event",notice:"emitted when an entitlement is cleared from an asset"},"EntitlementImposed(uint32,address,uint32,address)":{anonymous:!1,inputs:[{indexed:!1,internalType:"uint32",name:"assetId",type:"uint32"},{indexed:!1,internalType:"address",name:"entitledAccount",type:"address"},{indexed:!1,internalType:"uint32",name:"expiry",type:"uint32"},{indexed:!1,internalType:"address",name:"beneficialOwner",type:"address"}],name:"EntitlementImposed",type:"event",notice:"emitted when an entitlement is placed on an asset"}},methods:{"approveOperator(address,uint32)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"}],name:"approveOperator",outputs:[],stateMutability:"nonpayable",type:"function",details:"Only a single account can be approved at a time, so approving the zero address clears previous approvals. * Requirements: - The caller must be the beneficial owner - `tokenId` must exist. Emits an {Approval} event.",notice:"Gives permission to `to` to impose an entitlement upon `assetId`"},"assetAddress(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"assetAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"the contract address of the vaulted asset"},notice:"the contract address of the vaulted asset"},"clearEntitlement(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"clearEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset to clear"},notice:"Allows the entitled address to release their claim on the asset"},"clearEntitlementAndDistribute(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"receiver",type:"address"}],name:"clearEntitlementAndDistribute",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the Id of the asset to clear",receiver:"the intended receiver of the asset"},notice:"Removes the active entitlement from a vault and returns the asset to the beneficial owner"},"entitlementExpiration(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"entitlementExpiration",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",details:"returns the 0 if no entitlement is set",returns:{_0:"the block timestamp after which the entitlement expires"},notice:"Looks up the expiration timestamp of the current entitlement"},"getApprovedOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getApprovedOperator",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"Returns the account approved for `tokenId` token. Requirements: - `assetId` must exist."},"getBeneficialOwner(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getBeneficialOwner",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"the address of the beneficial owner of the asset"},notice:"looks up the current beneficial owner of the asset"},"getCurrentEntitlementOperator(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getCurrentEntitlementOperator",outputs:[{internalType:"bool",name:"",type:"bool"},{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",params:{assetId:"the id of the underlying asset"},notice:"looks up the current operator of an entitlement on an asset"},"getHoldsAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"getHoldsAsset",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",params:{assetId:"the referenced asset"},returns:{_0:"true if the asset is currently within the vault, false otherwise"},notice:"checks if the asset is currently stored in the vault"},"grantEntitlement((address,address,address,uint32,uint32))":{inputs:[{components:[{internalType:"address",name:"beneficialOwner",type:"address"},{internalType:"address",name:"operator",type:"address"},{internalType:"address",name:"vaultAddress",type:"address"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint32",name:"expiry",type:"uint32"}],internalType:"struct Entitlements.Entitlement",name:"entitlement",type:"tuple"}],name:"grantEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",details:"this function call is signed by the sender per the EVM, so we know the entitlement is authentic",params:{entitlement:"The entitlement to impose onto the contract"},notice:"Allows the beneficial owner to grant an entitlement to an asset within the contract"},"imposeEntitlement(address,uint32,uint32,uint8,bytes32,bytes32)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"uint32",name:"expiry",type:"uint32"},{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"uint8",name:"v",type:"uint8"},{internalType:"bytes32",name:"r",type:"bytes32"},{internalType:"bytes32",name:"s",type:"bytes32"}],name:"imposeEntitlement",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the asset within the vault",expiry:"the duration of the entitlement",operator:"the operator to entitle",r:"sig r",s:"sig s",v:"sig v"},notice:"Add an entitlement claim to the asset held within the contract"},"setBeneficialOwner(uint32,address)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"},{internalType:"address",name:"newBeneficialOwner",type:"address"}],name:"setBeneficialOwner",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the id of the subject asset to impose the entitlement",newBeneficialOwner:"the account of the person who is able to withdrawal when there are no entitlements."},notice:"setBeneficialOwner updates the current address that can claim the asset when it is free of entitlements."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."},"withdrawalAsset(uint32)":{inputs:[{internalType:"uint32",name:"assetId",type:"uint32"}],name:"withdrawalAsset",outputs:[],stateMutability:"nonpayable",type:"function",params:{assetId:"the asset to remove from the vault"},notice:"Withdrawal an unencumbered asset from this vault"}}},"src/interfaces/IInitializeableBeacon.sol:IInitializeableBeacon":{source:"src/interfaces/IInitializeableBeacon.sol",name:"IInitializeableBeacon",title:"Interface for a beacon with an initializer function",author:"Jake Nyquist-j@hook.xyz",details:"the Hook Beacons conform to this interface, and can be called with this initializer in order to start a beacon",methods:{"initializeBeacon(address,bytes)":{inputs:[{internalType:"address",name:"beacon",type:"address"},{internalType:"bytes",name:"data",type:"bytes"}],name:"initializeBeacon",outputs:[],stateMutability:"nonpayable",type:"function"}}},"src/interfaces/IWETH.sol:IWETH":{source:"src/interfaces/IWETH.sol",name:"IWETH",methods:{"deposit()":{inputs:[],name:"deposit",outputs:[],stateMutability:"payable",type:"function"},"transfer(address,uint256)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"value",type:"uint256"}],name:"transfer",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"nonpayable",type:"function"},"withdraw(uint256)":{inputs:[{internalType:"uint256",name:"wad",type:"uint256"}],name:"withdraw",outputs:[],stateMutability:"nonpayable",type:"function"}}},"src/interfaces/zeroex-v4/IPropertyValidator.sol:IPropertyValidator":{source:"src/interfaces/zeroex-v4/IPropertyValidator.sol",name:"IPropertyValidator",methods:{"validateProperty(address,uint256,bytes)":{inputs:[{internalType:"address",name:"tokenAddress",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"propertyData",type:"bytes"}],name:"validateProperty",outputs:[],stateMutability:"view",type:"function",details:"Checks that the given ERC721/ERC1155 asset satisfies the properties encoded in `propertyData`. Should revert if the asset does not satisfy the specified properties.",params:{propertyData:"Encoded properties or auxiliary data needed to perform the check.",tokenAddress:"The ERC721/ERC1155 token contract address.",tokenId:"The ERC721/ERC1155 tokenId of the asset to check."}}}},"src/lib/BeaconSalts.sol:BeaconSalts":{source:"src/lib/BeaconSalts.sol",name:"BeaconSalts"},"src/lib/Entitlements.sol:Entitlements":{source:"src/lib/Entitlements.sol",name:"Entitlements"},"src/lib/HookStrings.sol:HookStrings":{source:"src/lib/HookStrings.sol",name:"HookStrings"},"src/lib/PoolOrders.sol:PoolOrders":{source:"src/lib/PoolOrders.sol",name:"PoolOrders"},"src/lib/Signatures.sol:Signatures":{source:"src/lib/Signatures.sol",name:"Signatures",details:"A library for validating signatures from ZeroEx"},"src/lib/TokenURI.sol:TokenURI":{source:"src/lib/TokenURI.sol",name:"TokenURI",details:"This contract implements some ERC721 / for hook instruments.",methods:{"tokenURIERC721(uint256,address,uint256,uint256,uint256,uint256)":{inputs:[{internalType:"uint256",name:"instrumentId",type:"uint256"},{internalType:"address",name:"underlyingAddress",type:"address"},{internalType:"uint256",name:"underlyingTokenId",type:"uint256"},{internalType:"uint256",name:"instrumentExpiration",type:"uint256"},{internalType:"uint256",name:"instrumentStrike",type:"uint256"},{internalType:"uint256",name:"transfers",type:"uint256"}],name:"tokenURIERC721",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"this is a basic tokenURI based on the loot contract for an ERC721"}}},"src/lib/lyra/BlackScholes.sol:BlackScholes":{source:"src/lib/lyra/BlackScholes.sol",name:"BlackScholes",title:"BlackScholes",author:"Lyra",details:"Contract to compute the black scholes price of options. Where the unit is unspecified, it should be treated as a PRECISE_DECIMAL, which has 1e27 units of precision. The default decimal matches the ethereum standard of 1e18 units of precision.",methods:{"_stdNormalCDF(int256)":{inputs:[{internalType:"int256",name:"x",type:"int256"}],name:"_stdNormalCDF",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"pure",type:"function",details:"The standard normal cumulative distribution of the value. borrowed from a C++ implementation https://stackoverflow.com/a/23119456"},"delta((uint256,uint256,uint256,uint256,int256))":{inputs:[{components:[{internalType:"uint256",name:"timeToExpirySec",type:"uint256"},{internalType:"uint256",name:"volatilityDecimal",type:"uint256"},{internalType:"uint256",name:"spotDecimal",type:"uint256"},{internalType:"uint256",name:"strikePriceDecimal",type:"uint256"},{internalType:"int256",name:"rateDecimal",type:"int256"}],internalType:"struct BlackScholes.BlackScholesInputs",name:"bsInput",type:"tuple"}],name:"delta",outputs:[{internalType:"int256",name:"callDeltaDecimal",type:"int256"},{internalType:"int256",name:"putDeltaDecimal",type:"int256"}],stateMutability:"pure",type:"function"},"optionPrices((uint256,uint256,uint256,uint256,int256))":{inputs:[{components:[{internalType:"uint256",name:"timeToExpirySec",type:"uint256"},{internalType:"uint256",name:"volatilityDecimal",type:"uint256"},{internalType:"uint256",name:"spotDecimal",type:"uint256"},{internalType:"uint256",name:"strikePriceDecimal",type:"uint256"},{internalType:"int256",name:"rateDecimal",type:"int256"}],internalType:"struct BlackScholes.BlackScholesInputs",name:"bsInput",type:"tuple"}],name:"optionPrices",outputs:[{internalType:"uint256",name:"call",type:"uint256"},{internalType:"uint256",name:"put",type:"uint256"}],stateMutability:"pure",type:"function"},"pricesDeltaStdVega((uint256,uint256,uint256,uint256,int256))":{inputs:[{components:[{internalType:"uint256",name:"timeToExpirySec",type:"uint256"},{internalType:"uint256",name:"volatilityDecimal",type:"uint256"},{internalType:"uint256",name:"spotDecimal",type:"uint256"},{internalType:"uint256",name:"strikePriceDecimal",type:"uint256"},{internalType:"int256",name:"rateDecimal",type:"int256"}],internalType:"struct BlackScholes.BlackScholesInputs",name:"bsInput",type:"tuple"}],name:"pricesDeltaStdVega",outputs:[{components:[{internalType:"uint256",name:"callPrice",type:"uint256"},{internalType:"uint256",name:"putPrice",type:"uint256"},{internalType:"int256",name:"callDelta",type:"int256"},{internalType:"int256",name:"putDelta",type:"int256"},{internalType:"uint256",name:"vega",type:"uint256"},{internalType:"uint256",name:"stdVega",type:"uint256"}],internalType:"struct BlackScholes.PricesDeltaStdVega",name:"",type:"tuple"}],stateMutability:"pure",type:"function"},"vega((uint256,uint256,uint256,uint256,int256))":{inputs:[{components:[{internalType:"uint256",name:"timeToExpirySec",type:"uint256"},{internalType:"uint256",name:"volatilityDecimal",type:"uint256"},{internalType:"uint256",name:"spotDecimal",type:"uint256"},{internalType:"uint256",name:"strikePriceDecimal",type:"uint256"},{internalType:"int256",name:"rateDecimal",type:"int256"}],internalType:"struct BlackScholes.BlackScholesInputs",name:"bsInput",type:"tuple"}],name:"vega",outputs:[{internalType:"uint256",name:"vegaDecimal",type:"uint256"}],stateMutability:"pure",type:"function"}}},"src/lib/lyra/FixedPointMathLib.sol:FixedPointMathLib":{source:"src/lib/lyra/FixedPointMathLib.sol",name:"FixedPointMathLib"},"src/lib/lyra/Math.sol:Math":{source:"src/lib/lyra/Math.sol",name:"Math",title:"Math",author:"Lyra",details:"Library to unify logic for common shared functions"},"src/lib/synthetix/DecimalMath.sol:DecimalMath":{source:"src/lib/synthetix/DecimalMath.sol",name:"DecimalMath",title:"DecimalMath",author:"Lyra",details:"Modified synthetix SafeDecimalMath to include internal arithmetic underflow/overflow.https://docs.synthetix.io/contracts/source/libraries/SafeDecimalMath/",methods:{"PRECISE_UNIT()":{inputs:[],name:"PRECISE_UNIT",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"},"UNIT()":{inputs:[],name:"UNIT",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function"},"decimals()":{inputs:[],name:"decimals",outputs:[{internalType:"uint8",name:"",type:"uint8"}],stateMutability:"view",type:"function"},"highPrecisionDecimals()":{inputs:[],name:"highPrecisionDecimals",outputs:[{internalType:"uint8",name:"",type:"uint8"}],stateMutability:"view",type:"function"},"preciseUnit()":{inputs:[],name:"preciseUnit",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"pure",type:"function",returns:{_0:"Provides an interface to PRECISE_UNIT."}},"unit()":{inputs:[],name:"unit",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"pure",type:"function",returns:{_0:"Provides an interface to UNIT."}}}},"src/lib/synthetix/SignedDecimalMath.sol:SignedDecimalMath":{source:"src/lib/synthetix/SignedDecimalMath.sol",name:"SignedDecimalMath",title:"SignedDecimalMath",author:"Lyra",details:"Modified synthetix SafeSignedDecimalMath to include internal arithmetic underflow/overflow.https://docs.synthetix.io/contracts/source/libraries/safedecimalmath",methods:{"PRECISE_UNIT()":{inputs:[],name:"PRECISE_UNIT",outputs:[{internalType:"int256",name:"",type:"int256"}],stateMutability:"view",type:"function"},"UNIT()":{inputs:[],name:"UNIT",outputs:[{internalType:"int256",name:"",type:"int256"}],stateMutability:"view",type:"function"},"decimals()":{inputs:[],name:"decimals",outputs:[{internalType:"uint8",name:"",type:"uint8"}],stateMutability:"view",type:"function"},"highPrecisionDecimals()":{inputs:[],name:"highPrecisionDecimals",outputs:[{internalType:"uint8",name:"",type:"uint8"}],stateMutability:"view",type:"function"},"preciseUnit()":{inputs:[],name:"preciseUnit",outputs:[{internalType:"int256",name:"",type:"int256"}],stateMutability:"pure",type:"function",returns:{_0:"Provides an interface to PRECISE_UNIT."}},"unit()":{inputs:[],name:"unit",outputs:[{internalType:"int256",name:"",type:"int256"}],stateMutability:"pure",type:"function",returns:{_0:"Provides an interface to UNIT."}}}},"src/mixin/EIP712.sol:EIP712":{source:"src/mixin/EIP712.sol",name:"EIP712",details:"EIP712 helpers for features.",stateVariables:{"EIP712_DOMAIN_SEPARATOR()":{inputs:[],name:"EIP712_DOMAIN_SEPARATOR",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"stateVariable",details:"The domain hash separator for the entire call option protocol"}}},"src/mixin/HookInstrumentERC721.sol:HookInstrumentERC721":{source:"src/mixin/HookInstrumentERC721.sol",name:"HookInstrumentERC721",details:"This contract implements some ERC721 / for hook instruments.",events:{"Approval(address,address,uint256)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"owner",type:"address"},{indexed:!0,internalType:"address",name:"approved",type:"address"},{indexed:!0,internalType:"uint256",name:"tokenId",type:"uint256"}],name:"Approval",type:"event"},"ApprovalForAll(address,address,bool)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"owner",type:"address"},{indexed:!0,internalType:"address",name:"operator",type:"address"},{indexed:!1,internalType:"bool",name:"approved",type:"bool"}],name:"ApprovalForAll",type:"event"},"Transfer(address,address,uint256)":{anonymous:!1,inputs:[{indexed:!0,internalType:"address",name:"from",type:"address"},{indexed:!0,internalType:"address",name:"to",type:"address"},{indexed:!0,internalType:"uint256",name:"tokenId",type:"uint256"}],name:"Transfer",type:"event"}},stateVariables:{"_preApprovedMarketplace()":{inputs:[],name:"_preApprovedMarketplace",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"stateVariable",details:"the contact address for a marketplace to pre-approve"}},methods:{"approve(address,uint256)":{inputs:[{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"approve",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-approve}."},"balanceOf(address)":{inputs:[{internalType:"address",name:"owner",type:"address"}],name:"balanceOf",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"See {IERC721-balanceOf}."},"burn(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"burn",outputs:[],stateMutability:"nonpayable",type:"function",details:"Burns `tokenId`. See {ERC721-_burn}. Requirements: - The caller must own `tokenId` or be an approved operator."},"contractUri(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"contractUri",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"this is the OpenSea compatible collection - level metadata URI."},"getApproved(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"getApproved",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IERC721-getApproved}."},"getAssetId(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getAssetId",outputs:[{internalType:"uint32",name:"",type:"uint32"}],stateMutability:"view",type:"function",notice:"getter for the assetId of the underlying asset within a vault"},"getExpiration(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getExpiration",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",notice:"getter for the options expiration. After this time the option is invalid"},"getStrikePrice(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getStrikePrice",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",notice:"getter for the option strike price"},"getTransferCount(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getTransferCount",outputs:[{internalType:"uint256",name:"",type:"uint256"}],stateMutability:"view",type:"function",details:"this count can be used by overbooks to invalidate orders after a token has been transferred, preventing stale order execution by malicious parties",notice:"the number of times the token has been transferred"},"getVaultAddress(uint256)":{inputs:[{internalType:"uint256",name:"optionId",type:"uint256"}],name:"getVaultAddress",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",notice:"getter for the address holding the underlying asset"},"isApprovedForAll(address,address)":{inputs:[{internalType:"address",name:"owner",type:"address"},{internalType:"address",name:"operator",type:"address"}],name:"isApprovedForAll",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC721-isApprovedForAll}. this extension ensures that any operator contract located at {_approvedMarketpace} is considered approved internally in the ERC721 contract"},"name()":{inputs:[],name:"name",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"See {IERC721Metadata-name}."},"ownerOf(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"ownerOf",outputs:[{internalType:"address",name:"",type:"address"}],stateMutability:"view",type:"function",details:"See {IERC721-ownerOf}."},"safeTransferFrom(address,address,uint256)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"safeTransferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-safeTransferFrom}."},"safeTransferFrom(address,address,uint256,bytes)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"},{internalType:"bytes",name:"_data",type:"bytes"}],name:"safeTransferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-safeTransferFrom}."},"setApprovalForAll(address,bool)":{inputs:[{internalType:"address",name:"operator",type:"address"},{internalType:"bool",name:"approved",type:"bool"}],name:"setApprovalForAll",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-setApprovalForAll}."},"supportsInterface(bytes4)":{inputs:[{internalType:"bytes4",name:"interfaceId",type:"bytes4"}],name:"supportsInterface",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"view",type:"function",details:"See {IERC165-supportsInterface}."},"symbol()":{inputs:[],name:"symbol",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"See {IERC721Metadata-symbol}."},"tokenURI(uint256)":{inputs:[{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"tokenURI",outputs:[{internalType:"string",name:"",type:"string"}],stateMutability:"view",type:"function",details:"See {IERC721-tokenURI}."},"transferFrom(address,address,uint256)":{inputs:[{internalType:"address",name:"from",type:"address"},{internalType:"address",name:"to",type:"address"},{internalType:"uint256",name:"tokenId",type:"uint256"}],name:"transferFrom",outputs:[],stateMutability:"nonpayable",type:"function",details:"See {IERC721-transferFrom}."}}},"src/mixin/PermissionConstants.sol:PermissionConstants":{source:"src/mixin/PermissionConstants.sol",name:"PermissionConstants",details:"new roles here should be initialized in the constructor of the protocol",notice:"roles on the hook protocol that can be read by other contract",methods:{"ALLOWLISTER_ROLE()":{inputs:[],name:"ALLOWLISTER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the allowlister is able to enable and disable projects to mint instruments"},"CALL_UPGRADER()":{inputs:[],name:"CALL_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the call upgrader role is able to upgrade the implementation of the covered call options"},"COLLECTION_CONF()":{inputs:[],name:"COLLECTION_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the collection configuration role allows the actor to make changes the collection configs on the protocol contract"},"MARKET_CONF()":{inputs:[],name:"MARKET_CONF",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the market configuration role allows the actor to make changes to how the market operates"},"PAUSER_ROLE()":{inputs:[],name:"PAUSER_ROLE",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the pauser is able to start and pause various components of the protocol"},"VAULT_UPGRADER()":{inputs:[],name:"VAULT_UPGRADER",outputs:[{internalType:"bytes32",name:"",type:"bytes32"}],stateMutability:"view",type:"function",notice:"the vault upgrader role is able to upgrade the implementation for all vaults"}}}};new wo({el:"#app",router:new pu({routes:[{path:"/",component:Vu,props:()=>({json:Hu})},{path:"*",component:Su,props:e=>({json:Hu[e.path.slice(1)]})}]}),mounted(){document.dispatchEvent(new Event("render-event"))},render:e=>e(mu)})})()})(); \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index d927b53..4e3be9a 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,4 +1,4 @@ -[default] +[profile.default] src = 'src' out = 'out' libs = ['lib'] diff --git a/integration/helpers/index.ts b/integration/helpers/index.ts index a9b71e3..ce3ec68 100644 --- a/integration/helpers/index.ts +++ b/integration/helpers/index.ts @@ -13,6 +13,39 @@ export interface Entitlement { expiry: string; } +export enum OrderDirection { + BUY = 0, + SELL = 1, +} + +export enum OptionType { + CALL = 0, + PUT = 1, +} + +export interface VolOrderNFTProperties { + propertyValidator: string; + propertyData: string; +} + +export interface VolOrder { + direction: OrderDirection; + maker: string; + orderExpiry: string; + nonce: string; + size: string; + optionType: OptionType; + maxStrikePriceMultiple: string; + minOptionDuration: string; + maxOptionDuration: string; + maxPriceSignalAge: string; + nftProperties: VolOrderNFTProperties[]; + optionMarketAddress: string; + impliedVolBips: string; + skewDecimal: string; + riskFreeRateBips: string; +} + const signTypedData = async ( domain: TypedDataDomain, types: Record, @@ -33,6 +66,47 @@ const signTypedData = async ( return signature; }; +export function genVolOrderTypedData( + order: VolOrder, + verifyingContract: string +) { + return { + // All properties on a domain are optional + domain: { + name: "Hook", + version: "1.0.0", + chainId: 1337, // pulled from hardhat.config.ts + verifyingContract, // Hook Protocol + }, + // The named list of all type definitions + types: { + Property: [ + { name: "propertyValidator", type: "address" }, + { name: "propertyData", type: "bytes" }, + ], + Order: [ + { name: "direction", type: "uint8" }, + { name: "maker", type: "address" }, + { name: "orderExpiry", type: "uint256" }, + { name: "nonce", type: "uint256" }, + { name: "size", type: "uint8" }, + { name: "optionType", type: "uint8" }, + { name: "maxStrikePriceMultiple", type: "uint256" }, + { name: "minOptionDuration", type: "uint64" }, + { name: "maxOptionDuration", type: "uint64" }, + { name: "maxPriceSignalAge", type: "uint64" }, + { name: "nftProperties", type: "Property[]" }, + { name: "optionMarketAddress", type: "address" }, + { name: "impliedVolBips", type: "uint64" }, + { name: "skewDecimal", type: "uint64" }, + { name: "riskFreeRateBips", type: "uint64" }, + ], + }, + // The data to sign + value: order, + }; +} + function genEntitlementTypedData( entitlement: Entitlement, verifyingContract: string @@ -91,3 +165,19 @@ export async function signEntitlement( return signature; } + +export async function signVolOrder( + order: VolOrder, + signer: SignerWithAddress, + hookProtocol: string // Hook Protocol +) { + const { domain, types, value } = genVolOrderTypedData(order, hookProtocol); + const signature = await signTypedData( + domain, + types, + value, + signer, + order.maker + ); + return signature; +} diff --git a/integration/integration.test.ts b/integration/integration.test.ts index 573bf14..23e2a78 100644 --- a/integration/integration.test.ts +++ b/integration/integration.test.ts @@ -4,8 +4,14 @@ import { BigNumber, Contract } from "ethers"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { solidity } from "ethereum-waffle"; -import { signEntitlement } from "./helpers"; -import { getAddress } from "ethers/lib/utils"; +import { + OptionType, + OrderDirection, + genVolOrderTypedData, + signEntitlement, + signVolOrder, +} from "./helpers"; +import { _TypedDataEncoder, getAddress } from "ethers/lib/utils"; use(solidity); @@ -135,7 +141,9 @@ describe("UpgradeableBeacon", function () { ).to.be.false; await expect( beacon.connect(actor).upgradeTo(impl2.address) - ).to.be.revertedWith("HookUpgradeableBeacon: caller does not have the required upgrade permissions"); + ).to.be.revertedWith( + "HookUpgradeableBeacon: caller does not have the required upgrade permissions" + ); expect(await beacon.implementation()).to.eq(impl1.address); }); @@ -155,7 +163,9 @@ describe("UpgradeableBeacon", function () { const [, actor] = await ethers.getSigners(); await expect( beacon.connect(admin).upgradeTo(actor.address) - ).to.be.revertedWith("HookUpgradeableBeacon: implementation is not a contract"); + ).to.be.revertedWith( + "HookUpgradeableBeacon: implementation is not a contract" + ); }); }); @@ -3351,3 +3361,503 @@ describe("Call Instrument Tests", function () { }); }); }); + +describe("VolBidPool", function () { + // Constants + const SECS_IN_A_DAY = 60 * 60 * 24; + + // Contracts + let vaultFactory: Contract, + protocol: Contract, + token: Contract, + calls: Contract, + bidPool: Contract, + weth: Contract; + + // Signers + let admin: SignerWithAddress, + writer: SignerWithAddress, + operator: SignerWithAddress, + buyer: SignerWithAddress, + firstBidder: SignerWithAddress, + secondBidder: SignerWithAddress; + + beforeEach(async function () { + // Create signers + [admin, writer, operator, buyer, firstBidder, secondBidder] = + await ethers.getSigners(); + + // Deploy weth + const wethFactory = await ethers.getContractFactory("WETH"); + weth = await wethFactory.deploy(); + + // Deploy test NFT + const testNftFactory = await ethers.getContractFactory("TestERC721"); + token = await testNftFactory.deploy(); + + // // Deploy protocol + const protocolFactory = await ethers.getContractFactory("HookProtocol"); + protocol = await protocolFactory.deploy( + admin.address, + admin.address, + admin.address, + admin.address, + admin.address, + admin.address, + weth.address + ); + + // Deploy multi vault + const vaultFactoryFactory = await ethers.getContractFactory( + "HookERC721VaultFactory" + ); + const vaultImplFactory = await ethers.getContractFactory( + "HookERC721VaultImplV1" + ); + const vaultBeaconFactory = await ethers.getContractFactory( + "HookUpgradeableBeacon" + ); + const multiVaultImplFactory = await ethers.getContractFactory( + "HookERC721MultiVaultImplV1" + ); + const multiVaultBeaconFactory = await ethers.getContractFactory( + "HookUpgradeableBeacon" + ); + + const vaultImpl = await vaultImplFactory.deploy(); + const multiVaultImpl = await multiVaultImplFactory.deploy(); + + const vaultBeacon = await vaultBeaconFactory.deploy( + vaultImpl.address, + protocol.address, + ethers.utils.id("VAULT_UPGRADER") + ); + + const multiVaultBeacon = await multiVaultBeaconFactory.deploy( + multiVaultImpl.address, + protocol.address, + ethers.utils.id("VAULT_UPGRADER") + ); + + vaultFactory = await vaultFactoryFactory.deploy( + protocol.address, + vaultBeacon.address, + multiVaultBeacon.address + ); + + protocol.setVaultFactory(vaultFactory.address); + + // Deploy call instrument + const callFactoryFactory = await ethers.getContractFactory( + "HookCoveredCallFactory" + ); + const tokenURILib = await ethers.getContractFactory("TokenURI"); + const tokenURI = await tokenURILib.deploy(); + const callImplFactory = await ethers.getContractFactory( + "HookCoveredCallImplV1", + { libraries: { TokenURI: tokenURI.address } } + ); + const callBeaconFactory = await ethers.getContractFactory( + "HookUpgradeableBeacon" + ); + + const blackScholesLib = await ethers.getContractFactory("BlackScholes"); + const blackScholes = await blackScholesLib.deploy(); + const bidPoolFactory = await ethers.getContractFactory("HookBidPool", { + libraries: { BlackScholes: blackScholes.address }, + }); + + const callImpl = await callImplFactory.deploy(); + const callBeacon = await callBeaconFactory.deploy( + callImpl.address, + protocol.address, + ethers.utils.id("VAULT_UPGRADER") + ); + const callFactory = await callFactoryFactory.deploy( + protocol.address, + callBeacon.address, + callBeacon.address // use this address for pre-approved marketplace to ensure its a contract + ); + + protocol.setCoveredCallFactory(callFactory.address); + + // Create another call instrument contract instance + await callFactory.makeCallInstrument(token.address); + const callInstrumentAddress = await callFactory.getCallInstrument( + token.address + ); + + // Attach to existing address + calls = await ethers.getContractAt( + "HookCoveredCallImplV1", + callInstrumentAddress + ); + + // Mint 2 tokens + await token.connect(writer).mint(writer.address, 0); + await token.connect(writer).mint(writer.address, 1); + await token.connect(writer).mint(writer.address, 2); + + // Set approval for call instrument + await token.connect(writer).setApprovalForAll(calls.address, true); + + bidPool = await bidPoolFactory.deploy( + weth.address, + admin.address, + admin.address, + admin.address, + 100, + admin.address, + protocol.address + ); + + bidPool.setPoolPaused(false); + }); + + describe("orderFill", async function () { + it("should be valid", async function () { + const blockNumber = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNumber); + const blockTimestamp = block.timestamp; + const expiration = Math.floor(blockTimestamp + SECS_IN_A_DAY * 5); + + // Mint call option + const createCall = await calls + .connect(writer) + .mintWithErc721(token.address, 0, 1000, expiration); + const cc = await createCall.wait(); + + const callCreatedEvent = cc.events.find( + (event: any) => event?.event === "CallCreated" + ); + + const optionTokenId = callCreatedEvent.args.optionId; + + const volOrder = { + direction: OrderDirection.BUY, + maker: buyer.address, + orderExpiry: Math.floor(blockTimestamp + 40).toString(), + nonce: "1405", + size: "1", + optionType: OptionType.CALL, + maxStrikePriceMultiple: "0", + minOptionDuration: (SECS_IN_A_DAY * 0.5).toString(), + maxOptionDuration: (SECS_IN_A_DAY * 80).toString(), + maxPriceSignalAge: "0", + optionMarketAddress: calls.address, + impliedVolBips: "5000", + nftProperties: [], + skewDecimal: "0", + riskFreeRateBips: "500", + }; + + const signedOrder = await signVolOrder(volOrder, buyer, protocol.address); + + const { types, domain, value } = genVolOrderTypedData( + volOrder, + protocol.address + ); + + const orderHash = _TypedDataEncoder.hash(domain, types, value); + + const orderValiditySignature = await admin.signMessage( + ethers.utils.arrayify( + ethers.utils.solidityKeccak256( + ["bytes32", "uint256"], + [orderHash, expiration] + ) + ) + ); + + const { v, r, s } = ethers.utils.splitSignature(orderValiditySignature); + + const orderValidityClaim = { + orderHash: orderHash, + goodTilTimestamp: expiration, + v, + r, + s, + }; + + const { + v: v2, + r: r2, + s: s2, + } = ethers.utils.splitSignature( + await admin.signMessage( + ethers.utils.arrayify( + ethers.utils.solidityKeccak256( + ["uint256", "uint256", "uint256"], + ["900", Math.floor(blockTimestamp - 10).toString(), expiration] + ) + ) + ) + ); + + const assetPriceClaim = { + assetPriceInWei: "900", + priceObservedTimestamp: Math.floor(blockTimestamp - 10).toString(), + goodTilTimestamp: expiration, + v: v2, + r: r2, + s: s2, + }; + + calls.connect(writer).setApprovalForAll(bidPool.address, true); + weth.connect(buyer).deposit({ value: 1000 }); + weth.connect(buyer).approve(bidPool.address, 1000); + bidPool + .connect(writer) + .sellOption( + volOrder, + signedOrder, + assetPriceClaim, + orderValidityClaim, + BigNumber.from("14"), + calls.address, + BigNumber.from(optionTokenId) + ); + }); + + it("works with property-validator encoded orders", async function () { + const blockNumber = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNumber); + const blockTimestamp = block.timestamp; + const expiration = Math.floor(blockTimestamp + SECS_IN_A_DAY * 5); + + // Mint call option + const createCall = await calls + .connect(writer) + .mintWithErc721(token.address, 0, 1000, expiration); + const cc = await createCall.wait(); + + const callCreatedEvent = cc.events.find( + (event: any) => event?.event === "CallCreated" + ); + + const optionTokenId = callCreatedEvent.args.optionId; + + const validatorFactory = await ethers.getContractFactory( + "PropertyValidator1" + ); + + const validator = await validatorFactory.deploy(); + + const volOrder = { + direction: OrderDirection.BUY, + maker: buyer.address, + orderExpiry: Math.floor(blockTimestamp + 40).toString(), + nonce: "1405", + size: "1", + optionType: OptionType.CALL, + maxStrikePriceMultiple: "0", + minOptionDuration: (SECS_IN_A_DAY * 0.5).toString(), + maxOptionDuration: (SECS_IN_A_DAY * 80).toString(), + maxPriceSignalAge: "0", + optionMarketAddress: calls.address, + impliedVolBips: "5000", + nftProperties: [ + { + propertyValidator: validator.address, + propertyData: ethers.utils.defaultAbiCoder.encode( + [ + "uint256", + "uint8", + "uint256", + "uint8", + "bool", + "uint256", + "uint256", + ], + [0, 0, 0, 0, false, 0, 0] + ), + }, + ], + skewDecimal: "0", + riskFreeRateBips: "500", + }; + + const signedOrder = await signVolOrder(volOrder, buyer, protocol.address); + + const { types, domain, value } = genVolOrderTypedData( + volOrder, + protocol.address + ); + + const orderHash = _TypedDataEncoder.hash(domain, types, value); + + const orderValiditySignature = await admin.signMessage( + ethers.utils.arrayify( + ethers.utils.solidityKeccak256( + ["bytes32", "uint256"], + [orderHash, expiration] + ) + ) + ); + + const { v, r, s } = ethers.utils.splitSignature(orderValiditySignature); + + const orderValidityClaim = { + orderHash: orderHash, + goodTilTimestamp: expiration, + v, + r, + s, + }; + + const { + v: v2, + r: r2, + s: s2, + } = ethers.utils.splitSignature( + await admin.signMessage( + ethers.utils.arrayify( + ethers.utils.solidityKeccak256( + ["uint256", "uint256", "uint256"], + ["900", Math.floor(blockTimestamp - 10).toString(), expiration] + ) + ) + ) + ); + + const assetPriceClaim = { + assetPriceInWei: "900", + priceObservedTimestamp: Math.floor(blockTimestamp - 10).toString(), + goodTilTimestamp: expiration, + v: v2, + r: r2, + s: s2, + }; + + calls.connect(writer).setApprovalForAll(bidPool.address, true); + weth.connect(buyer).deposit({ value: 1000 }); + weth.connect(buyer).approve(bidPool.address, 1000); + bidPool + .connect(writer) + .sellOption( + volOrder, + signedOrder, + assetPriceClaim, + orderValidityClaim, + BigNumber.from("14"), + calls.address, + BigNumber.from(optionTokenId) + ); + }); + + it("works with property-validator empty validator", async function () { + const blockNumber = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNumber); + const blockTimestamp = block.timestamp; + const expiration = Math.floor(blockTimestamp + SECS_IN_A_DAY * 5); + + // Mint call option + const createCall = await calls + .connect(writer) + .mintWithErc721(token.address, 0, 1000, expiration); + const cc = await createCall.wait(); + + const callCreatedEvent = cc.events.find( + (event: any) => event?.event === "CallCreated" + ); + + const optionTokenId = callCreatedEvent.args.optionId; + + const validatorFactory = await ethers.getContractFactory( + "PropertyValidator1" + ); + + const validator = await validatorFactory.deploy(); + + const volOrder = { + direction: OrderDirection.BUY, + maker: buyer.address, + orderExpiry: Math.floor(blockTimestamp + 40).toString(), + nonce: "1405", + size: "1", + optionType: OptionType.CALL, + maxStrikePriceMultiple: "0", + minOptionDuration: (SECS_IN_A_DAY * 0.5).toString(), + maxOptionDuration: (SECS_IN_A_DAY * 80).toString(), + maxPriceSignalAge: "0", + optionMarketAddress: calls.address, + impliedVolBips: "5000", + nftProperties: [ + { + propertyValidator: "0x0000000000000000000000000000000000000000", + propertyData: [], + }, + ], + skewDecimal: "0", + riskFreeRateBips: "500", + }; + + const signedOrder = await signVolOrder(volOrder, buyer, protocol.address); + + const { types, domain, value } = genVolOrderTypedData( + volOrder, + protocol.address + ); + + const orderHash = _TypedDataEncoder.hash(domain, types, value); + + const orderValiditySignature = await admin.signMessage( + ethers.utils.arrayify( + ethers.utils.solidityKeccak256( + ["bytes32", "uint256"], + [orderHash, expiration] + ) + ) + ); + + const { v, r, s } = ethers.utils.splitSignature(orderValiditySignature); + + const orderValidityClaim = { + orderHash: orderHash, + goodTilTimestamp: expiration, + v, + r, + s, + }; + + const { + v: v2, + r: r2, + s: s2, + } = ethers.utils.splitSignature( + await admin.signMessage( + ethers.utils.arrayify( + ethers.utils.solidityKeccak256( + ["uint256", "uint256", "uint256"], + ["900", Math.floor(blockTimestamp - 10).toString(), expiration] + ) + ) + ) + ); + + const assetPriceClaim = { + assetPriceInWei: "900", + priceObservedTimestamp: Math.floor(blockTimestamp - 10).toString(), + goodTilTimestamp: expiration, + v: v2, + r: r2, + s: s2, + }; + + calls.connect(writer).setApprovalForAll(bidPool.address, true); + weth.connect(buyer).deposit({ value: 1000 }); + weth.connect(buyer).approve(bidPool.address, 1000); + bidPool + .connect(writer) + .sellOption( + volOrder, + signedOrder, + assetPriceClaim, + orderValidityClaim, + BigNumber.from("14"), + calls.address, + BigNumber.from(optionTokenId) + ); + }); + }); +}); diff --git a/src/HookBidPool.sol b/src/HookBidPool.sol new file mode 100644 index 0000000..6078363 --- /dev/null +++ b/src/HookBidPool.sol @@ -0,0 +1,580 @@ +// SPDX-License-Identifier: MIT +// +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// ██████████████ ██████████████ +// ██████████████ ▄▄████████████████▄▄ ▐█████████████▌ +// ██████████████ ▄█████████████████████████████▄ ██████████████ +// ██████████▀ ▄█████████████████████████████████ ██████████████▌ +// ██████▀ ▄██████████████████████████████████▀ ▄███████████████ +// ███▀ ██████████████████████████████████▀ ▄████████████████ +// ▀▀ ████████████████████████████████▀▀ ▄█████████████████▌ +// █████████████████████▀▀▀▀▀▀▀ ▄▄███████████████████▀ +// ██████████████████▀ ▄▄▄█████████████████████████████▀ +// ████████████████▀ ▄█████████████████████████████████▀ ██▄ +// ▐███████████████▀ ▄██████████████████████████████████▀ █████▄ +// ██████████████▀ ▄█████████████████████████████████▀ ▄████████ +// ██████████████▀ ███████████████████████████████▀ ▄████████████ +// ▐█████████████▌ ▀▀▀▀████████████████████▀▀▀▀ █████████████▌ +// ██████████████ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ + +pragma solidity ^0.8.10; + +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import "@openzeppelin/contracts/access/AccessControl.sol"; + +import "./lib/PoolOrders.sol"; +import "./lib/Signatures.sol"; +import "./lib/lyra/BlackScholes.sol"; + +import "./mixin/EIP712.sol"; + +import "./interfaces/IHookProtocol.sol"; +import "./interfaces/IHookOption.sol"; + +import "./interfaces/delegate-cash/IDelegationRegistry.sol"; + +/// @notice HookBidPools allows users to make off-chain orders in terms of an implied volatility which +/// can later be filled by an option seller. The price of the sell will be computed using the Black-Scholes +/// model at bid time. +/// @title HookBidPool +/// @author Jake Nyquist-j@hook.xyz +/// @dev This contract is directly interacted with by users, and holds approvals for ERC-20 tokens. +/// +/// In order for an order to be filled, it must be signed by the maker and the maker must have enough balance +/// to provide the order proceeds and relevant fees. The maximum bid the order maker has offered is computed +/// using the volatility and risk-free rate signed into the order. This information is combined with the NFT +/// floor price provided by the off-chain oracle to compute the maximum bid price. +/// If the amount of consideration requested by the seller + the protocol fees is less than the maximum bid, +/// the order can then be filled. The seller will receive their requested proceeds, the protocol will receive +/// their fees, and the buyer receives their option nft. +/// +/// The order must also be signed by the off-chain order validity oracle. This oracle is responsible for allowing +/// the user to make gasless cancellations which take effect as soon as the last outstanding order validity signature +/// expires. Alternatively, the user can make a calculation directly on the contract with their order hash to immediately +/// cancel their order. +contract HookBidPool is EIP712, ReentrancyGuard, AccessControl { + // use the SafeERC20 library to safely interact with ERC-20 tokens + using SafeERC20 for IERC20; + + /// @notice The asset price claim is a signed struct used to verify the price of + /// an underlying asset. + struct AssetPriceClaim { + /// @notice All prices are denominated in ETH or ETH-equivalent tokens + uint256 assetPriceInWei; + /// @notice The timestamp when this price point was computed or observed (in seconds) + uint256 priceObservedTimestamp; + /// @notice the last timestamp where this claim is still valid + uint256 goodTilTimestamp; + uint8 v; + bytes32 r; + bytes32 s; + } + + /// @notice Ensure that the order was not canceled as of some off-chain verified lookback + /// time or mechanism. + struct OrderValidityOracleClaim { + /// @notice the eip712 hash of the corder + bytes32 orderHash; + /// @notice the timestamp of the last block (inclusive) where this claim is considered valid + uint256 goodTilTimestamp; + uint8 v; + bytes32 r; + bytes32 s; + } + + /// @notice event emitted when the paused state of the contract changes\ + /// + /// @param newState the new paused state of the contract + event PauseUpdated(bool newState); + + /// @notice event emitted when the fee take rate is updated + /// + /// @param feeBips the new fee take rate in bips + event FeesUpdated(uint64 feeBips); + + /// @notice event emitted when the oracle address is updated + /// + /// @param oracle the new oracle address + event PriceOracleSignerUpdated(address oracle); + + /// @notice event emitted when the protocol fee recipient is updated + /// + /// @param recipient the new protocol fee recipient + event ProtocolFeeRecipientUpdated(address recipient); + + /// @notice event emitted when the order validity oracle is updated + /// + /// @param oracle the new order validity oracle + event OrderValidityOracleSignerUpdated(address oracle); + + /// @notice event emitted when the protocol address is updated + /// + /// @param protocol the new protocol address + event ProtocolAddressSet(address protocol); + + /// @notice event emitted when an option is sold + /// + /// @param maker the signer who made the order initially + /// @param taker the caller who filled the order + /// @param orderHash the eip-712 hash of the order + /// @param proceeds the proceeds the seller receives + /// @param fees the fees the buyer paid, in addition to the proceeds to the sellers + /// @param optionContract the contract address of the Hook option instrument + /// @param optionId the id of the option within the optionContract + event OrderFilled( + address maker, + address taker, + bytes32 orderHash, + uint256 proceeds, + uint256 fees, + address optionContract, + uint256 optionId + ); + + /// @notice event emitted when an order is canceled + /// + /// @param maker the signer who made the order initially + /// @param orderHash the eip-712 hash of the order + event OrderCancelled(address maker, bytes32 orderHash); + + /// LOCAL VARIABLES /// + + /// @notice the address of the WETH contract on the deployed network + address immutable weth; + + /// @notice the address of the HookProtocol contract + IHookProtocol protocol; + + /// @notice the address of the price oracle signer + address priceOracleSigner; + + /// @notice the address of the order validity oracle signer + address orderValidityOracleSigner; + + /// @notice the fee in basis points (1/100th of a percent) that the seller pays to the protocol + /// this fee is assessed at order fill time using the current value, which could be different + /// from the time that the order was made + uint64 feeBips; + address feeRecipient; + bool paused; + mapping(bytes32 => uint256) orderFills; + mapping(bytes32 => bool) orderCancellations; + + /// CONSTANTS /// + + // 1% = 0.01, 100 bips = 1%, 10000 bps = 100% == 1 + uint256 constant BPS_TO_DECIMAL = 10e14; + + /// https://github.com/delegatecash/delegation-registry + IDelegationRegistry constant DELEGATE_CASH_REGISTRY = + IDelegationRegistry(0x00000000000076A84feF008CDAbe6409d2FE638B); + + /// ROLE CONSTANTS /// + + /// @notice the role that can pause the contract - should be held by a mulitsig + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + /// @notice the role that can update the protocol address - should be held by a multisig + bytes32 public constant PROTOCOL_ROLE = keccak256("PROTOCOL_ROLE"); + + /// @notice the role that can update the fee amount and recipient, should be held by a timelock + bytes32 public constant FEES_ROLE = keccak256("FEES_ROLE"); + + /// @notice the role that can update the price oracle signer, should be held by a timelock + /// If an oracle is compromised, the pool should be paused immediately, a new oracle nominated via + /// the timelock, and the pool unpaused after the timelock delay has passed. + bytes32 public constant ORACLE_ROLE = keccak256("ORACLE_ROLE"); + + /// CONSTRUCTOR /// + + /// @param _weth the address of the WETH contract + /// @param _priceOracleSigner the public key for the price oracle signer + /// @param _initialAdmin the initial holder of roles on the contract + /// @param _orderValidityOracleSigner the public key for the order validity oracle signer + /// @param _feeBips the initial fee in basis points (1/100th of a percent) that the seller pays to the protocol + /// @param _feeRecipient the initial address that receives the protocol fees + /// @param _protocol the address of the HookProtocol contract + constructor( + address _weth, + address _initialAdmin, + address _priceOracleSigner, + address _orderValidityOracleSigner, + uint64 _feeBips, + address _feeRecipient, + address _protocol + ) { + weth = _weth; + priceOracleSigner = _priceOracleSigner; + orderValidityOracleSigner = _orderValidityOracleSigner; + feeBips = _feeBips; + feeRecipient = _feeRecipient; + protocol = IHookProtocol(_protocol); + setAddressForEipDomain(_protocol); + + /// set the contract to be initially paused after deploy. + /// it should not be unpaused until the relevant roles have been + /// already assigned to separate wallets + paused = true; + + /// SETUP THE ROLES, AND GRANT THEM TO THE INITIAL ADMIN + /// the holders of these roles should be modified + /// The role admin is also set to the role itself, such that + /// the deployer cannot unilaterally reassign the roles. + _grantRole(ORACLE_ROLE, _initialAdmin); + _setRoleAdmin(ORACLE_ROLE, ORACLE_ROLE); + _grantRole(PAUSER_ROLE, _initialAdmin); + _setRoleAdmin(PAUSER_ROLE, PAUSER_ROLE); + _grantRole(PROTOCOL_ROLE, _initialAdmin); + _setRoleAdmin(PROTOCOL_ROLE, PROTOCOL_ROLE); + _grantRole(FEES_ROLE, _initialAdmin); + _setRoleAdmin(FEES_ROLE, FEES_ROLE); + + /// emit events to make it easier for off chain indexers to + /// track contract state from inception + emit PauseUpdated(paused); + emit FeesUpdated(_feeBips); + emit ProtocolAddressSet(_protocol); + emit ProtocolFeeRecipientUpdated(_feeRecipient); + emit PriceOracleSignerUpdated(_priceOracleSigner); + emit OrderValidityOracleSignerUpdated(_orderValidityOracleSigner); + } + + /// PUBLIC/EXTERNAL FUNCTIONS /// + + /// @notice sells a european call option to a bidder + /// + /// @param order the order struct from the off-chain orderbook + /// @param orderSignature the signature of the order struct signed by the maker + /// @param assetPrice the price of the underlying asset, signed off-chain by the oracle + /// @param orderValidityOracleClaim the claim that the order is still valid, signed off-chain by the oracle + /// @param saleProceeds the proceeds from the sale desired by the filler/caller, denominated in the quote asset + /// @param optionInstrumentAddress the address of the Hook option instrument contract + /// @param optionId the id of the option token + /// + /// @dev the optionInstrumentAddress must be trusted by the orderer (maker) when signing to be related + /// to their desired market / option terms (i.e. the option must be a european call option on the + /// correct underlying asset). If the option instrument/market supports many different sub-collections, + /// as in the case with artblocks or a foundation shared contract, then a corresponding property validator + /// should be included in the order as to ensure that the underlying asset for the option is the one that + /// the maker intended. + /// + /// The value of the "bid" for a specific order changes (decreases) with each block because the time + /// until the option expires decreases. Instead of computing the highest possible sale proceeds at + /// the time of the order, an implementer can compute a slightly lower sale proceeds, perhaps + /// at a time a few blocks into the future, to ensure that the transaction is still successful. + /// If they do this, the protocol won't earn extra fees -- that savings is passed on to the buyer. + function sellOption( + PoolOrders.Order calldata order, + Signatures.Signature calldata orderSignature, + AssetPriceClaim calldata assetPrice, + OrderValidityOracleClaim calldata orderValidityOracleClaim, + uint256 saleProceeds, + address optionInstrumentAddress, + uint256 optionId + ) external nonReentrant whenNotPaused { + // input validity checks + bytes32 eip712hash = _getEIP712Hash(PoolOrders.getPoolOrderStructHash(order)); + (uint256 expiry, uint256 strikePrice) = _performSellOptionOrderChecks( + order, eip712hash, orderSignature, assetPrice, orderValidityOracleClaim, optionInstrumentAddress, optionId + ); + (uint256 ask, uint256 bid) = _computeOptionAskAndBid(order, assetPrice, expiry, strikePrice, saleProceeds); + + require(bid >= ask, "order not high enough for the ask"); + + IERC721(optionInstrumentAddress).safeTransferFrom(msg.sender, order.maker, optionId); + IERC20(weth).safeTransferFrom(order.maker, msg.sender, saleProceeds); + IERC20(weth).safeTransferFrom(order.maker, feeRecipient, ask - saleProceeds); + + // update order fills + orderFills[eip712hash] += 1; + emit OrderFilled( + order.maker, msg.sender, eip712hash, saleProceeds, ask - saleProceeds, optionInstrumentAddress, optionId + ); + } + + /// @notice Function to allow a maker to cancel all examples of an order that they've already signed. + /// If an order has already been filled, but support more than one fill, calling this function cancels + /// future fills of the order (but not current ones). + /// + /// @param order the order struct that should no longer be fillable. + /// + /// @dev this function is available even when the pool is paused in case makers want to cancel orders + /// as a result of the event that motivated the pause. + function cancelOrder(PoolOrders.Order calldata order) external { + require(msg.sender == order.maker, "Only the order maker can cancel the order"); + bytes32 eip712hash = _getEIP712Hash(PoolOrders.getPoolOrderStructHash(order)); + orderCancellations[eip712hash] = true; + emit OrderCancelled(order.maker, eip712hash); + } + + /// EXTERNAL ACCESS-CONTROLLED FUNCTIONS /// + + function setProtocol(address _protocol) external onlyRole(PROTOCOL_ROLE) { + setAddressForEipDomain(_protocol); + protocol = IHookProtocol(_protocol); + emit ProtocolAddressSet(_protocol); + } + + function setPriceOracleSigner(address _priceOracleSigner) external onlyRole(ORACLE_ROLE) { + priceOracleSigner = _priceOracleSigner; + emit PriceOracleSignerUpdated(_priceOracleSigner); + } + + function setOrderValidityOracleSigner(address _orderValidityOracleSigner) external onlyRole(ORACLE_ROLE) { + orderValidityOracleSigner = _orderValidityOracleSigner; + emit OrderValidityOracleSignerUpdated(_orderValidityOracleSigner); + } + + function setFeeBips(uint64 _feeBips) external onlyRole(FEES_ROLE) { + require(_feeBips <= 10000, "Fee bips over 10000"); + feeBips = _feeBips; + emit FeesUpdated(_feeBips); + } + + function setFeeRecipient(address _feeRecipient) external onlyRole(FEES_ROLE) { + feeRecipient = _feeRecipient; + emit ProtocolFeeRecipientUpdated(_feeRecipient); + } + + /// @dev sets a paused / unpaused state for this bid pool + /// @param _paused should the bid pool be set to paused? + function setPoolPaused(bool _paused) external onlyRole(PAUSER_ROLE) { + require(paused == !_paused, "cannot set to current state"); + paused = _paused; + emit PauseUpdated(paused); + } + + /// MODIFIERS /// + + /// @dev modifier to check that the market is not paused + /// this also includes a check that the overall Hook protocol is + /// not paused. The Hook Protocol pause is designed to convert the + /// protocol to a close-only state in the event of a disaster. + modifier whenNotPaused() { + require(!paused, "market paused"); + protocol.throwWhenPaused(); + _; + } + + /// INTERNAL FUNCTIONS /// + + /// @notice checks that the validity claim was signed by the oracle, and that the claim is not expired + /// + /// NOTE: if the order validity oracle is compromised, the security provided by this check will be invalidated + /// if a user does not trust the off-chain order validity oracle, they should cancel orders by using the + /// cancel function provider. + /// + /// @param claim the claim to be verified + /// @param orderHash the hash of the subject order + /// @dev this function uses an ETHSIGN signature because it makes it much easier to test as many + /// signers automatically sign messages in this format. It is not technically necessary as standard + /// wallet providers will not be signing these messages. + function _validateOrderValidityOracleClaim(OrderValidityOracleClaim calldata claim, bytes32 orderHash) + internal + view + { + bytes memory claimEncoded = abi.encode(orderHash, claim.goodTilTimestamp); + + bytes32 claimHash = keccak256(claimEncoded); + bytes32 prefixedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", claimHash)); + + address signer = ecrecover(prefixedHash, claim.v, claim.r, claim.s); + + require(signer == orderValidityOracleSigner, "Claim is not signed by the orderValidityOracle"); + require(claim.goodTilTimestamp > block.timestamp, "Claim is expired"); + } + + /// @notice checks that the asset price claim was signed by the oracle, and that the claim is not expired + /// + /// NOTE: If the price oracle signer is compromised, any claims made by the compromised signer will be + /// considered valid. This is a security risk, must trust that this oracle has not been compromised and + /// provides accurate price data in order to utilize this pool. If a user believes that the oracle is + /// compromised, they should cancel orders by using the cancel function provided. Additionally, the + /// protocol should be paused in the event of a compromised oracle. + /// + /// @param claim the claim to be verified + function _validateAssetPriceClaim(AssetPriceClaim calldata claim) internal view { + bytes memory claimEncoded = + abi.encode(claim.assetPriceInWei, claim.priceObservedTimestamp, claim.goodTilTimestamp); + + bytes32 claimHash = keccak256(claimEncoded); + bytes32 prefixedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", claimHash)); + + address signer = ecrecover(prefixedHash, claim.v, claim.r, claim.s); + + require(signer == priceOracleSigner, "Claim is not signed by the priceOracle"); + require(claim.goodTilTimestamp > block.timestamp, "Claim is expired"); + } + + /// @notice validates the EIP-712 signature for the order. If the order maker has + /// delegated rights for this contract to a different signer, then orders signed by + /// that signer are also be considered valid. + /// + /// @param hash the EIP-721 hash of the order struct + /// @param maker the maker of the order, who should have signed the order + /// @param orderSignature the signature of the order + /// @dev it is essential that the correct order maker is passed in at this step + function _validateOrderSignature(bytes32 hash, address maker, Signatures.Signature calldata orderSignature) + internal + view + { + address signer = ecrecover(hash, orderSignature.v, orderSignature.r, orderSignature.s); + require(signer != address(0), "Order signature is invalid"); // sanity check - maker should not be 0 + if (signer == maker) { + // if the order maker signed the order, than accept the signer's signature + return; + } + // If the maker has delegated control of this contract to a different signer, + // then accept this signed order as a valid signature. + require( + DELEGATE_CASH_REGISTRY.checkDelegateForContract(signer, maker, address(this)), "Order signature is invalid" + ); + } + + /// @dev modifies the supplied base implied volatility to account for skew. + /// @param strikePrice the strike price of the option + /// @param assetPrice the asset price of the underlying asset + /// @param order the order to source the volatility and skew + function _computeVolDecimalWithSkewDecimal(uint256 strikePrice, uint256 assetPrice, PoolOrders.Order memory order) + internal + view + returns (uint256) + { + uint256 decimalVol = order.impliedVolBips * BPS_TO_DECIMAL; + if (order.skewDecimal == 0) { + return decimalVol; + } + uint256 xDistance = Math.abs(int256(strikePrice) - int256(assetPrice)); + uint256 volIncrease = DecimalMath.multiplyDecimal(xDistance, order.skewDecimal); + uint256 volWithSkew = decimalVol + volIncrease; + return volWithSkew; + } + + /// @dev compute the input checks for selling an option. + /// factored out to resolve a stack space issue. + function _performSellOptionOrderChecks( + PoolOrders.Order calldata order, + bytes32 eip712hash, + Signatures.Signature calldata orderSignature, + AssetPriceClaim calldata assetPrice, + OrderValidityOracleClaim calldata orderValidityOracleClaim, + address optionInstrumentAddress, + uint256 optionId + ) internal returns (uint256 expiry, uint256 strikePrice) { + /// validate the signature from the order validity oracle + _validateOrderValidityOracleClaim(orderValidityOracleClaim, eip712hash); + /// validate that the maker signed their order. + _validateOrderSignature(eip712hash, order.maker, orderSignature); + /// validate the asset price claim from the price oracle + _validateAssetPriceClaim(assetPrice); + + /// verify that the price signal is not too old, or that the order does not + /// sepcify a maximum price signal age + require( + order.maxPriceSignalAge == 0 + || block.timestamp - order.maxPriceSignalAge < assetPrice.priceObservedTimestamp, + "Price signal is too old" + ); + + // Verify that the order is not cancelled or filled too many times + require(!orderCancellations[eip712hash], "Order is cancelled"); + require(orderFills[eip712hash] < order.size, "Order is filled"); + + require(order.orderExpiry > block.timestamp, "Order is expired"); + require(order.direction == PoolOrders.OrderDirection.BUY, "Order is not a buy order"); + + IHookOption hookOption = IHookOption(optionInstrumentAddress); + strikePrice = hookOption.getStrikePrice(optionId); + expiry = hookOption.getExpiration(optionId); + + _validateOptionProperties(order, optionInstrumentAddress, optionId); + /// even if the order technically allows it, make sure this pool cannot be used for trading + /// expired options. + require(expiry > block.timestamp, "Option is expired"); + require(block.timestamp + order.minOptionDuration < expiry, "Option is too close to expiry"); + require( + order.maxOptionDuration == 0 || block.timestamp + order.maxOptionDuration > expiry, + "Option is too far from expiry" + ); + + /// verify that the option is not too far out of the money given the strike price multiple + /// if one has been specified by the maker + require( + order.maxStrikePriceMultiple == 0 + || (strikePrice - assetPrice.assetPriceInWei) * 10e18 / assetPrice.assetPriceInWei + < order.maxStrikePriceMultiple, + "option is too far out of the money" + ); + } + + function _computeOptionAskAndBid( + PoolOrders.Order calldata order, + AssetPriceClaim calldata assetPrice, + uint256 expiry, + uint256 strikePrice, + uint256 saleProceeds + ) internal view returns (uint256 ask, uint256 bid) { + ask = (saleProceeds * (10000 + feeBips)) / 10000; + uint256 decimalVol = _computeVolDecimalWithSkewDecimal(strikePrice, assetPrice.assetPriceInWei, order); + int256 rateDecimal = int256(order.riskFreeRateBips * BPS_TO_DECIMAL); + (uint256 callBid, uint256 putBid) = BlackScholes.optionPrices( + BlackScholes.BlackScholesInputs({ + timeToExpirySec: (expiry - block.timestamp), + volatilityDecimal: decimalVol, + spotDecimal: assetPrice.assetPriceInWei, // ETH prices are already 18 decimals + strikePriceDecimal: strikePrice, + rateDecimal: rateDecimal + }) + ); + if (order.optionType == PoolOrders.OptionType.CALL) { + bid = callBid; + } else { + bid = putBid; + } + } + + function _validateOptionProperties(PoolOrders.Order memory order, address optionInstrument, uint256 optionId) + internal + view + { + // If no properties are specified, the order is valid for any instrument. + if (order.nftProperties.length == 0) { + return; + } else { + // Validate each property + for (uint256 i = 0; i < order.nftProperties.length; i++) { + PoolOrders.Property memory property = order.nftProperties[i]; + // `address(0)` is interpreted as a no-op. Any token ID + // will satisfy a property with `propertyValidator == address(0)`. + if (address(property.propertyValidator) == address(0)) { + continue; + } + + // Call the property validator and throw a descriptive error + // if the call reverts. + try property.propertyValidator.validateProperty(optionInstrument, optionId, property.propertyData) {} + catch { + revert("Property validation failed for the provided optionId"); + } + } + } + } +} diff --git a/src/interfaces/IHookOption.sol b/src/interfaces/IHookOption.sol new file mode 100644 index 0000000..3773772 --- /dev/null +++ b/src/interfaces/IHookOption.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +// +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// ██████████████ ██████████████ +// ██████████████ ▄▄████████████████▄▄ ▐█████████████▌ +// ██████████████ ▄█████████████████████████████▄ ██████████████ +// ██████████▀ ▄█████████████████████████████████ ██████████████▌ +// ██████▀ ▄██████████████████████████████████▀ ▄███████████████ +// ███▀ ██████████████████████████████████▀ ▄████████████████ +// ▀▀ ████████████████████████████████▀▀ ▄█████████████████▌ +// █████████████████████▀▀▀▀▀▀▀ ▄▄███████████████████▀ +// ██████████████████▀ ▄▄▄█████████████████████████████▀ +// ████████████████▀ ▄█████████████████████████████████▀ ██▄ +// ▐███████████████▀ ▄██████████████████████████████████▀ █████▄ +// ██████████████▀ ▄█████████████████████████████████▀ ▄████████ +// ██████████████▀ ███████████████████████████████▀ ▄████████████ +// ▐█████████████▌ ▀▀▀▀████████████████████▀▀▀▀ █████████████▌ +// ██████████████ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ + +pragma solidity ^0.8.10; + +interface IHookOption { + enum OptionType { + CALL, + PUT + } + enum OptionClass { + EUROPEAN, + AMERICAN + } + + function getStrikePrice(uint256 optionId) external view returns (uint256); + function getExpiration(uint256 optionId) external view returns (uint256); +} diff --git a/src/interfaces/delegate-cash/IDelegationRegistry.sol b/src/interfaces/delegate-cash/IDelegationRegistry.sol new file mode 100644 index 0000000..aa770c0 --- /dev/null +++ b/src/interfaces/delegate-cash/IDelegationRegistry.sol @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity 0.8.10; + +/** + * @title An immutable registry contract to be deployed as a standalone primitive + * @dev See EIP-5639, new project launches can read previous cold wallet -> hot wallet delegations + * from here and integrate those permissions into their flow + */ +interface IDelegationRegistry { + /// @notice Delegation type + enum DelegationType { + NONE, + ALL, + CONTRACT, + TOKEN + } + + /// @notice Info about a single delegation, used for onchain enumeration + struct DelegationInfo { + DelegationType type_; + address vault; + address delegate; + address contract_; + uint256 tokenId; + } + + /// @notice Info about a single contract-level delegation + struct ContractDelegation { + address contract_; + address delegate; + } + + /// @notice Info about a single token-level delegation + struct TokenDelegation { + address contract_; + uint256 tokenId; + address delegate; + } + + /// @notice Emitted when a user delegates their entire wallet + event DelegateForAll(address vault, address delegate, bool value); + + /// @notice Emitted when a user delegates a specific contract + event DelegateForContract(address vault, address delegate, address contract_, bool value); + + /// @notice Emitted when a user delegates a specific token + event DelegateForToken(address vault, address delegate, address contract_, uint256 tokenId, bool value); + + /// @notice Emitted when a user revokes all delegations + event RevokeAllDelegates(address vault); + + /// @notice Emitted when a user revoes all delegations for a given delegate + event RevokeDelegate(address vault, address delegate); + + /** + * ----------- WRITE ----------- + */ + + /** + * @notice Allow the delegate to act on your behalf for all contracts + * @param delegate The hotwallet to act on your behalf + * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking + */ + function delegateForAll(address delegate, bool value) external; + + /** + * @notice Allow the delegate to act on your behalf for a specific contract + * @param delegate The hotwallet to act on your behalf + * @param contract_ The address for the contract you're delegating + * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking + */ + function delegateForContract(address delegate, address contract_, bool value) external; + + /** + * @notice Allow the delegate to act on your behalf for a specific token + * @param delegate The hotwallet to act on your behalf + * @param contract_ The address for the contract you're delegating + * @param tokenId The token id for the token you're delegating + * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking + */ + function delegateForToken(address delegate, address contract_, uint256 tokenId, bool value) external; + + /** + * @notice Revoke all delegates + */ + function revokeAllDelegates() external; + + /** + * @notice Revoke a specific delegate for all their permissions + * @param delegate The hotwallet to revoke + */ + function revokeDelegate(address delegate) external; + + /** + * @notice Remove yourself as a delegate for a specific vault + * @param vault The vault which delegated to the msg.sender, and should be removed + */ + function revokeSelf(address vault) external; + + /** + * ----------- READ ----------- + */ + + /** + * @notice Returns all active delegations a given delegate is able to claim on behalf of + * @param delegate The delegate that you would like to retrieve delegations for + * @return info Array of DelegationInfo structs + */ + function getDelegationsByDelegate(address delegate) external view returns (DelegationInfo[] memory); + + /** + * @notice Returns an array of wallet-level delegates for a given vault + * @param vault The cold wallet who issued the delegation + * @return addresses Array of wallet-level delegates for a given vault + */ + function getDelegatesForAll(address vault) external view returns (address[] memory); + + /** + * @notice Returns an array of contract-level delegates for a given vault and contract + * @param vault The cold wallet who issued the delegation + * @param contract_ The address for the contract you're delegating + * @return addresses Array of contract-level delegates for a given vault and contract + */ + function getDelegatesForContract(address vault, address contract_) external view returns (address[] memory); + + /** + * @notice Returns an array of contract-level delegates for a given vault's token + * @param vault The cold wallet who issued the delegation + * @param contract_ The address for the contract holding the token + * @param tokenId The token id for the token you're delegating + * @return addresses Array of contract-level delegates for a given vault's token + */ + function getDelegatesForToken(address vault, address contract_, uint256 tokenId) + external + view + returns (address[] memory); + + /** + * @notice Returns all contract-level delegations for a given vault + * @param vault The cold wallet who issued the delegations + * @return delegations Array of ContractDelegation structs + */ + function getContractLevelDelegations(address vault) + external + view + returns (ContractDelegation[] memory delegations); + + /** + * @notice Returns all token-level delegations for a given vault + * @param vault The cold wallet who issued the delegations + * @return delegations Array of TokenDelegation structs + */ + function getTokenLevelDelegations(address vault) external view returns (TokenDelegation[] memory delegations); + + /** + * @notice Returns true if the address is delegated to act on the entire vault + * @param delegate The hotwallet to act on your behalf + * @param vault The cold wallet who issued the delegation + */ + function checkDelegateForAll(address delegate, address vault) external view returns (bool); + + /** + * @notice Returns true if the address is delegated to act on your behalf for a token contract or an entire vault + * @param delegate The hotwallet to act on your behalf + * @param contract_ The address for the contract you're delegating + * @param vault The cold wallet who issued the delegation + */ + function checkDelegateForContract(address delegate, address vault, address contract_) + external + view + returns (bool); + + /** + * @notice Returns true if the address is delegated to act on your behalf for a specific token, the token's contract or an entire vault + * @param delegate The hotwallet to act on your behalf + * @param contract_ The address for the contract you're delegating + * @param tokenId The token id for the token you're delegating + * @param vault The cold wallet who issued the delegation + */ + function checkDelegateForToken(address delegate, address vault, address contract_, uint256 tokenId) + external + view + returns (bool); +} diff --git a/src/interfaces/delegate-cash/README.md b/src/interfaces/delegate-cash/README.md new file mode 100644 index 0000000..449158b --- /dev/null +++ b/src/interfaces/delegate-cash/README.md @@ -0,0 +1,6 @@ +This folder contains the interfaces for the Delegate Cash contracts. + +They can be found here: +https://github.com/delegatecash/delegation-registry/blob/main/src/IDelegationRegistry.sol + +The deployed address is 0x00000000000076A84feF008CDAbe6409d2FE638B on all chains. \ No newline at end of file diff --git a/src/interfaces/zeroex-v4/IPropertyValidator.sol b/src/interfaces/zeroex-v4/IPropertyValidator.sol new file mode 100644 index 0000000..4e7c681 --- /dev/null +++ b/src/interfaces/zeroex-v4/IPropertyValidator.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.10; + +interface IPropertyValidator { + /// @dev Checks that the given ERC721/ERC1155 asset satisfies the properties encoded in `propertyData`. + /// Should revert if the asset does not satisfy the specified properties. + /// @param tokenAddress The ERC721/ERC1155 token contract address. + /// @param tokenId The ERC721/ERC1155 tokenId of the asset to check. + /// @param propertyData Encoded properties or auxiliary data needed to perform the check. + function validateProperty(address tokenAddress, uint256 tokenId, bytes calldata propertyData) external view; +} diff --git a/src/lib/PoolOrders.sol b/src/lib/PoolOrders.sol new file mode 100644 index 0000000..5cdaa4b --- /dev/null +++ b/src/lib/PoolOrders.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT +// +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// █████████████▌ ▐█████████████ +// ██████████████ ██████████████ +// ██████████████ ▄▄████████████████▄▄ ▐█████████████▌ +// ██████████████ ▄█████████████████████████████▄ ██████████████ +// ██████████▀ ▄█████████████████████████████████ ██████████████▌ +// ██████▀ ▄██████████████████████████████████▀ ▄███████████████ +// ███▀ ██████████████████████████████████▀ ▄████████████████ +// ▀▀ ████████████████████████████████▀▀ ▄█████████████████▌ +// █████████████████████▀▀▀▀▀▀▀ ▄▄███████████████████▀ +// ██████████████████▀ ▄▄▄█████████████████████████████▀ +// ████████████████▀ ▄█████████████████████████████████▀ ██▄ +// ▐███████████████▀ ▄██████████████████████████████████▀ █████▄ +// ██████████████▀ ▄█████████████████████████████████▀ ▄████████ +// ██████████████▀ ███████████████████████████████▀ ▄████████████ +// ▐█████████████▌ ▀▀▀▀████████████████████▀▀▀▀ █████████████▌ +// ██████████████ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ +// █████████████▌ ██████████████ + +pragma solidity ^0.8.10; + +import "../interfaces/zeroex-v4/IPropertyValidator.sol"; + +library PoolOrders { + uint256 private constant _PROPERTY_TYPEHASH = + uint256(keccak256(abi.encodePacked("Property(", "address propertyValidator,", "bytes propertyData", ")"))); + + // uint256 private constant _ORDER_TYPEHASH = abi.encode( + // "Order(", + // "uint8 direction,", + // "address maker,", + // "uint256 orderExpiry,", + // "uint256 nonce,", + // "uint8 size,", + // "uint8 optionType,", + // "uint256 maxStrikePriceMultiple," + // "uint64 minOptionDuration,", + // "uint64 maxOptionDuration,", + // "uint64 maxPriceSignalAge,", + // "Property[] nftProperties,", + // "address optionMarketAddress,", + // "uint64 impliedVolBips,", + // "uint256 skewDecimal,", + // "uint64 riskFreeRateBips", + // ")", + // _PROPERTY_TYPEHASH + // ); + uint256 private constant _ORDER_TYPEHASH = 0xcf88a2fdf20e362d67310061df675df92f17bd55a872a02e14b7dc017475f705; + + /// ---- ENUMS ----- + enum OptionType { + CALL, + PUT + } + + enum OrderDirection { + BUY, + SELL + } + + /// ---- STRUCTS ----- + struct Property { + IPropertyValidator propertyValidator; + bytes propertyData; + } + + struct Order { + /// @notice the direction of the order. Only BUY orders are currently supported + OrderDirection direction; + /// @notice the address of the maker who must sign this order + address maker; + /// @notice the block timestamp at which this order can no longer be filled + uint256 orderExpiry; + /// @notice a cryptographic nonce used to make the order unique + uint256 nonce; + /// @notice the maximum number of times this order can be filled + uint8 size; + OptionType optionType; + /// @notice bips in the money or out of the money an option can be filled at. For example, 5000 == 50% out of the money max for a call option. 0 means no max + uint256 maxStrikePriceMultiple; + /// @notice minimum time from the time the order is filled that the option could expire. 0 means no min + uint64 minOptionDuration; + /// @notice maximum time from the time the order is filled that the option could expire. 0 means no max + uint64 maxOptionDuration; + /// @notice maximum age of a price signal to accept as a valid floor price + uint64 maxPriceSignalAge; + /// @notice array of property validators if the filler would like more fine-grained control of the filling option instrument + Property[] nftProperties; + /// @notice address of Hook option market (and option instrument) that can fill this order. This address must be trusted by the orderer to deliver the correct type of call instrument. + address optionMarketAddress; + /// @notice impliedVolBips is the maximum implied volatility of the desired options in bips (1/100th of a percent). For example, 100 bips = 1%. + uint64 impliedVolBips; + /// @notice the decimal-described slope of the skew for the desired implied volatility + uint256 skewDecimal; + /// @notice riskFreeRateBips is the percentage risk free rate + carry costs (e.g. 100 = 1%). About 5% is typical. + uint64 riskFreeRateBips; + } + + function _propertiesHash(Property[] memory properties) private pure returns (bytes32 propertiesHash) { + uint256 numProperties = properties.length; + if (numProperties == 0) { + return 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; + } + bytes32[] memory propertyStructHashArray = new bytes32[](numProperties); + for (uint256 i = 0; i < numProperties; i++) { + propertyStructHashArray[i] = keccak256( + abi.encode(_PROPERTY_TYPEHASH, properties[i].propertyValidator, keccak256(properties[i].propertyData)) + ); + } + return keccak256(abi.encodePacked(propertyStructHashArray)); + } + + /// @dev split the hash to resolve a stack too deep error + function _hashPt1(Order memory poolOrder) private pure returns (bytes memory) { + return abi.encode( + _ORDER_TYPEHASH, + poolOrder.direction, + poolOrder.maker, + poolOrder.orderExpiry, + poolOrder.nonce, + poolOrder.size, + poolOrder.optionType, + poolOrder.maxStrikePriceMultiple + ); + } + + /// @dev split the hash to resolve a stack too deep error + function _hashPt2(Order memory poolOrder) private pure returns (bytes memory) { + return abi.encode( + poolOrder.minOptionDuration, + poolOrder.maxOptionDuration, + poolOrder.maxPriceSignalAge, + _propertiesHash(poolOrder.nftProperties), + poolOrder.optionMarketAddress, + poolOrder.impliedVolBips, + poolOrder.skewDecimal, + poolOrder.riskFreeRateBips + ); + } + + function getPoolOrderStructHash(Order memory poolOrder) internal view returns (bytes32) { + return keccak256(abi.encodePacked(_hashPt1(poolOrder), _hashPt2(poolOrder))); + } +} diff --git a/src/lib/lyra/BlackScholes.sol b/src/lib/lyra/BlackScholes.sol new file mode 100644 index 0000000..fa67448 --- /dev/null +++ b/src/lib/lyra/BlackScholes.sol @@ -0,0 +1,412 @@ +//SPDX-License-Identifier: ISC +pragma solidity 0.8.10; + +// Libraries +import "../synthetix/SignedDecimalMath.sol"; +import "../synthetix/DecimalMath.sol"; +import "./FixedPointMathLib.sol"; +import "./Math.sol"; + +/** + * @title BlackScholes + * @author Lyra + * @dev Contract to compute the black scholes price of options. Where the unit is unspecified, it should be treated as a + * PRECISE_DECIMAL, which has 1e27 units of precision. The default decimal matches the ethereum standard of 1e18 units + * of precision. + */ +library BlackScholes { + using DecimalMath for uint256; + using SignedDecimalMath for int256; + + struct PricesDeltaStdVega { + uint256 callPrice; + uint256 putPrice; + int256 callDelta; + int256 putDelta; + uint256 vega; + uint256 stdVega; + } + + /** + * @param timeToExpirySec Number of seconds to the expiry of the option + * @param volatilityDecimal Implied volatility over the period til expiry as a percentage + * @param spotDecimal The current price of the base asset + * @param strikePriceDecimal The strikePrice price of the option + * @param rateDecimal The percentage risk free rate + carry cost + */ + struct BlackScholesInputs { + uint256 timeToExpirySec; + uint256 volatilityDecimal; + uint256 spotDecimal; + uint256 strikePriceDecimal; + int256 rateDecimal; + } + + uint256 private constant SECONDS_PER_YEAR = 31536000; + /// @dev Internally this library uses 27 decimals of precision + uint256 private constant PRECISE_UNIT = 1e27; + uint256 private constant SQRT_TWOPI = 2506628274631000502415765285; + /// @dev Value to use to avoid any division by 0 or values near 0 + uint256 private constant MIN_T_ANNUALISED = PRECISE_UNIT / SECONDS_PER_YEAR; // 1 second + uint256 private constant MIN_VOLATILITY = PRECISE_UNIT / 10000; // 0.001% + uint256 private constant VEGA_STANDARDISATION_MIN_DAYS = 7 days; + /// @dev Magic numbers for normal CDF + uint256 private constant SPLIT = 7071067811865470000000000000; + uint256 private constant N0 = 220206867912376000000000000000; + uint256 private constant N1 = 221213596169931000000000000000; + uint256 private constant N2 = 112079291497871000000000000000; + uint256 private constant N3 = 33912866078383000000000000000; + uint256 private constant N4 = 6373962203531650000000000000; + uint256 private constant N5 = 700383064443688000000000000; + uint256 private constant N6 = 35262496599891100000000000; + uint256 private constant M0 = 440413735824752000000000000000; + uint256 private constant M1 = 793826512519948000000000000000; + uint256 private constant M2 = 637333633378831000000000000000; + uint256 private constant M3 = 296564248779674000000000000000; + uint256 private constant M4 = 86780732202946100000000000000; + uint256 private constant M5 = 16064177579207000000000000000; + uint256 private constant M6 = 1755667163182640000000000000; + uint256 private constant M7 = 88388347648318400000000000; + + ///////////////////////////////////// + // Option Pricing public functions // + ///////////////////////////////////// + + /** + * @dev Returns call and put prices for options with given parameters. + */ + function optionPrices(BlackScholesInputs memory bsInput) public pure returns (uint256 call, uint256 put) { + uint256 tAnnualised = _annualise(bsInput.timeToExpirySec); + uint256 spotPrecise = bsInput.spotDecimal.decimalToPreciseDecimal(); + uint256 strikePricePrecise = bsInput.strikePriceDecimal.decimalToPreciseDecimal(); + int256 ratePrecise = bsInput.rateDecimal.decimalToPreciseDecimal(); + (int256 d1, int256 d2) = _d1d2( + tAnnualised, + bsInput.volatilityDecimal.decimalToPreciseDecimal(), + spotPrecise, + strikePricePrecise, + ratePrecise + ); + (call, put) = _optionPrices(tAnnualised, spotPrecise, strikePricePrecise, ratePrecise, d1, d2); + return (call.preciseDecimalToDecimal(), put.preciseDecimalToDecimal()); + } + + /** + * @dev Returns call/put prices and delta/stdVega for options with given parameters. + */ + function pricesDeltaStdVega(BlackScholesInputs memory bsInput) public pure returns (PricesDeltaStdVega memory) { + uint256 tAnnualised = _annualise(bsInput.timeToExpirySec); + uint256 spotPrecise = bsInput.spotDecimal.decimalToPreciseDecimal(); + + (int256 d1, int256 d2) = _d1d2( + tAnnualised, + bsInput.volatilityDecimal.decimalToPreciseDecimal(), + spotPrecise, + bsInput.strikePriceDecimal.decimalToPreciseDecimal(), + bsInput.rateDecimal.decimalToPreciseDecimal() + ); + (uint256 callPrice, uint256 putPrice) = _optionPrices( + tAnnualised, + spotPrecise, + bsInput.strikePriceDecimal.decimalToPreciseDecimal(), + bsInput.rateDecimal.decimalToPreciseDecimal(), + d1, + d2 + ); + (uint256 vegaPrecise, uint256 stdVegaPrecise) = _standardVega(d1, spotPrecise, bsInput.timeToExpirySec); + (int256 callDelta, int256 putDelta) = _delta(d1); + + return PricesDeltaStdVega( + callPrice.preciseDecimalToDecimal(), + putPrice.preciseDecimalToDecimal(), + callDelta.preciseDecimalToDecimal(), + putDelta.preciseDecimalToDecimal(), + vegaPrecise.preciseDecimalToDecimal(), + stdVegaPrecise.preciseDecimalToDecimal() + ); + } + + /** + * @dev Returns call delta given parameters. + */ + + function delta(BlackScholesInputs memory bsInput) + public + pure + returns (int256 callDeltaDecimal, int256 putDeltaDecimal) + { + uint256 tAnnualised = _annualise(bsInput.timeToExpirySec); + uint256 spotPrecise = bsInput.spotDecimal.decimalToPreciseDecimal(); + + (int256 d1,) = _d1d2( + tAnnualised, + bsInput.volatilityDecimal.decimalToPreciseDecimal(), + spotPrecise, + bsInput.strikePriceDecimal.decimalToPreciseDecimal(), + bsInput.rateDecimal.decimalToPreciseDecimal() + ); + + (int256 callDelta, int256 putDelta) = _delta(d1); + return (callDelta.preciseDecimalToDecimal(), putDelta.preciseDecimalToDecimal()); + } + + /** + * @dev Returns non-normalized vega given parameters. Quoted in cents. + */ + function vega(BlackScholesInputs memory bsInput) public pure returns (uint256 vegaDecimal) { + uint256 tAnnualised = _annualise(bsInput.timeToExpirySec); + uint256 spotPrecise = bsInput.spotDecimal.decimalToPreciseDecimal(); + + (int256 d1,) = _d1d2( + tAnnualised, + bsInput.volatilityDecimal.decimalToPreciseDecimal(), + spotPrecise, + bsInput.strikePriceDecimal.decimalToPreciseDecimal(), + bsInput.rateDecimal.decimalToPreciseDecimal() + ); + return _vega(tAnnualised, spotPrecise, d1).preciseDecimalToDecimal(); + } + + ////////////////////// + // Computing Greeks // + ////////////////////// + + /** + * @dev Returns internal coefficients of the Black-Scholes call price formula, d1 and d2. + * @param tAnnualised Number of years to expiry + * @param volatility Implied volatility over the period til expiry as a percentage + * @param spot The current price of the base asset + * @param strikePrice The strikePrice price of the option + * @param rate The percentage risk free rate + carry cost + */ + function _d1d2(uint256 tAnnualised, uint256 volatility, uint256 spot, uint256 strikePrice, int256 rate) + internal + pure + returns (int256 d1, int256 d2) + { + // Set minimum values for tAnnualised and volatility to not break computation in extreme scenarios + // These values will result in option prices reflecting only the difference in stock/strikePrice, which is expected. + // This should be caught before calling this function, however the function shouldn't break if the values are 0. + tAnnualised = tAnnualised < MIN_T_ANNUALISED ? MIN_T_ANNUALISED : tAnnualised; + volatility = volatility < MIN_VOLATILITY ? MIN_VOLATILITY : volatility; + + int256 vtSqrt = int256(volatility.multiplyDecimalRoundPrecise(_sqrtPrecise(tAnnualised))); + int256 log = FixedPointMathLib.lnPrecise(int256(spot.divideDecimalRoundPrecise(strikePrice))); + int256 v2t = (int256(volatility.multiplyDecimalRoundPrecise(volatility) / 2) + rate).multiplyDecimalRoundPrecise( + int256(tAnnualised) + ); + d1 = (log + v2t).divideDecimalRoundPrecise(vtSqrt); + d2 = d1 - vtSqrt; + } + + /** + * @dev Internal coefficients of the Black-Scholes call price formula. + * @param tAnnualised Number of years to expiry + * @param spot The current price of the base asset + * @param strikePrice The strikePrice price of the option + * @param rate The percentage risk free rate + carry cost + * @param d1 Internal coefficient of Black-Scholes + * @param d2 Internal coefficient of Black-Scholes + */ + function _optionPrices(uint256 tAnnualised, uint256 spot, uint256 strikePrice, int256 rate, int256 d1, int256 d2) + internal + pure + returns (uint256 call, uint256 put) + { + uint256 strikePricePV = strikePrice.multiplyDecimalRoundPrecise( + FixedPointMathLib.expPrecise(int256(-rate.multiplyDecimalRoundPrecise(int256(tAnnualised)))) + ); + uint256 spotNd1 = spot.multiplyDecimalRoundPrecise(_stdNormalCDF(d1)); + uint256 strikePriceNd2 = strikePricePV.multiplyDecimalRoundPrecise(_stdNormalCDF(d2)); + + // We clamp to zero if the minuend is less than the subtrahend + // In some scenarios it may be better to compute put price instead and derive call from it depending on which way + // around is more precise. + call = strikePriceNd2 <= spotNd1 ? spotNd1 - strikePriceNd2 : 0; + put = call + strikePricePV; + put = spot <= put ? put - spot : 0; + } + + /* + * Greeks + */ + + /** + * @dev Returns the option's delta value + * @param d1 Internal coefficient of Black-Scholes + */ + function _delta(int256 d1) internal pure returns (int256 callDelta, int256 putDelta) { + callDelta = int256(_stdNormalCDF(d1)); + putDelta = callDelta - int256(PRECISE_UNIT); + } + + /** + * @dev Returns the option's vega value based on d1. Quoted in cents. + * + * @param d1 Internal coefficient of Black-Scholes + * @param tAnnualised Number of years to expiry + * @param spot The current price of the base asset + */ + function _vega(uint256 tAnnualised, uint256 spot, int256 d1) internal pure returns (uint256) { + return _sqrtPrecise(tAnnualised).multiplyDecimalRoundPrecise(_stdNormal(d1).multiplyDecimalRoundPrecise(spot)); + } + + /** + * @dev Returns the option's vega value with expiry modified to be at least VEGA_STANDARDISATION_MIN_DAYS + * @param d1 Internal coefficient of Black-Scholes + * @param spot The current price of the base asset + * @param timeToExpirySec Number of seconds to expiry + */ + function _standardVega(int256 d1, uint256 spot, uint256 timeToExpirySec) internal pure returns (uint256, uint256) { + uint256 tAnnualised = _annualise(timeToExpirySec); + uint256 normalisationFactor = _getVegaNormalisationFactorPrecise(timeToExpirySec); + uint256 vegaPrecise = _vega(tAnnualised, spot, d1); + return (vegaPrecise, vegaPrecise.multiplyDecimalRoundPrecise(normalisationFactor)); + } + + function _getVegaNormalisationFactorPrecise(uint256 timeToExpirySec) internal pure returns (uint256) { + timeToExpirySec = + timeToExpirySec < VEGA_STANDARDISATION_MIN_DAYS ? VEGA_STANDARDISATION_MIN_DAYS : timeToExpirySec; + uint256 daysToExpiry = timeToExpirySec / 1 days; + uint256 thirty = 30 * PRECISE_UNIT; + return _sqrtPrecise(thirty / daysToExpiry) / 100; + } + + ///////////////////// + // Math Operations // + ///////////////////// + + /// @notice Calculates the square root of x, rounding down (borrowed from https://github.com/paulrberg/prb-math) + /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. + /// @param x The uint256 number for which to calculate the square root. + /// @return result The result as an uint256. + function _sqrt(uint256 x) internal pure returns (uint256 result) { + if (x == 0) { + return 0; + } + + // Calculate the square root of the perfect square of a power of two that is the closest to x. + uint256 xAux = uint256(x); + result = 1; + if (xAux >= 0x100000000000000000000000000000000) { + xAux >>= 128; + result <<= 64; + } + if (xAux >= 0x10000000000000000) { + xAux >>= 64; + result <<= 32; + } + if (xAux >= 0x100000000) { + xAux >>= 32; + result <<= 16; + } + if (xAux >= 0x10000) { + xAux >>= 16; + result <<= 8; + } + if (xAux >= 0x100) { + xAux >>= 8; + result <<= 4; + } + if (xAux >= 0x10) { + xAux >>= 4; + result <<= 2; + } + if (xAux >= 0x8) { + result <<= 1; + } + + // The operations can never overflow because the result is max 2^127 when it enters this block. + unchecked { + result = (result + x / result) >> 1; + result = (result + x / result) >> 1; + result = (result + x / result) >> 1; + result = (result + x / result) >> 1; + result = (result + x / result) >> 1; + result = (result + x / result) >> 1; + result = (result + x / result) >> 1; // Seven iterations should be enough + uint256 roundedDownResult = x / result; + return result >= roundedDownResult ? roundedDownResult : result; + } + } + + /** + * @dev Returns the square root of the value using Newton's method. + */ + function _sqrtPrecise(uint256 x) internal pure returns (uint256) { + // Add in an extra unit factor for the square root to gobble; + // otherwise, sqrt(x * UNIT) = sqrt(x) * sqrt(UNIT) + return _sqrt(x * PRECISE_UNIT); + } + + /** + * @dev The standard normal distribution of the value. + */ + function _stdNormal(int256 x) internal pure returns (uint256) { + return FixedPointMathLib.expPrecise(int256(-x.multiplyDecimalRoundPrecise(x / 2))).divideDecimalRoundPrecise( + SQRT_TWOPI + ); + } + + /** + * @dev The standard normal cumulative distribution of the value. + * borrowed from a C++ implementation https://stackoverflow.com/a/23119456 + */ + function _stdNormalCDF(int256 x) public pure returns (uint256) { + uint256 z = Math.abs(x); + int256 c = 0; + + if (z <= 37 * PRECISE_UNIT) { + uint256 e = FixedPointMathLib.expPrecise(-int256(z.multiplyDecimalRoundPrecise(z / 2))); + if (z < SPLIT) { + c = int256( + ( + _stdNormalCDFNumerator(z).divideDecimalRoundPrecise(_stdNormalCDFDenom(z)) + .multiplyDecimalRoundPrecise(e) + ) + ); + } else { + uint256 f = ( + z + + PRECISE_UNIT.divideDecimalRoundPrecise( + z + + (2 * PRECISE_UNIT).divideDecimalRoundPrecise( + z + + (3 * PRECISE_UNIT).divideDecimalRoundPrecise( + z + (4 * PRECISE_UNIT).divideDecimalRoundPrecise(z + ((PRECISE_UNIT * 13) / 20)) + ) + ) + ) + ); + c = int256(e.divideDecimalRoundPrecise(f.multiplyDecimalRoundPrecise(SQRT_TWOPI))); + } + } + return uint256((x <= 0 ? c : (int256(PRECISE_UNIT) - c))); + } + + /** + * @dev Helper for _stdNormalCDF + */ + function _stdNormalCDFNumerator(uint256 z) internal pure returns (uint256) { + uint256 numeratorInner = ((((((N6 * z) / PRECISE_UNIT + N5) * z) / PRECISE_UNIT + N4) * z) / PRECISE_UNIT + N3); + return (((((numeratorInner * z) / PRECISE_UNIT + N2) * z) / PRECISE_UNIT + N1) * z) / PRECISE_UNIT + N0; + } + + /** + * @dev Helper for _stdNormalCDF + */ + function _stdNormalCDFDenom(uint256 z) internal pure returns (uint256) { + uint256 denominatorInner = + ((((((M7 * z) / PRECISE_UNIT + M6) * z) / PRECISE_UNIT + M5) * z) / PRECISE_UNIT + M4); + return ( + ((((((denominatorInner * z) / PRECISE_UNIT + M3) * z) / PRECISE_UNIT + M2) * z) / PRECISE_UNIT + M1) * z + ) / PRECISE_UNIT + M0; + } + + /** + * @dev Converts an integer number of seconds to a fractional number of years. + */ + function _annualise(uint256 secs) internal pure returns (uint256 yearFraction) { + return secs.divideDecimalRoundPrecise(SECONDS_PER_YEAR); + } +} diff --git a/src/lib/lyra/FixedPointMathLib.sol b/src/lib/lyra/FixedPointMathLib.sol new file mode 100644 index 0000000..4d4dcf7 --- /dev/null +++ b/src/lib/lyra/FixedPointMathLib.sol @@ -0,0 +1,162 @@ +//SPDX-License-Identifier: ISC +pragma solidity 0.8.10; + +// Slightly modified version of: +// - https://github.com/recmo/experiment-solexp/blob/605738f3ed72d6c67a414e992be58262fbc9bb80/src/FixedPointMathLib.sol +library FixedPointMathLib { + /// @dev Computes ln(x) for a 1e27 fixed point. Loses 9 last significant digits of precision. + function lnPrecise(int256 x) internal pure returns (int256 r) { + return ln(x / 1e9) * 1e9; + } + + /// @dev Computes e ^ x for a 1e27 fixed point. Loses 9 last significant digits of precision. + function expPrecise(int256 x) internal pure returns (uint256 r) { + return exp(x / 1e9) * 1e9; + } + + // Computes ln(x) in 1e18 fixed point. + // Reverts if x is negative or zero. + // Consumes 670 gas. + function ln(int256 x) internal pure returns (int256 r) { + unchecked { + if (x < 1) { + if (x < 0) revert LnNegativeUndefined(); + revert Overflow(); + } + + // We want to convert x from 10**18 fixed point to 2**96 fixed point. + // We do this by multiplying by 2**96 / 10**18. + // But since ln(x * C) = ln(x) + ln(C), we can simply do nothing here + // and add ln(2**96 / 10**18) at the end. + + // Reduce range of x to (1, 2) * 2**96 + // ln(2^k * x) = k * ln(2) + ln(x) + // Note: inlining ilog2 saves 8 gas. + int256 k = int256(ilog2(uint256(x))) - 96; + x <<= uint256(159 - k); + x = int256(uint256(x) >> 159); + + // Evaluate using a (8, 8)-term rational approximation + // p is made monic, we will multiply by a scale factor later + int256 p = x + 3273285459638523848632254066296; + p = ((p * x) >> 96) + 24828157081833163892658089445524; + p = ((p * x) >> 96) + 43456485725739037958740375743393; + p = ((p * x) >> 96) - 11111509109440967052023855526967; + p = ((p * x) >> 96) - 45023709667254063763336534515857; + p = ((p * x) >> 96) - 14706773417378608786704636184526; + p = p * x - (795164235651350426258249787498 << 96); + //emit log_named_int("p", p); + // We leave p in 2**192 basis so we don't need to scale it back up for the division. + // q is monic by convention + int256 q = x + 5573035233440673466300451813936; + q = ((q * x) >> 96) + 71694874799317883764090561454958; + q = ((q * x) >> 96) + 283447036172924575727196451306956; + q = ((q * x) >> 96) + 401686690394027663651624208769553; + q = ((q * x) >> 96) + 204048457590392012362485061816622; + q = ((q * x) >> 96) + 31853899698501571402653359427138; + q = ((q * x) >> 96) + 909429971244387300277376558375; + assembly { + // Div in assembly because solidity adds a zero check despite the `unchecked`. + // The q polynomial is known not to have zeros in the domain. (All roots are complex) + // No scaling required because p is already 2**96 too large. + r := sdiv(p, q) + } + // r is in the range (0, 0.125) * 2**96 + + // Finalization, we need to + // * multiply by the scale factor s = 5.549… + // * add ln(2**96 / 10**18) + // * add k * ln(2) + // * multiply by 10**18 / 2**96 = 5**18 >> 78 + // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 + r *= 1677202110996718588342820967067443963516166; + // add ln(2) * k * 5e18 * 2**192 + r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k; + // add ln(2**96 / 10**18) * 5e18 * 2**192 + r += 600920179829731861736702779321621459595472258049074101567377883020018308; + // base conversion: mul 2**18 / 2**192 + r >>= 174; + } + } + + // Integer log2 + // @returns floor(log2(x)) if x is nonzero, otherwise 0. This is the same + // as the location of the highest set bit. + // Consumes 232 gas. This could have been an 3 gas EVM opcode though. + function ilog2(uint256 x) internal pure returns (uint256 r) { + assembly { + r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) + r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) + r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) + r := or(r, shl(4, lt(0xffff, shr(r, x)))) + r := or(r, shl(3, lt(0xff, shr(r, x)))) + r := or(r, shl(2, lt(0xf, shr(r, x)))) + r := or(r, shl(1, lt(0x3, shr(r, x)))) + r := or(r, lt(0x1, shr(r, x))) + } + } + + // Computes e^x in 1e18 fixed point. + function exp(int256 x) internal pure returns (uint256 r) { + unchecked { + // Input x is in fixed point format, with scale factor 1/1e18. + + // When the result is < 0.5 we return zero. This happens when + // x <= floor(log(0.5e18) * 1e18) ~ -42e18 + if (x <= -42139678854452767551) { + return 0; + } + + // When the result is > (2**255 - 1) / 1e18 we can not represent it + // as an int256. This happens when x >= floor(log((2**255 -1) / 1e18) * 1e18) ~ 135. + if (x >= 135305999368893231589) revert ExpOverflow(); + + // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96 + // for more intermediate precision and a binary basis. This base conversion + // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. + x = (x << 78) / 5 ** 18; + + // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers of two + // such that exp(x) = exp(x') * 2**k, where k is an integer. + // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). + int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96; + x = x - k * 54916777467707473351141471128; + // k is in the range [-61, 195]. + + // Evaluate using a (6, 7)-term rational approximation + // p is made monic, we will multiply by a scale factor later + int256 p = x + 2772001395605857295435445496992; + p = ((p * x) >> 96) + 44335888930127919016834873520032; + p = ((p * x) >> 96) + 398888492587501845352592340339721; + p = ((p * x) >> 96) + 1993839819670624470859228494792842; + p = p * x + (4385272521454847904632057985693276 << 96); + // We leave p in 2**192 basis so we don't need to scale it back up for the division. + // Evaluate using using Knuth's scheme from p. 491. + int256 z = x + 750530180792738023273180420736; + z = ((z * x) >> 96) + 32788456221302202726307501949080; + int256 w = x - 2218138959503481824038194425854; + w = ((w * z) >> 96) + 892943633302991980437332862907700; + int256 q = z + w - 78174809823045304726920794422040; + q = ((q * w) >> 96) + 4203224763890128580604056984195872; + assembly { + // Div in assembly because solidity adds a zero check despite the `unchecked`. + // The q polynomial is known not to have zeros in the domain. (All roots are complex) + // No scaling required because p is already 2**96 too large. + r := sdiv(p, q) + } + // r should be in the range (0.09, 0.25) * 2**96. + + // We now need to multiply r by + // * the scale factor s = ~6.031367120..., + // * the 2**k factor from the range reduction, and + // * the 1e18 / 2**96 factor for base converison. + // We do all of this at once, with an intermediate result in 2**213 basis + // so the final right shift is always by a positive amount. + r = (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k); + } + } + + error Overflow(); + error ExpOverflow(); + error LnNegativeUndefined(); +} diff --git a/src/lib/lyra/Math.sol b/src/lib/lyra/Math.sol new file mode 100644 index 0000000..d8397ec --- /dev/null +++ b/src/lib/lyra/Math.sol @@ -0,0 +1,30 @@ +//SPDX-License-Identifier: ISC +pragma solidity 0.8.10; + +/** + * @title Math + * @author Lyra + * @dev Library to unify logic for common shared functions + */ +library Math { + /// @dev Return the minimum value between the two inputs + function min(uint256 x, uint256 y) internal pure returns (uint256) { + return (x < y) ? x : y; + } + + /// @dev Return the maximum value between the two inputs + function max(uint256 x, uint256 y) internal pure returns (uint256) { + return (x > y) ? x : y; + } + + /// @dev Compute the absolute value of `val`. + function abs(int256 val) internal pure returns (uint256) { + return uint256(val < 0 ? -val : val); + } + + /// @dev Takes ceiling of a to m precision + /// @param m represents 1eX where X is the number of trailing 0's + function ceil(uint256 a, uint256 m) internal pure returns (uint256) { + return ((a + m - 1) / m) * m; + } +} diff --git a/src/lib/lyra/README.md b/src/lib/lyra/README.md new file mode 100644 index 0000000..197d370 --- /dev/null +++ b/src/lib/lyra/README.md @@ -0,0 +1,6 @@ +## LYRA +The files in this directories are libraries from the NEWPORT release of Lyra's smart contract suite. + +The commit sha for the contracts is `604d383be4af85c614eded78688dc3ee8c9370c7` + +They are *out of scope* of the audit \ No newline at end of file diff --git a/src/lib/synthetix/DecimalMath.sol b/src/lib/synthetix/DecimalMath.sol new file mode 100644 index 0000000..4f61a5a --- /dev/null +++ b/src/lib/synthetix/DecimalMath.sol @@ -0,0 +1,202 @@ +//SPDX-License-Identifier: MIT +// +//Copyright (c) 2019 Synthetix +// +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files (the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions: +// +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. +// +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. + +pragma solidity 0.8.10; + +/** + * @title DecimalMath + * @author Lyra + * @dev Modified synthetix SafeDecimalMath to include internal arithmetic underflow/overflow. + * @dev https://docs.synthetix.io/contracts/source/libraries/SafeDecimalMath/ + */ + +library DecimalMath { + /* Number of decimal places in the representations. */ + uint8 public constant decimals = 18; + uint8 public constant highPrecisionDecimals = 27; + + /* The number representing 1.0. */ + uint256 public constant UNIT = 10 ** uint256(decimals); + + /* The number representing 1.0 for higher fidelity numbers. */ + uint256 public constant PRECISE_UNIT = 10 ** uint256(highPrecisionDecimals); + uint256 private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10 ** uint256(highPrecisionDecimals - decimals); + + /** + * @return Provides an interface to UNIT. + */ + function unit() external pure returns (uint256) { + return UNIT; + } + + /** + * @return Provides an interface to PRECISE_UNIT. + */ + function preciseUnit() external pure returns (uint256) { + return PRECISE_UNIT; + } + + /** + * @return The result of multiplying x and y, interpreting the operands as fixed-point + * decimals. + * + * @dev A unit factor is divided out after the product of x and y is evaluated, + * so that product must be less than 2**256. As this is an integer division, + * the internal division always rounds down. This helps save on gas. Rounding + * is more expensive on gas. + */ + function multiplyDecimal(uint256 x, uint256 y) internal pure returns (uint256) { + /* Divide by UNIT to remove the extra factor introduced by the product. */ + return (x * y) / UNIT; + } + + /** + * @return The result of safely multiplying x and y, interpreting the operands + * as fixed-point decimals of the specified precision unit. + * + * @dev The operands should be in the form of a the specified unit factor which will be + * divided out after the product of x and y is evaluated, so that product must be + * less than 2**256. + * + * Unlike multiplyDecimal, this function rounds the result to the nearest increment. + * Rounding is useful when you need to retain fidelity for small decimal numbers + * (eg. small fractions or percentages). + */ + function _multiplyDecimalRound(uint256 x, uint256 y, uint256 precisionUnit) private pure returns (uint256) { + /* Divide by UNIT to remove the extra factor introduced by the product. */ + uint256 quotientTimesTen = (x * y) / (precisionUnit / 10); + + if (quotientTimesTen % 10 >= 5) { + quotientTimesTen += 10; + } + + return quotientTimesTen / 10; + } + + /** + * @return The result of safely multiplying x and y, interpreting the operands + * as fixed-point decimals of a precise unit. + * + * @dev The operands should be in the precise unit factor which will be + * divided out after the product of x and y is evaluated, so that product must be + * less than 2**256. + * + * Unlike multiplyDecimal, this function rounds the result to the nearest increment. + * Rounding is useful when you need to retain fidelity for small decimal numbers + * (eg. small fractions or percentages). + */ + function multiplyDecimalRoundPrecise(uint256 x, uint256 y) internal pure returns (uint256) { + return _multiplyDecimalRound(x, y, PRECISE_UNIT); + } + + /** + * @return The result of safely multiplying x and y, interpreting the operands + * as fixed-point decimals of a standard unit. + * + * @dev The operands should be in the standard unit factor which will be + * divided out after the product of x and y is evaluated, so that product must be + * less than 2**256. + * + * Unlike multiplyDecimal, this function rounds the result to the nearest increment. + * Rounding is useful when you need to retain fidelity for small decimal numbers + * (eg. small fractions or percentages). + */ + function multiplyDecimalRound(uint256 x, uint256 y) internal pure returns (uint256) { + return _multiplyDecimalRound(x, y, UNIT); + } + + /** + * @return The result of safely dividing x and y. The return value is a high + * precision decimal. + * + * @dev y is divided after the product of x and the standard precision unit + * is evaluated, so the product of x and UNIT must be less than 2**256. As + * this is an integer division, the result is always rounded down. + * This helps save on gas. Rounding is more expensive on gas. + */ + function divideDecimal(uint256 x, uint256 y) internal pure returns (uint256) { + /* Reintroduce the UNIT factor that will be divided out by y. */ + return (x * UNIT) / y; + } + + /** + * @return The result of safely dividing x and y. The return value is as a rounded + * decimal in the precision unit specified in the parameter. + * + * @dev y is divided after the product of x and the specified precision unit + * is evaluated, so the product of x and the specified precision unit must + * be less than 2**256. The result is rounded to the nearest increment. + */ + function _divideDecimalRound(uint256 x, uint256 y, uint256 precisionUnit) private pure returns (uint256) { + uint256 resultTimesTen = (x * (precisionUnit * 10)) / y; + + if (resultTimesTen % 10 >= 5) { + resultTimesTen += 10; + } + + return resultTimesTen / 10; + } + + /** + * @return The result of safely dividing x and y. The return value is as a rounded + * standard precision decimal. + * + * @dev y is divided after the product of x and the standard precision unit + * is evaluated, so the product of x and the standard precision unit must + * be less than 2**256. The result is rounded to the nearest increment. + */ + function divideDecimalRound(uint256 x, uint256 y) internal pure returns (uint256) { + return _divideDecimalRound(x, y, UNIT); + } + + /** + * @return The result of safely dividing x and y. The return value is as a rounded + * high precision decimal. + * + * @dev y is divided after the product of x and the high precision unit + * is evaluated, so the product of x and the high precision unit must + * be less than 2**256. The result is rounded to the nearest increment. + */ + function divideDecimalRoundPrecise(uint256 x, uint256 y) internal pure returns (uint256) { + return _divideDecimalRound(x, y, PRECISE_UNIT); + } + + /** + * @dev Convert a standard decimal representation to a high precision one. + */ + function decimalToPreciseDecimal(uint256 i) internal pure returns (uint256) { + return i * UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR; + } + + /** + * @dev Convert a high precision decimal to a standard decimal representation. + */ + function preciseDecimalToDecimal(uint256 i) internal pure returns (uint256) { + uint256 quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10); + + if (quotientTimesTen % 10 >= 5) { + quotientTimesTen += 10; + } + + return quotientTimesTen / 10; + } +} diff --git a/src/lib/synthetix/SignedDecimalMath.sol b/src/lib/synthetix/SignedDecimalMath.sol new file mode 100644 index 0000000..992e65b --- /dev/null +++ b/src/lib/synthetix/SignedDecimalMath.sol @@ -0,0 +1,203 @@ +//SPDX-License-Identifier: MIT +// +//Copyright (c) 2019 Synthetix +// +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files (the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions: +// +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. +// +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. + +pragma solidity 0.8.10; + +/** + * @title SignedDecimalMath + * @author Lyra + * @dev Modified synthetix SafeSignedDecimalMath to include internal arithmetic underflow/overflow. + * @dev https://docs.synthetix.io/contracts/source/libraries/safedecimalmath + */ +library SignedDecimalMath { + /* Number of decimal places in the representations. */ + uint8 public constant decimals = 18; + uint8 public constant highPrecisionDecimals = 27; + + /* The number representing 1.0. */ + int256 public constant UNIT = int256(10 ** uint256(decimals)); + + /* The number representing 1.0 for higher fidelity numbers. */ + int256 public constant PRECISE_UNIT = int256(10 ** uint256(highPrecisionDecimals)); + int256 private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = + int256(10 ** uint256(highPrecisionDecimals - decimals)); + + /** + * @return Provides an interface to UNIT. + */ + function unit() external pure returns (int256) { + return UNIT; + } + + /** + * @return Provides an interface to PRECISE_UNIT. + */ + function preciseUnit() external pure returns (int256) { + return PRECISE_UNIT; + } + + /** + * @dev Rounds an input with an extra zero of precision, returning the result without the extra zero. + * Half increments round away from zero; positive numbers at a half increment are rounded up, + * while negative such numbers are rounded down. This behaviour is designed to be consistent with the + * unsigned version of this library (SafeDecimalMath). + */ + function _roundDividingByTen(int256 valueTimesTen) private pure returns (int256) { + int256 increment; + if (valueTimesTen % 10 >= 5) { + increment = 10; + } else if (valueTimesTen % 10 <= -5) { + increment = -10; + } + return (valueTimesTen + increment) / 10; + } + + /** + * @return The result of multiplying x and y, interpreting the operands as fixed-point + * decimals. + * + * @dev A unit factor is divided out after the product of x and y is evaluated, + * so that product must be less than 2**256. As this is an integer division, + * the internal division always rounds down. This helps save on gas. Rounding + * is more expensive on gas. + */ + function multiplyDecimal(int256 x, int256 y) internal pure returns (int256) { + /* Divide by UNIT to remove the extra factor introduced by the product. */ + return (x * y) / UNIT; + } + + /** + * @return The result of safely multiplying x and y, interpreting the operands + * as fixed-point decimals of the specified precision unit. + * + * @dev The operands should be in the form of a the specified unit factor which will be + * divided out after the product of x and y is evaluated, so that product must be + * less than 2**256. + * + * Unlike multiplyDecimal, this function rounds the result to the nearest increment. + * Rounding is useful when you need to retain fidelity for small decimal numbers + * (eg. small fractions or percentages). + */ + function _multiplyDecimalRound(int256 x, int256 y, int256 precisionUnit) private pure returns (int256) { + /* Divide by UNIT to remove the extra factor introduced by the product. */ + int256 quotientTimesTen = (x * y) / (precisionUnit / 10); + return _roundDividingByTen(quotientTimesTen); + } + + /** + * @return The result of safely multiplying x and y, interpreting the operands + * as fixed-point decimals of a precise unit. + * + * @dev The operands should be in the precise unit factor which will be + * divided out after the product of x and y is evaluated, so that product must be + * less than 2**256. + * + * Unlike multiplyDecimal, this function rounds the result to the nearest increment. + * Rounding is useful when you need to retain fidelity for small decimal numbers + * (eg. small fractions or percentages). + */ + function multiplyDecimalRoundPrecise(int256 x, int256 y) internal pure returns (int256) { + return _multiplyDecimalRound(x, y, PRECISE_UNIT); + } + + /** + * @return The result of safely multiplying x and y, interpreting the operands + * as fixed-point decimals of a standard unit. + * + * @dev The operands should be in the standard unit factor which will be + * divided out after the product of x and y is evaluated, so that product must be + * less than 2**256. + * + * Unlike multiplyDecimal, this function rounds the result to the nearest increment. + * Rounding is useful when you need to retain fidelity for small decimal numbers + * (eg. small fractions or percentages). + */ + function multiplyDecimalRound(int256 x, int256 y) internal pure returns (int256) { + return _multiplyDecimalRound(x, y, UNIT); + } + + /** + * @return The result of safely dividing x and y. The return value is a high + * precision decimal. + * + * @dev y is divided after the product of x and the standard precision unit + * is evaluated, so the product of x and UNIT must be less than 2**256. As + * this is an integer division, the result is always rounded down. + * This helps save on gas. Rounding is more expensive on gas. + */ + function divideDecimal(int256 x, int256 y) internal pure returns (int256) { + /* Reintroduce the UNIT factor that will be divided out by y. */ + return (x * UNIT) / y; + } + + /** + * @return The result of safely dividing x and y. The return value is as a rounded + * decimal in the precision unit specified in the parameter. + * + * @dev y is divided after the product of x and the specified precision unit + * is evaluated, so the product of x and the specified precision unit must + * be less than 2**256. The result is rounded to the nearest increment. + */ + function _divideDecimalRound(int256 x, int256 y, int256 precisionUnit) private pure returns (int256) { + int256 resultTimesTen = (x * (precisionUnit * 10)) / y; + return _roundDividingByTen(resultTimesTen); + } + + /** + * @return The result of safely dividing x and y. The return value is as a rounded + * standard precision decimal. + * + * @dev y is divided after the product of x and the standard precision unit + * is evaluated, so the product of x and the standard precision unit must + * be less than 2**256. The result is rounded to the nearest increment. + */ + function divideDecimalRound(int256 x, int256 y) internal pure returns (int256) { + return _divideDecimalRound(x, y, UNIT); + } + + /** + * @return The result of safely dividing x and y. The return value is as a rounded + * high precision decimal. + * + * @dev y is divided after the product of x and the high precision unit + * is evaluated, so the product of x and the high precision unit must + * be less than 2**256. The result is rounded to the nearest increment. + */ + function divideDecimalRoundPrecise(int256 x, int256 y) internal pure returns (int256) { + return _divideDecimalRound(x, y, PRECISE_UNIT); + } + + /** + * @dev Convert a standard decimal representation to a high precision one. + */ + function decimalToPreciseDecimal(int256 i) internal pure returns (int256) { + return i * UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR; + } + + /** + * @dev Convert a high precision decimal to a standard decimal representation. + */ + function preciseDecimalToDecimal(int256 i) internal pure returns (int256) { + int256 quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10); + return _roundDividingByTen(quotientTimesTen); + } +} diff --git a/src/test/HookBidPoolTest.t.sol b/src/test/HookBidPoolTest.t.sol new file mode 100644 index 0000000..aed78f3 --- /dev/null +++ b/src/test/HookBidPoolTest.t.sol @@ -0,0 +1,1062 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.10; + +import "./utils/base.t.sol"; +import "./utils/mocks/PropertyValidator1.sol"; +import "./utils/mocks/PropertyValidatorReverts.sol"; +import "../HookBidPool.sol"; +import "../lib/PoolOrders.sol"; + +import "../mixin/EIP712.sol"; + +contract EIP712Imp is EIP712 { + constructor(address protocol) { + setAddressForEipDomain(protocol); + } + + function hash(bytes32 hash) public view returns (bytes32) { + return _getEIP712Hash(hash); + } +} + +contract BidPoolTest is HookProtocolTest { + HookBidPool bidPool; + + uint256 internal priceSignerPkey; + uint256 internal orderSignerPkey; + uint256 internal bidderPkey; + + address priceSigner; + address orderSigner; + address feeRecipient; + + address bidder; + address seller; + + EIP712Imp eip712; + + // 1% = 0.01, 100 bips = 1%, 10000 bps = 100% == 1 + uint256 constant BPS_TO_DECIMAL = 10e14; + + event PauseUpdated(bool newState); + event FeesUpdated(uint64 feeBips); + event PriceOracleSignerUpdated(address oracle); + event ProtocolFeeRecipientUpdated(address recipient); + event OrderValidityOracleSignerUpdated(address oracle); + event ProtocolAddressSet(address protocol); + + function setUp() public { + setUpAddresses(); + setUpFullProtocol(); + + eip712 = new EIP712Imp(address(protocol)); + + priceSignerPkey = 0xA11CE; + orderSignerPkey = 0xB11CE; + bidderPkey = 0xB0B; + + priceSigner = vm.addr(priceSignerPkey); + orderSigner = vm.addr(orderSignerPkey); + bidder = vm.addr(bidderPkey); + feeRecipient = address(0x8327); + seller = address(0x45); + + bidPool = new HookBidPool(address(weth), admin, priceSigner, orderSigner, 500, feeRecipient, address(protocol)); + vm.prank(address(admin)); + bidPool.setPoolPaused(false); + // add address to the allowlist for minting + vm.prank(address(admin)); + vaultFactory.makeMultiVault(address(token)); + + // Set user balances + vm.deal(address(bidder), 100 ether); + + // Mint underlying token + underlyingTokenId = 0; + token.mint(address(seller), underlyingTokenId); + + // Buyer swap 50 ETH <> 50 WETH + vm.prank(address(bidder)); + weth.deposit{value: 50 ether}(); + + // Seller approve ERC721TransferHelper + vm.prank(address(seller)); + token.setApprovalForAll(address(calls), true); + vm.prank(address(seller)); + calls.setApprovalForAll(address(bidPool), true); + + // Buyer approve the bid pool to bid + vm.prank(address(bidder)); + weth.approve(address(bidPool), 50 ether); + } + + function testDeployerCannotChangeRoles() public { + // make sure the background admin cannot change roles + vm.stopPrank(); + bytes32 pauser = bidPool.PAUSER_ROLE(); + vm.expectRevert(); + bidPool.grantRole(pauser, address(0)); + + bytes32 oracle = bidPool.ORACLE_ROLE(); + vm.expectRevert(); + bidPool.grantRole(oracle, address(0)); + + bytes32 protocol = bidPool.PROTOCOL_ROLE(); + vm.expectRevert(); + bidPool.grantRole(protocol, address(0)); + + bytes32 fees = bidPool.FEES_ROLE(); + vm.expectRevert(); + bidPool.grantRole(fees, address(0)); + } + + function testSetProtocol() public { + vm.startPrank(address(admin)); + // deploy a new protocol + + HookProtocol protocol2 = new HookProtocol( + admin, + admin, + admin, + admin, + admin, + admin, + address(weth) + ); + + vm.expectEmit(true, true, true, true); + emit ProtocolAddressSet(address(protocol2)); + bidPool.setProtocol(address(protocol2)); + } + + function testSetProtocolNotOwner() public { + // deploy a new protocol + HookProtocol protocol2 = new HookProtocol( + admin, + admin, + admin, + admin, + admin, + admin, + address(weth) + ); + + vm.startPrank(bidder); + vm.expectRevert(); + emit ProtocolAddressSet(address(protocol2)); + bidPool.setProtocol(address(protocol2)); + } + + function testSetPriceOracleSigner() public { + address newSigner = address(0x1234); + vm.startPrank(admin); + vm.expectEmit(true, true, true, true); + emit PriceOracleSignerUpdated(newSigner); + bidPool.setPriceOracleSigner(newSigner); + } + + function testSetPriceOracleSignerNotOwner() public { + address newSigner = address(0x1234); + vm.startPrank(bidder); + vm.expectRevert(); + emit PriceOracleSignerUpdated(newSigner); + bidPool.setPriceOracleSigner(newSigner); + } + + function testSetOrderValidityOracleSigner() public { + address newSigner = address(0x1234); + vm.expectEmit(true, true, true, true); + emit OrderValidityOracleSignerUpdated(newSigner); + vm.startPrank(admin); + bidPool.setOrderValidityOracleSigner(newSigner); + } + + function testSetOrderValidityOracleSignerNotOwner() public { + address newSigner = address(0x1234); + vm.startPrank(bidder); + vm.expectRevert(); + emit OrderValidityOracleSignerUpdated(newSigner); + bidPool.setOrderValidityOracleSigner(newSigner); + } + + function testSetFeeBips() public { + uint64 newBips = 3737; + vm.prank(address(admin)); + vm.expectEmit(true, true, true, true); + emit FeesUpdated(newBips); + bidPool.setFeeBips(newBips); + } + + function testSetFeeBipsNotOwner() public { + uint64 newBips = 3737; + vm.startPrank(bidder); + vm.expectRevert(); + emit FeesUpdated(newBips); + bidPool.setFeeBips(newBips); + } + + function testSetFeeBipsOverLimit() public { + uint64 newBips = 10001; + vm.expectRevert("Fee bips over 10000"); + emit FeesUpdated(newBips); + vm.prank(address(admin)); + bidPool.setFeeBips(newBips); + } + + function testSetFeeRecipient() public { + address newRecipient = address(0x1234); + vm.expectEmit(true, true, true, true); + emit ProtocolFeeRecipientUpdated(newRecipient); + vm.prank(address(admin)); + bidPool.setFeeRecipient(newRecipient); + } + + function testSetFeeRecipientNotOwner() public { + address newRecipient = address(0x1234); + vm.startPrank(bidder); + vm.expectRevert(); + emit ProtocolFeeRecipientUpdated(newRecipient); + bidPool.setFeeRecipient(newRecipient); + } + + function testSetProtocolPaused() public { + vm.startPrank(address(admin)); + vm.expectEmit(true, true, true, true); + emit PauseUpdated(true); + bidPool.setPoolPaused(true); + } + + function testSetProtocolPausedNotOwner() public { + vm.startPrank(bidder); + vm.expectRevert(); + emit PauseUpdated(true); + bidPool.setPoolPaused(true); + } + + function testSetProtocolPausedAlreadyPaused() public { + vm.startPrank(address(admin)); + vm.expectEmit(true, true, true, true); + emit PauseUpdated(true); + bidPool.setPoolPaused(true); + vm.expectRevert("cannot set to current state"); + bidPool.setPoolPaused(true); + } + + function testSetProtocolPausedAlreadyNotPaused() public { + vm.expectRevert("cannot set to current state"); + vm.prank(address(admin)); + bidPool.setPoolPaused(false); + } + + function testBS() public { + (uint256 call, uint256 put) = BlackScholes.optionPrices( + BlackScholes.BlackScholesInputs({ + timeToExpirySec: 1209600, // seconds in 2 weeks + volatilityDecimal: 700000000000000000, // 0.70 + spotDecimal: 10000000000000000000, // 10 + strikePriceDecimal: 12000000000000000000, // 12 + rateDecimal: 50000000000000000 // 0.05 + }) + ); + + assertEq(call, 65919925077818231, "call price should be ~.065"); + assertEq(put, 2042928280277283091, "bs should be 0"); + } + + function _signOrder(PoolOrders.Order memory order, uint256 pkey) + internal + returns (Signatures.Signature memory, bytes32 hash) + { + bytes32 hash = PoolOrders.getPoolOrderStructHash(order); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(pkey, eip712.hash(hash)); + return ( + Signatures.Signature({v: v, r: r, s: s, signatureType: Signatures.SignatureType.EIP712}), eip712.hash(hash) + ); + } + + function _makeAssetPriceClaim(uint256 assetPrice) internal returns (HookBidPool.AssetPriceClaim memory) { + HookBidPool.AssetPriceClaim memory claim = HookBidPool.AssetPriceClaim({ + assetPriceInWei: assetPrice, + priceObservedTimestamp: uint32(block.timestamp) - 30 seconds, + goodTilTimestamp: uint32(block.timestamp) + 20 days, + v: 0, + r: 0, + s: 0 + }); + + (uint8 va, bytes32 ar, bytes32 sa) = vm.sign( + priceSignerPkey, + keccak256( + abi.encodePacked( + "\x19Ethereum Signed Message:\n32", + keccak256(abi.encode(claim.assetPriceInWei, claim.priceObservedTimestamp, claim.goodTilTimestamp)) + ) + ) + ); + + claim.v = va; + claim.r = ar; + claim.s = sa; + return claim; + } + + function _makeInvalidAssetPriceClaim(uint256 assetPrice) internal returns (HookBidPool.AssetPriceClaim memory) { + HookBidPool.AssetPriceClaim memory claim = HookBidPool.AssetPriceClaim({ + assetPriceInWei: assetPrice, + priceObservedTimestamp: uint32(block.timestamp) - 30 seconds, + goodTilTimestamp: uint32(block.timestamp) + 20 days, + v: 0, + r: 0, + s: 0 + }); + + (uint8 va, bytes32 ar, bytes32 sa) = vm.sign( + bidderPkey, + keccak256( + abi.encodePacked( + "\x19Ethereum Signed Message:\n32", + keccak256(abi.encode(claim.assetPriceInWei, claim.priceObservedTimestamp, claim.goodTilTimestamp)) + ) + ) + ); + + claim.v = va; + claim.r = ar; + claim.s = sa; + return claim; + } + + function _makeDefaultOrder() internal returns (PoolOrders.Order memory) { + PoolOrders.Property[] memory properties; + return PoolOrders.Order({ + direction: PoolOrders.OrderDirection.BUY, + maker: bidder, + orderExpiry: uint32(block.timestamp) + 2 weeks, + nonce: 1405, + size: 1, + optionType: PoolOrders.OptionType.CALL, + maxStrikePriceMultiple: 0, + minOptionDuration: 1 days, + maxOptionDuration: 80 days, + maxPriceSignalAge: 0, + optionMarketAddress: address(calls), + impliedVolBips: 5000, + nftProperties: properties, + skewDecimal: 0, + riskFreeRateBips: 500 + }); + } + + function _makeOrderClaim(bytes32 orderHash) internal returns (HookBidPool.OrderValidityOracleClaim memory) { + bytes memory claimEncoded = abi.encode(orderHash, block.timestamp + 30); + + bytes32 claimHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", keccak256(claimEncoded))); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(orderSignerPkey, claimHash); + + return HookBidPool.OrderValidityOracleClaim({ + v: v, + r: r, + s: s, + orderHash: orderHash, + goodTilTimestamp: uint32(block.timestamp) + 30 + }); + } + + function _makeInvalidOrderClaim(bytes32 orderHash) internal returns (HookBidPool.OrderValidityOracleClaim memory) { + bytes memory claimEncoded = abi.encode(orderHash, block.timestamp + 30); + + bytes32 claimHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", keccak256(claimEncoded))); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(bidderPkey, claimHash); + + return HookBidPool.OrderValidityOracleClaim({ + v: v, + r: r, + s: s, + orderHash: orderHash, + goodTilTimestamp: uint32(block.timestamp) + 30 + }); + } + + function testAcceptBid() public { + vm.warp(block.timestamp + 20 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + assertTrue(calls.ownerOf(optionId) == address(seller), "owner should own the option"); + + PoolOrders.Order memory order = _makeDefaultOrder(); + + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + uint256 initialBalanceBidder = weth.balanceOf(address(bidder)); + uint256 initialBalanceSeller = weth.balanceOf(address(seller)); + uint256 initialBalanceFeeRecipient = weth.balanceOf(address(feeRecipient)); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + + uint256 finalBalanceBidder = weth.balanceOf(bidder); + uint256 finalBalanceSeller = weth.balanceOf(seller); + uint256 finalBalanceFeeRecipient = weth.balanceOf(address(feeRecipient)); + + assertEq( + finalBalanceFeeRecipient, + initialBalanceFeeRecipient + 0.0005 ether, + "fee recipient should have received the 500 bps fee" + ); + assertEq(finalBalanceBidder, initialBalanceBidder - 0.0105 ether, "bidder should have paid the premium"); + assertEq(finalBalanceSeller, initialBalanceSeller + 0.01 ether, "seller should have received the premium"); + assertTrue(calls.ownerOf(optionId) == address(bidder), "bidder should own the option"); + } + + function testBidTooLow() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + + order.impliedVolBips = 5; // set a very low vol for the order + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.expectRevert("order not high enough for the ask"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testOrderExpired() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 90 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.warp(block.timestamp + 3 weeks); // 1 week after order expiry + + vm.expectRevert("Order is expired"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testNotBuyOrder() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 90 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Property[] memory properties; + PoolOrders.Order memory order = PoolOrders.Order({ + direction: PoolOrders.OrderDirection.SELL, + maker: bidder, + orderExpiry: uint32(block.timestamp) + 2 weeks, + nonce: 1405, + size: 1, + optionType: PoolOrders.OptionType.CALL, + maxStrikePriceMultiple: 0, + minOptionDuration: 1 days, + maxOptionDuration: 80 days, + maxPriceSignalAge: 0, + optionMarketAddress: address(calls), + impliedVolBips: 5000, + nftProperties: properties, + skewDecimal: 0, + riskFreeRateBips: 500 + }); + + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.expectRevert("Order is not a buy order"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testOptionExpired() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 2 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + vm.warp(block.timestamp + 1 days + 1 hours); // warp to within 1 day of expiry + + PoolOrders.Order memory order = _makeDefaultOrder(); + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.expectRevert("Option is too close to expiry"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testOptionTooCloseToExpiry() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 90 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + // Max option duration is 80 days + + PoolOrders.Order memory order = _makeDefaultOrder(); + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.expectRevert("Option is too far from expiry"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testOptionTooFarFromExpiry() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 90 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + // Max option duration is 80 days + + PoolOrders.Order memory order = _makeDefaultOrder(); + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.expectRevert("Option is too far from expiry"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testAcceptSkewedBidDefaultBidTooLow() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + + order.impliedVolBips = 1500; // set a low vol (15%) for order + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.expectRevert("order not high enough for the ask"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + + order.skewDecimal = 25000 * BPS_TO_DECIMAL; // will increase vol to 20% + (signature, orderHash) = _signOrder(order, bidderPkey); + + uint256 initialBalanceBidder = weth.balanceOf(address(bidder)); + uint256 initialBalanceSeller = weth.balanceOf(address(seller)); + uint256 initialBalanceFeeRecipient = weth.balanceOf(address(feeRecipient)); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + uint256 finalBalanceBidder = weth.balanceOf(bidder); + uint256 finalBalanceSeller = weth.balanceOf(seller); + uint256 finalBalanceFeeRecipient = weth.balanceOf(address(feeRecipient)); + + assertEq( + finalBalanceFeeRecipient, + initialBalanceFeeRecipient + 0.0005 ether, + "fee recipient should have received the 500 bps fee" + ); + assertEq(finalBalanceBidder, initialBalanceBidder - 0.0105 ether, "bidder should have paid the premium"); + assertEq(finalBalanceSeller, initialBalanceSeller + 0.01 ether, "seller should have received the premium"); + assertTrue(calls.ownerOf(optionId) == address(bidder), "bidder should own the option"); + } + + function testBidTooLowWithFees() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + + order.impliedVolBips = 1820; // set a very low vol for the order + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.expectRevert("order not high enough for the ask"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + + vm.stopPrank(); + vm.prank(admin); + bidPool.setFeeBips(0); + + // should work with no fees + vm.prank(seller); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testOptionDurationTooShort() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + order.minOptionDuration = 10 days; + + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.expectRevert("Option is too close to expiry"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testOptionDurationTooFar() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 50 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + order.maxOptionDuration = 10 days; + + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.expectRevert("Option is too far from expiry"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testPriceSignalTooOld() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 50 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + order.maxPriceSignalAge = 10; + + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.expectRevert("Price signal is too old"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testStrikeTooHigh() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 50 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.4 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + order.maxStrikePriceMultiple = 5 * 10e17; + + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.expectRevert("option is too far out of the money"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.1 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.35 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testOrderIsCanceled() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 50 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.4 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.stopPrank(); + vm.prank(bidder); + bidPool.cancelOrder(order); + + vm.prank(seller); + vm.expectRevert("Order is cancelled"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.3 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testOrderSize() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 50 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.4 ether, expiration); + token.mint(address(seller), underlyingTokenId + 1); + uint256 optionId1 = calls.mintWithErc721(address(token), underlyingTokenId + 1, 0.4 ether, expiration); + token.mint(address(seller), underlyingTokenId + 2); + uint256 optionId2 = calls.mintWithErc721(address(token), underlyingTokenId + 2, 0.4 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + order.size = 2; + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.3 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.29 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId1 + ); + + vm.expectRevert("Order is filled"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.3 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId1 + ); + } + + function testInvalidSignature() public { + vm.warp(block.timestamp + 1 days); + vm.mockCall( + address(0x00000000000076A84feF008CDAbe6409d2FE638B), + abi.encodeWithSelector( + IDelegationRegistry.checkDelegateForContract.selector, + address(priceSigner), + address(bidder), + address(bidPool) + ), + abi.encode(false) + ); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, priceSignerPkey); + + vm.expectRevert("Order signature is invalid"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testValidDelegate() public { + vm.warp(block.timestamp + 1 days); + vm.mockCall( + address(0x00000000000076A84feF008CDAbe6409d2FE638B), + abi.encodeWithSelector( + IDelegationRegistry.checkDelegateForContract.selector, + address(priceSigner), + address(bidder), + address(bidPool) + ), + abi.encode(true) + ); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, priceSignerPkey); + + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testNotSignedByOrderValidityOracle() public { + vm.warp(block.timestamp + 1 days); + vm.mockCall( + address(0x00000000000076A84feF008CDAbe6409d2FE638B), + abi.encodeWithSelector( + IDelegationRegistry.checkDelegateForContract.selector, + address(priceSigner), + address(bidder), + address(bidPool) + ), + abi.encode(true) + ); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, priceSignerPkey); + + vm.expectRevert("Claim is not signed by the orderValidityOracle"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeInvalidOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testNotSignedByPriceOracle() public { + vm.warp(block.timestamp + 1 days); + vm.mockCall( + address(0x00000000000076A84feF008CDAbe6409d2FE638B), + abi.encodeWithSelector( + IDelegationRegistry.checkDelegateForContract.selector, + address(priceSigner), + address(bidder), + address(bidPool) + ), + abi.encode(true) + ); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, priceSignerPkey); + + vm.expectRevert("Claim is not signed by the priceOracle"); + bidPool.sellOption( + order, + signature, + _makeInvalidAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testExpiredOrderValidityOracleSignature() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + HookBidPool.OrderValidityOracleClaim memory claim = _makeOrderClaim(orderHash); + + vm.warp(block.timestamp + 1 days); + vm.expectRevert("Claim is expired"); + bidPool.sellOption( + order, signature, _makeAssetPriceClaim(0.2 ether), claim, 0.01 ether, address(calls), optionId + ); + } + + function testPropertyValidatorReverts() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + + IPropertyValidator validator = new PropertyValidatorReverts(); + order.nftProperties = new PoolOrders.Property[](1); + order.nftProperties[0] = PoolOrders.Property(validator, abi.encodePacked()); + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + vm.expectRevert("Property validation failed for the provided optionId"); + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + } + + function testPropertyValidatorSuccess() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + + IPropertyValidator validator = new PropertyValidator1(); + order.nftProperties = new PoolOrders.Property[](1); + order.nftProperties[0] = PoolOrders.Property( + validator, abi.encode(0, Types.Operation.Ignore, 0, Types.Operation.Ignore, false, 0, 0) + ); + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + + assertEq(calls.ownerOf(optionId), address(bidder), "Option should be transferred to the bidder"); + } + + function testPropertyValidatorSuccessNullValidator() public { + vm.warp(block.timestamp + 1 days); + vm.startPrank(address(seller)); + uint32 expiration = uint32(block.timestamp) + 5 days; + uint256 optionId = calls.mintWithErc721(address(token), underlyingTokenId, 0.22 ether, expiration); + + PoolOrders.Order memory order = _makeDefaultOrder(); + + address validator = address(0x0); + order.nftProperties = new PoolOrders.Property[](1); + order.nftProperties[0] = PoolOrders.Property( + IPropertyValidator(validator), abi.encode(0, Types.Operation.Ignore, 0, Types.Operation.Ignore, false, 0, 0) + ); + (Signatures.Signature memory signature, bytes32 orderHash) = _signOrder(order, bidderPkey); + + bidPool.sellOption( + order, + signature, + _makeAssetPriceClaim(0.2 ether), + _makeOrderClaim(orderHash), + 0.01 ether, + address(calls), + optionId + ); + + assertEq(calls.ownerOf(optionId), address(bidder), "Option should be transferred to the bidder"); + } +} diff --git a/src/test/utils/mocks/PropertyValidator1.sol b/src/test/utils/mocks/PropertyValidator1.sol new file mode 100644 index 0000000..c65d4dd --- /dev/null +++ b/src/test/utils/mocks/PropertyValidator1.sol @@ -0,0 +1,79 @@ +pragma solidity ^0.8.10; + +import "../../../HookCoveredCallImplV1.sol"; +import "../../../interfaces/IHookERC721Vault.sol"; +import "../../../interfaces/zeroex-v4/IPropertyValidator.sol"; + +library Types { + enum Operation { + Ignore, + LessThanOrEqualTo, + GreaterThanOrEqualTo, + Equal + } +} + +contract PropertyValidator1 is IPropertyValidator { + function validateProperty(address tokenAddress, uint256 tokenId, bytes calldata propertyData) + external + view + override + { + ( + uint256 strikePrice, + Types.Operation strikePriceOperation, + uint256 expiry, + Types.Operation expiryOperation, + bool withinRange, + uint256 tokenIdLow, + uint256 tokenIdHigh + ) = abi.decode(propertyData, (uint256, Types.Operation, uint256, Types.Operation, bool, uint256, uint256)); + + HookCoveredCallImplV1 optionContract = HookCoveredCallImplV1(tokenAddress); + + compare(optionContract.getStrikePrice(tokenId), strikePrice, strikePriceOperation); + + if (withinRange) { + uint32 assetId = optionContract.getAssetId(tokenId); + if (assetId > 0) { + /// if the assetId is non-zero, we know that this asset is + /// within a multivault and we can simply get the data from the call + ensureInRange(assetId, tokenIdLow, tokenIdHigh); + } else { + IHookERC721Vault vault = IHookERC721Vault(optionContract.getVaultAddress(tokenId)); + ensureInRange(vault.assetTokenId(assetId), tokenIdLow, tokenIdHigh); + } + } + + compare(optionContract.getExpiration(tokenId), expiry, expiryOperation); + } + + function ensureInRange(uint256 tokenId, uint256 lowerBound, uint256 upperBound) internal pure { + require(tokenId >= lowerBound, "tokenId must be above the lower bound"); + require(tokenId <= upperBound, "tokenId must be below the upper bound"); + } + + function compare(uint256 actual, uint256 comparingTo, Types.Operation operation) internal pure { + if (operation == Types.Operation.Equal) { + require(actual == comparingTo, "values are not equal"); + } else if (operation == Types.Operation.LessThanOrEqualTo) { + require(actual <= comparingTo, "actual value is not <= comparison value"); + } else if (operation == Types.Operation.GreaterThanOrEqualTo) { + require(actual >= comparingTo, "actual value is not >= comparison value"); + } + } + + function encode( + uint256 strikePrice, + Types.Operation strikePriceOperation, + uint256 expiry, + Types.Operation expiryOperation, + bool withinRange, + uint256 tokenIdLow, + uint256 tokenIdHigh + ) external pure returns (bytes memory) { + return abi.encode( + strikePrice, strikePriceOperation, expiry, expiryOperation, withinRange, tokenIdLow, tokenIdHigh + ); + } +} diff --git a/src/test/utils/mocks/PropertyValidatorReverts.sol b/src/test/utils/mocks/PropertyValidatorReverts.sol new file mode 100644 index 0000000..1b83b7a --- /dev/null +++ b/src/test/utils/mocks/PropertyValidatorReverts.sol @@ -0,0 +1,13 @@ +pragma solidity ^0.8.10; + +import "../../../interfaces/zeroex-v4/IPropertyValidator.sol"; + +contract PropertyValidatorReverts is IPropertyValidator { + function validateProperty(address tokenAddress, uint256 tokenId, bytes calldata propertyData) + external + view + override + { + revert("PropertyValidator: BAD PROPERTIES"); + } +}