From b01b4e1c06b4fcb48736f3fdacf224dc0d86a242 Mon Sep 17 00:00:00 2001 From: geleeroyale Date: Thu, 15 Aug 2019 12:15:00 +0200 Subject: [PATCH] Create CNAME Update CNAME Delete CNAME Create CNAME Delete CNAME Create CNAME Delete CNAME Create CNAME Delete CNAME Create CNAME Delete CNAME Create CNAME Delete CNAME Create CNAME Update CNAME Create README.md try to get it to rebuild Update CNAME Update README.md Delete CNAME Create CNAME Delete CNAME Create CNAME Delete CNAME Create CNAME Delete CNAME Create CNAME Delete CNAME Create CNAME Delete CNAME Create CNAME Delete CNAME Updates --- asset-manifest.json | 6 +++--- index.html | 2 +- ... precache-manifest.73cf56db2c1f876f583bd4f7e0c881d1.js | 8 ++++---- service-worker.js | 2 +- static/js/main.289bb85e.chunk.js | 2 -- static/js/main.289bb85e.chunk.js.map | 1 - static/js/main.5d956bc1.chunk.js | 2 ++ static/js/main.5d956bc1.chunk.js.map | 1 + 8 files changed, 12 insertions(+), 12 deletions(-) rename precache-manifest.43cf2b484add9c6a2fe7c637ffe770f2.js => precache-manifest.73cf56db2c1f876f583bd4f7e0c881d1.js (69%) delete mode 100644 static/js/main.289bb85e.chunk.js delete mode 100644 static/js/main.289bb85e.chunk.js.map create mode 100644 static/js/main.5d956bc1.chunk.js create mode 100644 static/js/main.5d956bc1.chunk.js.map diff --git a/asset-manifest.json b/asset-manifest.json index fc036a9..6e19e10 100644 --- a/asset-manifest.json +++ b/asset-manifest.json @@ -1,14 +1,14 @@ { "files": { "main.css": "/augmented-tbc-design/static/css/main.ed579467.chunk.css", - "main.js": "/augmented-tbc-design/static/js/main.289bb85e.chunk.js", - "main.js.map": "/augmented-tbc-design/static/js/main.289bb85e.chunk.js.map", + "main.js": "/augmented-tbc-design/static/js/main.5d956bc1.chunk.js", + "main.js.map": "/augmented-tbc-design/static/js/main.5d956bc1.chunk.js.map", "runtime~main.js": "/augmented-tbc-design/static/js/runtime~main.e0588710.js", "runtime~main.js.map": "/augmented-tbc-design/static/js/runtime~main.e0588710.js.map", "static/js/2.dc6af9b8.chunk.js": "/augmented-tbc-design/static/js/2.dc6af9b8.chunk.js", "static/js/2.dc6af9b8.chunk.js.map": "/augmented-tbc-design/static/js/2.dc6af9b8.chunk.js.map", "index.html": "/augmented-tbc-design/index.html", - "precache-manifest.43cf2b484add9c6a2fe7c637ffe770f2.js": "/augmented-tbc-design/precache-manifest.43cf2b484add9c6a2fe7c637ffe770f2.js", + "precache-manifest.73cf56db2c1f876f583bd4f7e0c881d1.js": "/augmented-tbc-design/precache-manifest.73cf56db2c1f876f583bd4f7e0c881d1.js", "service-worker.js": "/augmented-tbc-design/service-worker.js", "static/css/main.ed579467.chunk.css.map": "/augmented-tbc-design/static/css/main.ed579467.chunk.css.map" } diff --git a/index.html b/index.html index 105c4b7..37a1ef9 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -Augmented Bonding Curve Design
\ No newline at end of file +Augmented Bonding Curve Design
\ No newline at end of file diff --git a/precache-manifest.43cf2b484add9c6a2fe7c637ffe770f2.js b/precache-manifest.73cf56db2c1f876f583bd4f7e0c881d1.js similarity index 69% rename from precache-manifest.43cf2b484add9c6a2fe7c637ffe770f2.js rename to precache-manifest.73cf56db2c1f876f583bd4f7e0c881d1.js index 40dbe0a..8a6943a 100644 --- a/precache-manifest.43cf2b484add9c6a2fe7c637ffe770f2.js +++ b/precache-manifest.73cf56db2c1f876f583bd4f7e0c881d1.js @@ -1,10 +1,10 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([ { - "revision": "4aed024c8a3715d778f0573eb1f01069", + "revision": "23b33394c0cee292617a928bff612e8e", "url": "/augmented-tbc-design/index.html" }, { - "revision": "9097c0a58c77d0491db0", + "revision": "84383d682203fd444916", "url": "/augmented-tbc-design/static/css/main.ed579467.chunk.css" }, { @@ -12,8 +12,8 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([ "url": "/augmented-tbc-design/static/js/2.dc6af9b8.chunk.js" }, { - "revision": "9097c0a58c77d0491db0", - "url": "/augmented-tbc-design/static/js/main.289bb85e.chunk.js" + "revision": "84383d682203fd444916", + "url": "/augmented-tbc-design/static/js/main.5d956bc1.chunk.js" }, { "revision": "bbaf5adc59b3ad16792b", diff --git a/service-worker.js b/service-worker.js index 7d8cabd..66faefa 100644 --- a/service-worker.js +++ b/service-worker.js @@ -14,7 +14,7 @@ importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); importScripts( - "/augmented-tbc-design/precache-manifest.43cf2b484add9c6a2fe7c637ffe770f2.js" + "/augmented-tbc-design/precache-manifest.73cf56db2c1f876f583bd4f7e0c881d1.js" ); self.addEventListener('message', (event) => { diff --git a/static/js/main.289bb85e.chunk.js b/static/js/main.289bb85e.chunk.js deleted file mode 100644 index dcb1329..0000000 --- a/static/js/main.289bb85e.chunk.js +++ /dev/null @@ -1,2 +0,0 @@ -(window["webpackJsonpaugmented-tbc-design"]=window["webpackJsonpaugmented-tbc-design"]||[]).push([[0],{216:function(e,t,a){e.exports=a(408)},406:function(e,t,a){},407:function(e,t,a){},408:function(e,t,a){"use strict";a.r(t);var n=a(1),r=a.n(n),i=a(14),o=a.n(i),c=a(448),l=a(447),s=a(63),u=a.n(s),m=a(114),d=a(4),p=a(409),f=a(454),h=a(446),g=a(410),b=a(450),v=a(444),x=a(445),E=a(452),y=a(443),O="https://medium.com/giveth/deep-dive-augmented-bonding-curves-3f1f7c1fa751",k=Object(p.a)(function(e){return Object(f.a)({container:{display:"flex",flexDirection:"column",alignItems:"center"},title:{},subtitle:{color:e.palette.text.secondary,margin:e.spacing(3,0,0),maxWidth:e.spacing(82)},subsubtitle:{color:e.palette.text.secondary,opacity:.6,maxWidth:e.spacing(74)},lightBulb:{verticalAlign:"middle",marginRight:e.spacing(1)},link:{color:e.palette.primary.main},logoContainer:{display:"flex",alignItems:"center",justifyContent:"center",marginBottom:e.spacing(4)},logo:{width:"25px",marginRight:"4px"},logoText:{display:"inline",fontSize:"1.1rem",fontWeight:500}})});function j(){var e=k();return r.a.createElement("div",{className:e.container},r.a.createElement("div",{className:e.logoContainer},r.a.createElement("img",{src:"./favicon.ico",className:e.logo,alt:"logo"}),r.a.createElement(g.a,{className:e.logoText},"Commons Stack")),r.a.createElement(g.a,{className:e.title,variant:"h4"},"Augmented Bonding Curve Design"),r.a.createElement(g.a,{className:e.subtitle},"Experiment with the Commons Stack Augmented Bonding Curve component. Customize the hatch variables and explore the continuous funding results for your community."),r.a.createElement(g.a,{className:e.subsubtitle},"Read more about the Augmented Bonding Curve"," ",r.a.createElement(y.a,{href:O},"here"),". Note that this is a demo for illustration purposes only, a narrative showcase of cadCAD's capabilities."))}var C=a(12),w=a(3),N=a(449),B=a(81),S=a.n(B),F=a(8),P=a(453),R=Object(F.a)({root:{height:8},thumb:{height:24,width:24,backgroundColor:"#fff",border:"2px solid currentColor",marginTop:-8,marginLeft:-12,"&:focus,&:hover,&$active":{boxShadow:"inherit"}},active:{},valueLabel:{left:"calc(-50% + 4px)"},track:{height:8,borderRadius:4},rail:{height:8,borderRadius:4},markLabel:{top:30}})(P.a),A=a(451),T=Object(p.a)(function(e){var t;return{container:{color:e.palette.text.secondary,display:"flex",fontSize:"0.9rem",cursor:"pointer",transition:"color ease 150ms","&:hover":{color:"#c3c9d0"}},popoverContainer:{padding:e.spacing(2),"& > p:not(:last-child)":{paddingBottom:e.spacing(1),marginBottom:e.spacing(1),borderBottom:"1px solid #3f5463"}},paper:(t={backgroundColor:"#384b59",maxWidth:.9*e.breakpoints.values.md},Object(C.a)(t,"@media screen and (max-width: ".concat(e.breakpoints.values.md,"px)"),{maxWidth:"90vw"}),Object(C.a)(t,"padding",e.spacing(.5)),t),descriptionBody:{color:"#dbdfe4"}}});function I(e){var t=e.content,a=e.popoverText,n=T(),i=r.a.useState(null),o=Object(d.a)(i,2),c=o[0],l=o[1];function s(){l(null)}var u=Boolean(c),m=u?"simple-popover":void 0;return r.a.createElement("div",{className:n.container},r.a.createElement("div",{"aria-describedby":m,onClick:function(e){l(e.currentTarget)}},r.a.createElement(g.a,null,t)),r.a.createElement(A.a,{PaperProps:{className:n.paper},id:m,open:u,anchorEl:c,onClose:s,onClick:s,anchorOrigin:{vertical:"bottom",horizontal:"center"},transformOrigin:{vertical:"top",horizontal:"center"}},r.a.createElement(b.a,{className:n.popoverContainer},r.a.createElement(g.a,null,t),r.a.createElement(g.a,{className:n.descriptionBody},a))))}var M=Object(p.a)(function(e){return Object(f.a)({root:{margin:e.spacing(6,0,3)},lightBulb:{verticalAlign:"middle",marginRight:e.spacing(1)},leftContainer:{color:e.palette.text.secondary},centerContainer:{},listBoxContainer:{"& > div:not(:last-child)":{paddingBottom:"12px",marginBottom:"12px",borderBottom:"1px solid #313d47"}},listBox:{"& > div":{display:"flex",alignItems:"center","& p":{marginBottom:0}},"& > div:not(:last-child)":{paddingRight:"12px"}},slider:{color:e.palette.primary.main}})});function D(e){var t=e.inputRef,a=e.onChange,n=e.prefix,i=e.suffix,o=Object(w.a)(e,["inputRef","onChange","prefix","suffix"]);return r.a.createElement(S.a,Object.assign({},o,{getInputRef:t,onValueChange:function(e){a({target:{value:e.value}})},thousandSeparator:!0,prefix:n,suffix:i}))}function H(e){var t=e.inputFields,a=e.onChangeCommited,n=M();return r.a.createElement("div",{className:n.listBoxContainer},t.map(function(e){var t=e.label,i=e.description,o=e.value,c=e.setter,l=e.min,s=e.max,u=e.step,m=e.prefix,d=e.suffix,p=e.format,f=e.toText,h=e.toNum;function g(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;isNaN(e)&&(e=0),e>s?e=s:ee*N&&b(e*N)},min:.01,max:1,step:.01,toText:function(e){return String(+e.toFixed(2))},toNum:function(e){return parseFloat(e)},format:function(e){return"$".concat(e)}},{label:"".concat(V.p1.name," (DAI/token)"),description:V.p1.text,value:g,setter:b,min:Number((B*(m||.1)).toFixed(2)),max:Number((N*m).toFixed(2)),step:.01,toText:function(e){return String(+e.toFixed(2))},toNum:function(e){return parseFloat(e)},format:function(e){return"$".concat(e)}},{label:V.wFee.name,description:V.wFee.text,value:E,setter:y,min:0,max:.1,step:.001,suffix:"%",format:function(e){return"".concat(+(100*e).toFixed(1),"%")},toText:function(e){return String(+(100*e).toFixed(1))},toNum:function(e){return.01*parseFloat(e)}},{label:"".concat(V.vHalflife.name," (weeks)"),description:V.vHalflife.text,value:j,setter:w,min:1,max:104,step:1,suffix:"",format:function(e){return String(Math.round(e))},toText:function(e){return String(Math.round(e))},toNum:function(e){return Math.round(parseInt(e))}}];return r.a.createElement(H,{inputFields:S,onChangeCommited:function(){a(function(e){return function(e){for(var t=1;t div:not(:last-child)":{paddingBottom:e.spacing(1),marginBottom:e.spacing(1),borderBottom:"1px solid #3f5463"},"& td":{verticalAlign:"top",padding:e.spacing(.5)}},descriptionTitle:{padding:e.spacing(.5)},descriptionBody:{color:"#dbdfe4",padding:e.spacing(.5)},descriptionPadding:{padding:e.spacing(.5)}}});function Q(e){var t=e.text,a=e.title,n=e.table,i=e.body,o=U(),c=r.a.useState(null),l=Object(d.a)(c,2),s=l[0],u=l[1];function m(){u(null)}var p=Boolean(s),f=p?"simple-popover":void 0;return r.a.createElement("div",{className:o.container},r.a.createElement(J.a,{onClick:function(e){u(e.currentTarget)}}),r.a.createElement(A.a,{PaperProps:{className:o.paper},id:f,open:p,anchorEl:s,onClose:m,onClick:m,anchorOrigin:{vertical:"bottom",horizontal:"center"},transformOrigin:{vertical:"top",horizontal:"center"}},r.a.createElement(b.a,{className:o.popoverContainer},r.a.createElement("div",{className:o.descriptionContainer},a&&r.a.createElement("div",null,r.a.createElement(g.a,{className:o.descriptionTitle},a)),i&&r.a.createElement("div",null,r.a.createElement(g.a,{className:o.descriptionBody},i)),n&&r.a.createElement("div",null,r.a.createElement("table",null,r.a.createElement("tbody",null,n.map(function(e){var t=e.name,a=e.text;return r.a.createElement("tr",{key:t},r.a.createElement("td",null,r.a.createElement(g.a,null,t)),r.a.createElement("td",null,r.a.createElement(g.a,{className:o.descriptionBody},a)))})))),t))))}var X=Object(p.a)(function(e){return Object(f.a)({root:{margin:e.spacing(6,0,3)},lightBulb:{verticalAlign:"middle",marginRight:e.spacing(1)},leftContainer:{},centerContainer:{},listBoxContainer:{"& > div:not(:last-child)":{paddingBottom:"12px",marginBottom:"12px",borderBottom:"1px solid #313d47"}},listBox:{"& > div":{display:"flex",alignItems:"center","& p":{marginBottom:0}},"& > div:not(:last-child)":{paddingRight:"12px"}},slider:{color:e.palette.primary.main}})});function Y(e){var t=e.inputRef,a=e.onChange,n=e.prefix,i=e.suffix,o=Object(w.a)(e,["inputRef","onChange","prefix","suffix"]);return r.a.createElement(S.a,Object.assign({},o,{getInputRef:t,onValueChange:function(e){a({target:{value:e.value}})},thousandSeparator:!0,prefix:n,suffix:i}))}function Z(e){var t=e.inputFields,a=e.onChangeCommited,n=X();return r.a.createElement("div",{className:n.listBoxContainer},t.map(function(e){var t=e.label,i=e.description,o=e.value,c=e.setter,l=e.min,s=e.max,u=e.step,m=e.prefix,d=e.suffix,p=e.format,f=e.toText,h=e.toNum;function b(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;isNaN(e)&&(e=0),e>s?e=s:e5e8?[1e9,"B"]:e>5e5?[1e6,"M"]:e>500?[1e3,"K"]:[1,""],a=Object(d.a)(t,2);return{scaling:a[0],unit:a[1]}}var le=a(19);function se(e){var t=e.d0,a=e.theta,n=e.p0,r=e.p1/n/(1-a),i=(1-a)*t,o=t/n;return{k:r,R0:i,S0:o,V0:Math.pow(o,r)/i}}function ue(e){var t=e.S,a=e.V0,n=e.k;return Math.pow(t,n)/a}function me(e){var t=e.R,a=e.V0,n=e.k;return Math.pow(a*t,1/n)}function de(e){var t=e.S,a=e.H,n=e.V0,r=e.k;if(t===a){var i=pe({R:ue({S:t,V0:n,k:r}),V0:n,k:r});return Math.abs(i)}return pe({R:ue({S:t-a,V0:n,k:r}),V0:n,k:r})}function pe(e){var t=e.R,a=e.V0,n=e.k;return n*Math.pow(t,(n-1)/n)/Math.pow(a,1/n)}function fe(e){var t=e.R,a=e.deltaR,n=e.V0,r=e.k,i=Math.pow(n*t,1/r),o=a/(Math.pow(n*(t+a),1/r)-i),c=pe({R:t,V0:n,k:r});return Math.abs(o-c)/c}function he(e){var t=e.R,a=e.k,n=e.priceGrowth;return-t+Math.pow(n*Math.pow(t,1-1/a),a/(-1+a))}function ge(e){for(var t=e.sum,a=e.num,n=t/a,r=n*e.spread,i=[],o=0;o1||r<0)&&(r=xe(e,t)),r*=t-e,r+=e}function Ee(e){var t=Math.floor(e.length/2),a=Object(le.a)(e).sort(function(e,t){return e-t});return e.length%2!==0?a[t]:(a[t-1]+a[t])/2}var ye=a(185),Oe=!1,ke="x",je="Supply (tokens) / Collateral (DAI)",Ce="#b7c1cb",we=Object(p.a)(function(e){return Object(f.a)({tooltip:{border:"1px solid #313d47",backgroundColor:"#384b59",padding:e.spacing(1),color:"#c7ccd2"}})});var Ne=function(e){for(var t=e.theta,a=se({d0:e.d0,theta:t,p0:e.p0,p1:e.p1}),n=a.k,i=a.R0,o=a.S0,c=a.V0,l=Math.round(i),s=function(e){return o*Math.pow(e/l,1/n)},u=4*l,m=Math.round((u-0)/100),p=ce(Math.max(u,s(u))),f=p.scaling,h=p.unit,g=[],b=0;b<101;b++){var v,x=Math.round(0+m*b);g.push((v={},Object(C.a)(v,ke,x),Object(C.a)(v,je,s(x)),v))}var E=Object(ye.a)(),y=we(),O=function(e){return(+(e/f).toPrecision(2)).toLocaleString()};return r.a.createElement(te.g,{debounce:1},r.a.createElement(te.b,{width:0,height:400,data:g,margin:{top:10,right:30,left:0,bottom:0}},r.a.createElement(te.c,{vertical:!1,stroke:E.palette.text.secondary,strokeOpacity:.13}),r.a.createElement(te.i,{interval:24,dataKey:ke,tickFormatter:O,unit:h,tick:{fill:E.palette.text.secondary},stroke:E.palette.text.secondary}),r.a.createElement(te.j,{interval:"preserveStartEnd",ticks:ne(g.map(function(e){return e[je]}),3),tickFormatter:O,unit:h,tick:{fill:E.palette.text.secondary},domain:[0,s(u)],stroke:E.palette.text.secondary}),r.a.createElement(te.h,{content:r.a.createElement(function(e){var t=e.active,a=e.payload,i=e.label;if(t){var o=a[0].value,l=i,s=pe({R:l,V0:c,k:n}),u=[["Supply",O(o)+h,"tokens"],["Collateral",O(l)+h,"DAI"],["Price",s.toFixed(2),"DAI/token"]];return r.a.createElement("div",{className:y.tooltip},r.a.createElement("table",null,r.a.createElement("tbody",null,u.map(function(e){var t=Object(d.a)(e,3),a=t[0],n=t[1],i=t[2];return r.a.createElement("tr",{key:a},r.a.createElement("td",null,a),r.a.createElement("td",null,n),r.a.createElement("td",null,i))}))))}return null},null)}),r.a.createElement(te.a,{isAnimationActive:Oe,type:"monotone",dataKey:je,stroke:E.palette.primary.main,fill:E.palette.primary.main,fillOpacity:.3,strokeWidth:2}),r.a.createElement(te.f,{x:l,y:s(l),stroke:"transparent",strokeDasharray:"9 0",label:r.a.createElement(function(e){var t=e.textAnchor,a=e.viewBox;return r.a.createElement("text",{x:a.x+a.width/4+10,y:a.y+20,fill:Ce,textAnchor:t},"Initial Token Supply")},null)}),r.a.createElement(te.e,{x:l,y:s(l),r:6,fill:E.palette.primary.main,stroke:2}),r.a.createElement(te.d,{formatter:function(e){return r.a.createElement("span",{style:{color:E.palette.text.secondary}},e)}})))};a(406);function Be(){return r.a.createElement("div",{className:"spinner"},r.a.createElement("div",{className:"bounce1"}),r.a.createElement("div",{className:"bounce2"}),r.a.createElement("div",{className:"bounce3"}))}var Se=Object(p.a)(function(e){return Object(f.a)({root:{margin:e.spacing(6,0,3)},lightBulb:{verticalAlign:"middle",marginRight:e.spacing(1)},leftContainer:{color:e.palette.text.secondary},centerContainer:{},listBoxContainer:{"& > div:not(:last-child)":{marginBottom:"12px",borderBottom:"1px solid #313d47"}},listBox:{paddingBottom:"12px","& > div":{display:"flex",alignItems:"center","& p":{marginBottom:0}},"& > div:not(:last-child)":{paddingRight:"12px"}},valueFooter:{color:e.palette.text.secondary,fontSize:"80%"}})});function Fe(e){var t=e.resultFields,a=e.simulationDuration,i=Object(n.useState)(!0),o=Object(d.a)(i,2),c=o[0],l=o[1];Object(n.useEffect)(function(){var e=setTimeout(function(){l(!1)},a);return function(){clearTimeout(e)}});var s=Se();return r.a.createElement("div",{className:s.listBoxContainer},t.map(function(e){var t=e.label,a=e.description,n=e.value,i=e.valueFooter;return r.a.createElement(x.a,{key:t,container:!0,spacing:0,className:s.listBox},r.a.createElement(x.a,{item:!0,xs:8,className:s.leftContainer},r.a.createElement(I,{content:t,popoverText:a})),r.a.createElement(x.a,{item:!0,xs:4,className:s.centerContainer},c?r.a.createElement(Be,null):r.a.createElement("div",null,r.a.createElement(g.a,null,n),i&&r.a.createElement(g.a,{className:s.valueFooter},i))))}))}var Pe="x",Re="Price (DAI/token)",Ae="Floor price (DAI/token)",Te="Total funds raised (DAI)",Ie="Post-Hatch price",Me="Hatch price",De="#53c388",He="#4090d9",Ve="#b7c1cb",Le=Object(p.a)(function(e){return Object(f.a)({tooltip:{border:"1px solid #313d47",backgroundColor:"#384b59",padding:e.spacing(1),color:"#c7ccd2"}})});var ze=function(e){for(var t=e.priceTimeseries,a=e.totalFundsRaisedTimeseries,i=e.floorpriceTimeseries,o=e.simulationDuration,c=e.p0,l=e.p1,s=[],u=0;u div:not(:last-child)":{paddingBottom:e.spacing(3)},"& > div":{"& > div":{paddingTop:"0 !important"}},paddingBottom:e.spacing(9)},simulationContainer:{minHeight:"442px"},paper:{width:"100%",height:"100%",minHeight:310,backgroundColor:"#293640"},box:{padding:e.spacing(3,3)},boxButton:{padding:e.spacing(3,3)},boxHeader:{padding:e.spacing(3,3),height:e.spacing(10),display:"flex",alignItems:"center",borderBottom:"1px solid #313d47"},boxBorderBottom:{borderBottom:"1px solid #313d47"},initialRaise:{justifyContent:"space-between"},boxChart:{width:"100%",height:"100%",minHeight:310,maxHeight:350,padding:e.spacing(3,3),paddingRight:"5px",paddingLeft:"5px"},boxPlaceholder:{padding:e.spacing(3,3),display:"flex",height:"100%",alignItems:"center",justifyContent:"center",color:e.palette.text.secondary,opacity:.4},header:{backgroundColor:"#0b1216",color:"#f8f8f8",textAlign:"center",padding:e.spacing(3,0,16),marginBottom:-e.spacing(10)},button:{background:"linear-gradient(290deg, #1aa059, #3d9567)",color:"white"},descriptionContainer:{"& > div:not(:last-child)":{paddingBottom:e.spacing(1),marginBottom:e.spacing(1),borderBottom:"1px solid #3f5463"},"& td":{verticalAlign:"top",padding:e.spacing(.5)}},descriptionTitle:{padding:e.spacing(.5)},descriptionBody:{color:"#dbdfe4"},descriptionPadding:{padding:e.spacing(.5)},d0Container:{"& > div":{padding:"0 12px 0 0 !important",display:"flex",alignItems:"center"}},d0Number:{padding:"0 !important",display:"flex",alignItems:"center"},d0Slidder:{padding:"0 12px 0 0 !important",display:"flex",alignItems:"center"}})});var Je=a(183),Ue=a.n(Je),Qe=a(184),Xe=Object(Qe.a)({palette:{type:"dark",primary:{main:"#2ecd79"},secondary:{main:"#116be0",light:"#0f8bff",dark:"#116be0"},error:{main:Ue.a.A400},background:{default:"#fff",paper:"#293640"},text:{primary:"#fff",secondary:"#9aa3ad"}},typography:{h6:{fontWeight:400}}});console.log(Xe);var Ye=Xe;o.a.render(r.a.createElement(l.a,{theme:Ye},r.a.createElement(c.a,null),r.a.createElement(function(){var e=Object(n.useState)({theta:.35,p0:.1,p1:.3,wFee:.05,vHalflife:17,d0:3e6}),t=Object(d.a)(e,2),a=t[0],i=t[1],o=a.d0,c=a.theta,l=a.p0,s=a.p1,p=a.wFee,f=a.vHalflife,y=Object(n.useMemo)(function(){return Object(We.throttle)(i,250)},[]),O=se({d0:o,theta:c,p0:l,p1:s}),k=O.k,C=O.R0,w=O.S0,N=O.V0,B=Object(n.useState)([0]),S=Object(d.a)(B,2),F=S[0],P=S[1],R=Object(n.useState)([0]),A=Object(d.a)(R,2),T=A[0],I=A[1],M=Object(n.useState)([0]),D=Object(d.a)(M,2),H=D[0],$=D[1],G=Object(n.useState)(C),J=Object(d.a)(G,2),U=J[0],X=J[1],Y=Object(n.useState)(0),Z=Object(d.a)(Y,2),_=Z[0],te=Z[1],ae=Object(n.useState)(0),ne=Object(d.a)(ae,2),ce=ne[0],le=ne[1],ue=Object(n.useState)(0),xe=Object(d.a)(ue,2),ye=xe[0],Oe=xe[1],ke=Object(n.useState)(!1),je=Object(d.a)(ke,2),Ce=je[0],we=je[1],Be=Object(n.useState)(!1),Se=Object(d.a)(Be,2),Pe=Se[0],Re=Se[1];function Ae(){return(Ae=Object(m.a)(u.a.mark(function e(){return u.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return Te(),e.next=3,oe(0);case 3:we(!0);case 4:case"end":return e.stop()}},e)}))).apply(this,arguments)}function Te(){we(!1),te(0),P([0]),I([0]),le(0)}Object(n.useEffect)(function(){we(!1)},[a]),Object(n.useEffect)(function(){var e=!0;function t(){return(t=Object(m.a)(u.a.mark(function t(){var a,n,r,i,o,c,l,s,m,d,h;return u.a.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:a=[C],n=[w],r=[pe({R:C,V0:N,k:k})],i=[0],o=[],c=[],l=[w],s=[],m=52,.97,1.04,10,8,Re(!0),d=function(t){for(var u=ve(100,40*t+100),m=re(a),d=(re(n),re(l)),h=0,g=0,b=0,v=0,x=[0],E=1,y=0,O=0;O<20&&v<1.05*E;O++){var j=void 0,C=void 0;j=Ke[t],C=$e[t],O>15&&(j=1.02,C+=1.04);var w=ve(j,C),B=he({R:m,k:k,priceGrowth:w});h=m+B;var S=ge({sum:B,num:u,spread:10});y=Ee(S.map(function(e){return fe({R:m,deltaR:e,V0:N,k:k})})),x=S.filter(function(e){return e<0}),b=d-be({week:t,H:d,halflife:f,cliff:8}),E=de({S:g=me({R:m,V0:N,k:k}),H:g-b,V0:N,k:k}),v=pe({R:h,V0:N,k:k})}var F=Ee(x),P=-p*x.reduce(function(e,t){return e+t},0);if(a.push(h),n.push(g),l.push(b),r.push(v),o.push(y),c.push(F),i.push(re(i)+P),s.push(E),te(function(e){return e+x.length}),!Ce||!e)return"break"},h=0;case 16:if(!(h\n createStyles({\n container: {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\"\n },\n title: {\n // color: theme.palette.text.secondary,\n },\n subtitle: {\n color: theme.palette.text.secondary,\n margin: theme.spacing(3, 0, 0),\n maxWidth: theme.spacing(82)\n },\n subsubtitle: {\n color: theme.palette.text.secondary,\n opacity: 0.6,\n maxWidth: theme.spacing(74)\n },\n lightBulb: {\n verticalAlign: \"middle\",\n marginRight: theme.spacing(1)\n },\n link: {\n color: theme.palette.primary.main\n },\n logoContainer: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n marginBottom: theme.spacing(4)\n },\n logo: {\n width: \"25px\",\n marginRight: \"4px\"\n },\n logoText: {\n display: \"inline\",\n fontSize: \"1.1rem\",\n fontWeight: 500\n }\n })\n);\n\nexport default function Header() {\n const classes = useStyles();\n return (\n
\n
\n \"logo\"\n Commons Stack\n
\n\n \n Augmented Bonding Curve Design\n \n\n \n Experiment with the Commons Stack Augmented Bonding Curve component.\n Customize the hatch variables and explore the continuous funding results\n for your community.\n \n \n Read more about the Augmented Bonding Curve{\" \"}\n here. Note that this is a demo for\n illustration purposes only, a narrative showcase of cadCAD's\n capabilities.\n \n
\n );\n}\n","import { withStyles } from \"@material-ui/core/styles\";\nimport Slider from \"@material-ui/core/Slider\";\n\nexport default withStyles({\n root: {\n height: 8\n },\n thumb: {\n height: 24,\n width: 24,\n backgroundColor: \"#fff\",\n border: \"2px solid currentColor\",\n marginTop: -8,\n marginLeft: -12,\n \"&:focus,&:hover,&$active\": {\n boxShadow: \"inherit\"\n }\n },\n active: {},\n valueLabel: {\n left: \"calc(-50% + 4px)\"\n },\n track: {\n height: 8,\n borderRadius: 4\n },\n rail: {\n height: 8,\n borderRadius: 4\n },\n markLabel: {\n top: 30\n }\n})(Slider);\n","import React from \"react\";\nimport { makeStyles } from \"@material-ui/core/styles\";\nimport Popover from \"@material-ui/core/Popover\";\nimport Typography from \"@material-ui/core/Typography\";\nimport Box from \"@material-ui/core/Box\";\n\nconst useStyles = makeStyles(theme => ({\n container: {\n color: theme.palette.text.secondary,\n display: \"flex\",\n fontSize: \"0.9rem\",\n cursor: \"pointer\",\n transition: \"color ease 150ms\",\n \"&:hover\": {\n color: \"#c3c9d0\"\n }\n },\n popoverContainer: {\n padding: theme.spacing(2),\n \"& > p:not(:last-child)\": {\n paddingBottom: theme.spacing(1),\n marginBottom: theme.spacing(1),\n borderBottom: \"1px solid #3f5463\"\n }\n },\n paper: {\n backgroundColor: \"#384b59\",\n maxWidth: theme.breakpoints.values.md * 0.9,\n [`@media screen and (max-width: ${theme.breakpoints.values.md}px)`]: {\n maxWidth: \"90vw\"\n },\n padding: theme.spacing(0.5)\n },\n descriptionBody: {\n color: \"#dbdfe4\"\n }\n}));\n\nexport default function TextWithPopover({\n content,\n popoverText\n}: {\n content: string;\n popoverText: string;\n}) {\n const classes = useStyles();\n const [anchorEl, setAnchorEl] = React.useState(null);\n\n function handleClick(event: any) {\n setAnchorEl(event.currentTarget);\n }\n\n function handleClose() {\n setAnchorEl(null);\n }\n\n const open = Boolean(anchorEl);\n const id = open ? \"simple-popover\" : undefined;\n\n return (\n
\n
\n {content}\n
\n \n \n {content}\n \n {popoverText}\n \n \n \n
\n );\n}\n","import React from \"react\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Grid from \"@material-ui/core/Grid\";\nimport TextField from \"@material-ui/core/TextField\";\nimport NumberFormat from \"react-number-format\";\nimport { InputFieldInterface } from \"./types\";\nimport PrettoSlider from \"./PrettoSlider\";\nimport TextWithPopover from \"./TextWithPopover\";\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n root: {\n margin: theme.spacing(6, 0, 3)\n },\n lightBulb: {\n verticalAlign: \"middle\",\n marginRight: theme.spacing(1)\n },\n leftContainer: {\n color: theme.palette.text.secondary\n },\n centerContainer: {\n // color: blackColor\n },\n listBoxContainer: {\n \"& > div:not(:last-child)\": {\n paddingBottom: \"12px\",\n marginBottom: \"12px\",\n borderBottom: \"1px solid #313d47\"\n }\n },\n listBox: {\n \"& > div\": {\n display: \"flex\",\n alignItems: \"center\",\n \"& p\": {\n marginBottom: 0\n }\n },\n \"& > div:not(:last-child)\": {\n paddingRight: \"12px\"\n }\n },\n slider: {\n color: theme.palette.primary.main\n }\n })\n);\n\nfunction NumberFormatCustom(props: any) {\n const { inputRef, onChange, prefix, suffix, ...other } = props;\n\n return (\n {\n onChange({ target: { value: values.value } });\n }}\n thousandSeparator\n prefix={prefix}\n suffix={suffix}\n />\n );\n}\n\nexport default function InputParams({\n inputFields,\n onChangeCommited\n}: {\n inputFields: InputFieldInterface[];\n onChangeCommited(): void;\n}) {\n const classes = useStyles();\n\n return (\n
\n {inputFields.map(\n ({\n label,\n description,\n value,\n setter,\n min,\n max,\n step,\n prefix,\n suffix,\n format,\n toText,\n toNum\n }) => {\n function sanitizeInput(num: number = 0) {\n if (isNaN(num)) num = 0;\n if (num > max) num = max;\n else if (num < min) num = min;\n setter(num);\n }\n\n return (\n \n \n \n \n\n \n {\n sanitizeInput(\n toNum ? toNum(e.target.value) : parseFloat(e.target.value)\n );\n onChangeCommited();\n }}\n InputProps={{\n inputComponent: NumberFormatCustom,\n disableUnderline: true,\n inputProps: {\n prefix,\n suffix\n }\n }}\n value={toText ? toText(value) : value}\n />\n \n\n \n sanitizeInput(Number(newValue))}\n onChangeCommitted={onChangeCommited}\n value={value}\n min={min}\n max={max}\n step={step}\n valueLabelFormat={value => format(value).replace(\"$\", \"\")}\n />\n \n \n );\n }\n )}\n
\n );\n}\n","export interface DescriptionObject {\n [key: string]: { name: string; text: string };\n}\n\nexport const parameterDescriptions: DescriptionObject = {\n theta: {\n name: \"Hatch Raise % to funding pool\",\n text:\n \"The percentage of the funds raised in the Hatch going directly to funding pool to be used to support the Commons, the rest goes to the collateral pool\"\n },\n p0: {\n name: \"Hatch price\",\n text: \"The price paid per token by when hatching the project\"\n },\n p1: {\n name: \"Post-Hatch price\",\n text:\n \"The price per token after the Hatch ends, the curve is set, and anyone can interact with the bonding curve\"\n },\n wFee: {\n name: \"Exit tribute\",\n text:\n \"The percentage that goes to the funding pool when token holders 'sell' by burning their token at the price determined by the bonding curve\"\n },\n vHalflife: {\n name: \"Vesting half-life\",\n text:\n \"Tokens that are purchased during the Hatch are locked for 8 weeks and then released slowly such that 50% of the tokens will be able to be sold after this many weeks and 87.5% of the tokens after 3x this many weeks\"\n },\n d0: {\n name: \"Hatch Raise\",\n text: \"Amount of funds contributed during the hatch period\"\n }\n};\n\nexport const supplyVsDemandChartDescription =\n \"Visualization of the bonding curve up to 4x the initial size of the Collateral Pool Post-Hatch. This result is deterministic given the curve parameters and the Hatch raise. It will never change regardless of the campaign's performance, it simply shows how the price will react to changes in the Collateral Pool.\";\n\nexport const simulationChartDescription =\n \"This chart shows a 52 week simulation of discrete transactions interacting with the Augmented Bonding Curve. Each transaction adds to or subtracts reserve from the system, modifying the price over time. The frequency, size and direction of each transaction is computed from a set of bounded random functions. This is a NOT a cadCAD simulation, but it showcases the intention behind cadCAD.\";\n\nexport const simulationParameterDescriptions: DescriptionObject = {\n price: {\n name: \"Price\",\n text: \"Price of the token over time.\"\n },\n floorPrice: {\n name: \"Floor price\",\n text:\n \"Lower bound of the price guaranteed by the vesting of hatch tokens. It decreases over time as more hatch tokens are allowed to be traded\"\n },\n totalRaised: {\n name: \"Total funds raised\",\n text: \"Cumulative sum of the funds sent to the Funding Pool\"\n }\n};\n\nexport const resultParameterDescriptions: DescriptionObject = {\n totalReserve: {\n name: \"Collateral pool balance\",\n text: \"Total DAI in the collateral pool at the end of the simulated period\"\n },\n slippage: {\n name: \"Median slippage\",\n text:\n \"Median of change in price a user experiences from the current price to the price received for exiting/selling/burning\"\n },\n initialHatchFunds: {\n name: \"Funds generated from Raise Hatch\",\n text: \"Funds raised during the Hatch that go directly to the cause\"\n },\n exitTributes: {\n name: \"Funds generated from exit tributes\",\n text:\n \"Cumulative sum of exit tributes collected from only exit / sell / burn transactions\"\n },\n totalRaised: {\n name: \"Total funds raised for your community\",\n text: \"Sum of funds from Raise Hatch + funds from exit tributes\"\n }\n};\n","import React, { useState, useEffect } from \"react\";\nimport { InputFieldInterface, CurveParamsInterface } from \"./types\";\nimport InputParams from \"./InputParams\";\nimport { parameterDescriptions } from \"./parametersDescriptions\";\n\nexport default function CurveDesignInputParams({\n curveParams,\n setCurveParams\n}: {\n curveParams: CurveParamsInterface;\n setCurveParams(newCurveParams: any): void;\n}) {\n const [theta, setTheta] = useState(curveParams.theta); // fraction allocated to reserve (.)\n const [p0, setP0] = useState(curveParams.p0); // Hatch sale Price p0 (DAI / token)\n const [p1, setP1] = useState(curveParams.p1); // Return factor (.)\n const [wFee, setWFee] = useState(curveParams.wFee); // friction coefficient (.)\n const [vHalflife, setVHalflife] = useState(curveParams.vHalflife); // friction coefficient (.)\n\n useEffect(() => {\n setTheta(curveParams.theta);\n setP0(curveParams.p0);\n setP1(curveParams.p1);\n setWFee(curveParams.wFee);\n setVHalflife(curveParams.vHalflife);\n }, [curveParams]);\n\n const maxReturnRate = 10;\n const minP1P0Rate = 1.5;\n\n function _setP0(newP0: number) {\n setP0(newP0);\n if (p1 < newP0 * minP1P0Rate) setP1(newP0 * minP1P0Rate);\n else if (p1 > newP0 * maxReturnRate) setP1(newP0 * maxReturnRate);\n }\n\n function setParentCurveParams() {\n setCurveParams((params: CurveParamsInterface) => ({\n ...params,\n theta,\n p0,\n p1,\n wFee,\n vHalflife\n }));\n }\n\n const inputFields: InputFieldInterface[] = [\n {\n label: parameterDescriptions.theta.name,\n description: parameterDescriptions.theta.text,\n value: theta,\n setter: setTheta,\n min: 0,\n max: 0.9,\n step: 0.01,\n suffix: \"%\",\n format: (n: number) => `${Math.round(100 * n)}%`,\n toText: (n: number) => String(+(n * 1e2).toFixed(0)),\n toNum: (n: string) => parseFloat(n) * 1e-2\n },\n {\n label: `${parameterDescriptions.p0.name} (DAI/token)`,\n description: parameterDescriptions.p0.text,\n value: p0,\n setter: _setP0,\n min: 0.01,\n max: 1,\n step: 0.01,\n toText: (n: number) => String(+n.toFixed(2)),\n toNum: (n: string) => parseFloat(n),\n format: (n: number) => `$${n}`\n },\n {\n label: `${parameterDescriptions.p1.name} (DAI/token)`,\n description: parameterDescriptions.p1.text,\n value: p1,\n setter: setP1,\n min: Number((minP1P0Rate * (p0 || 0.1)).toFixed(2)),\n max: Number((maxReturnRate * p0).toFixed(2)),\n step: 0.01,\n toText: (n: number) => String(+n.toFixed(2)),\n toNum: (n: string) => parseFloat(n),\n format: (n: number) => `$${n}`\n },\n {\n label: parameterDescriptions.wFee.name,\n description: parameterDescriptions.wFee.text,\n value: wFee,\n setter: setWFee,\n min: 0,\n max: 0.1,\n step: 0.001,\n suffix: \"%\",\n format: (n: number) => `${+(100 * n).toFixed(1)}%`,\n toText: (n: number) => String(+(n * 1e2).toFixed(1)),\n toNum: (n: string) => parseFloat(n) * 1e-2\n },\n {\n label: `${parameterDescriptions.vHalflife.name} (weeks)`,\n description: parameterDescriptions.vHalflife.text,\n value: vHalflife,\n setter: setVHalflife,\n min: 1,\n max: 52 * 2,\n step: 1,\n suffix: \"\",\n format: (n: number) => String(Math.round(n)),\n toText: (n: number) => String(Math.round(n)),\n toNum: (n: string) => Math.round(parseInt(n))\n }\n ];\n\n return (\n \n );\n}\n","import React from \"react\";\nimport { makeStyles } from \"@material-ui/core/styles\";\nimport Popover from \"@material-ui/core/Popover\";\nimport Typography from \"@material-ui/core/Typography\";\nimport Box from \"@material-ui/core/Box\";\nimport HelpIcon from \"@material-ui/icons/HelpOutline\";\n\nconst useStyles = makeStyles(theme => ({\n container: {\n display: \"flex\",\n marginLeft: \"6px\",\n fontSize: \"0.9rem\",\n cursor: \"pointer\",\n transition: \"opacity ease 150ms\",\n opacity: 0.2,\n \"&:hover\": {\n opacity: 0.85\n }\n },\n popoverContainer: {\n padding: theme.spacing(2)\n },\n paper: {\n backgroundColor: \"#384b59\",\n maxWidth: theme.breakpoints.values.md * 0.9,\n [`@media screen and (max-width: ${theme.breakpoints.values.md}px)`]: {\n maxWidth: \"90vw\"\n }\n },\n // Descriptions\n descriptionContainer: {\n \"& > div:not(:last-child)\": {\n paddingBottom: theme.spacing(1),\n marginBottom: theme.spacing(1),\n borderBottom: \"1px solid #3f5463\"\n },\n \"& td\": {\n verticalAlign: \"top\",\n padding: theme.spacing(0.5)\n }\n },\n descriptionTitle: {\n padding: theme.spacing(0.5)\n },\n descriptionBody: {\n color: \"#dbdfe4\",\n padding: theme.spacing(0.5)\n },\n descriptionPadding: {\n padding: theme.spacing(0.5)\n }\n}));\n\nexport default function SimplePopover({\n text,\n title,\n table,\n body\n}: {\n text?: any;\n title?: string;\n table?: { name: string; text: string }[];\n body?: string;\n}) {\n const classes = useStyles();\n const [anchorEl, setAnchorEl] = React.useState(null);\n\n function handleClick(e: any) {\n setAnchorEl(e.currentTarget);\n }\n\n function handleClose() {\n setAnchorEl(null);\n }\n\n const open = Boolean(anchorEl);\n const id = open ? \"simple-popover\" : undefined;\n\n return (\n
\n \n\n \n \n
\n {title && (\n
\n \n {title}\n \n
\n )}\n\n {body && (\n
\n \n {body}\n \n
\n )}\n\n {table && (\n
\n \n \n {table.map(({ name, text }) => (\n \n \n \n \n ))}\n \n
\n {name}\n \n \n {text}\n \n
\n
\n )}\n\n {text}\n
\n
\n \n
\n );\n}\n","import React from \"react\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Grid from \"@material-ui/core/Grid\";\nimport TextField from \"@material-ui/core/TextField\";\nimport Typography from \"@material-ui/core/Typography\";\nimport NumberFormat from \"react-number-format\";\nimport { InputFieldInterface } from \"./types\";\nimport PrettoSlider from \"./PrettoSlider\";\nimport HelpText from \"./HelpText\";\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n root: {\n margin: theme.spacing(6, 0, 3)\n },\n lightBulb: {\n verticalAlign: \"middle\",\n marginRight: theme.spacing(1)\n },\n leftContainer: {\n // color: theme.palette.text.secondary\n },\n centerContainer: {\n // color: blackColor\n },\n listBoxContainer: {\n \"& > div:not(:last-child)\": {\n paddingBottom: \"12px\",\n marginBottom: \"12px\",\n borderBottom: \"1px solid #313d47\"\n }\n },\n listBox: {\n \"& > div\": {\n display: \"flex\",\n alignItems: \"center\",\n \"& p\": {\n marginBottom: 0\n }\n },\n \"& > div:not(:last-child)\": {\n paddingRight: \"12px\"\n }\n },\n slider: {\n color: theme.palette.primary.main\n }\n })\n);\n\nfunction NumberFormatCustom(props: any) {\n const { inputRef, onChange, prefix, suffix, ...other } = props;\n\n return (\n {\n onChange({ target: { value: values.value } });\n }}\n thousandSeparator\n prefix={prefix}\n suffix={suffix}\n />\n );\n}\n\nexport default function InputParamBig({\n inputFields,\n onChangeCommited\n}: {\n inputFields: InputFieldInterface[];\n onChangeCommited(): void;\n}) {\n const classes = useStyles();\n\n return (\n
\n {inputFields.map(\n ({\n label,\n description,\n value,\n setter,\n min,\n max,\n step,\n prefix,\n suffix,\n format,\n toText,\n toNum\n }) => {\n function sanitizeInput(num: number = 0) {\n if (isNaN(num)) num = 0;\n if (num > max) num = max;\n else if (num < min) num = min;\n setter(num);\n }\n\n return (\n \n \n {label}\n \n \n\n \n {\n sanitizeInput(\n toNum ? toNum(e.target.value) : parseFloat(e.target.value)\n );\n onChangeCommited();\n }}\n InputProps={{\n inputComponent: NumberFormatCustom,\n disableUnderline: true,\n inputProps: {\n prefix,\n suffix\n }\n }}\n value={toText ? toText(value) : value}\n />\n \n\n \n sanitizeInput(Number(newValue))}\n onChangeCommitted={onChangeCommited}\n value={value}\n min={min}\n max={max}\n step={step}\n valueLabelFormat={value => format(value).replace(\"$\", \"\")}\n />\n \n \n );\n }\n )}\n
\n );\n}\n","import React, { useState, useEffect } from \"react\";\nimport { InputFieldInterface, CurveParamsInterface } from \"./types\";\nimport InputParamBig from \"./InputParamBig\";\nimport { parameterDescriptions } from \"./parametersDescriptions\";\n\nexport default function SimulationInputParams({\n curveParams,\n setCurveParams\n}: {\n curveParams: CurveParamsInterface;\n setCurveParams(newCurveParams: any): void;\n}) {\n const [d0, setD0] = useState(3e6); // Initial raise, d0 (DAI)\n\n useEffect(() => {\n setD0(curveParams.d0);\n }, [curveParams]);\n\n function setParentCurveParams() {\n setCurveParams((params: CurveParamsInterface) => ({\n ...params,\n d0\n }));\n }\n\n const inputFields: InputFieldInterface[] = [\n {\n label: `${parameterDescriptions.d0.name}`,\n description: parameterDescriptions.d0.text,\n value: d0,\n setter: setD0,\n min: 0.1e6,\n max: 10e6,\n step: 0.1e6,\n suffix: \"M\",\n format: (n: number) => `$${+(n * 1e-6).toFixed(1)}M`,\n toText: (n: number) => String(+(n * 1e-6).toFixed(1)),\n toNum: (n: string) => Math.floor(parseFloat(n) * 1e6)\n }\n ];\n\n return (\n \n );\n}\n","/**\n * Returns an equally spaced array of numbers `from`, `to` with `steps`.\n */\nexport function linspace({\n from = 0,\n to,\n steps\n}: {\n from?: number;\n to: number;\n steps: number;\n}) {\n const arr = [];\n for (let x = from; x <= to; x += (to - from) / steps) arr.push(x);\n return arr;\n}\n\n/**\n * Returns a uniform distribution of `num` ticks\n */\nexport function getLinspaceTicks(data: number[], num: number) {\n const desiredPoints = [];\n const step = (data[data.length - 1] - data[0]) / num;\n for (let x = data[0]; x < data[data.length - 1]; x += step) {\n desiredPoints.push(x);\n }\n if (desiredPoints.length < num + 1) desiredPoints.push(data[data.length - 1]);\n\n return desiredPoints;\n}\n\n/**\n * Returns the last element of an array\n */\nexport function getLast(a: number[]) {\n return a[a.length - 1];\n}\n\n/**\n * Returns the average of an array\n */\nexport function getAvg(a: number[]) {\n return a.reduce((t, c) => t + Math.abs(c), 0) / a.length;\n}\n\n/**\n * Waits `ms` miliseconds and resolves\n */\nexport function pause(ms: number) {\n return new Promise(r => setTimeout(r, ms));\n}\n\n/**\n * Parse the units of big numbers\n */\nexport function getUnits(\n biggestNum: number\n): { scaling: number; unit: string } {\n const [scaling, unit] =\n // Billion\n biggestNum > 0.5e9\n ? [1e9, \"B\"]\n : // Million\n biggestNum > 0.5e6\n ? [1e6, \"M\"]\n : // 1 thousand\n biggestNum > 0.5e3\n ? [1e3, \"K\"]\n : // No scale\n [1, \"\"];\n return { scaling, unit };\n}\n","/**\n * Computes the initial params given the \"user friendly\" params:\n * - Initial raise, `d0` (DAI)\n * - fraction allocated to reserve, `theta`\n * - Hatch sale price, `p0` (DAI / token)\n * - Return factor, `returnF`\n */\nexport function getInitialParams({\n d0,\n theta,\n p0,\n p1\n}: {\n d0: number;\n theta: number;\n p0: number;\n p1: number;\n}) {\n const k = p1 / p0 / (1 - theta); // Invariant power kappa (.)\n const R0 = (1 - theta) * d0; // Initial reserve (DAI)\n const S0 = d0 / p0; // initial supply of tokens (token)\n const V0 = S0 ** k / R0; // invariant coef\n return { k, R0, S0, V0 };\n}\n\nexport function getR({ S, V0, k }: { S: number; V0: number; k: number }) {\n return S ** k / V0;\n}\n\nexport function getS({ R, V0, k }: { R: number; V0: number; k: number }) {\n return (V0 * R) ** (1 / k);\n}\n\n// compute the price if all that supply is burned\nexport function getMinPrice({\n S,\n H,\n V0,\n k\n}: {\n S: number;\n H: number;\n V0: number;\n k: number;\n}) {\n if (S === H) {\n const myR = getR({ S, V0, k });\n const myP = getPriceR({ R: myR, V0, k }); // numerical precision make complex numbers just suppress it\n return Math.abs(myP);\n } else {\n // compute the reserve if all that supply is burned\n const minR = getR({ S: S - H, V0, k });\n return getPriceR({ R: minR, V0, k });\n }\n}\n\n/**\n * Computes the price at a specific reserve `R`\n */\nexport function getPriceR({ R, V0, k }: { R: number; V0: number; k: number }) {\n return (k * R ** ((k - 1) / k)) / V0 ** (1 / k);\n}\n\n/**\n * Compute slippage at a point `R`, given a `deltaR`\n */\nexport function getSlippage({\n R,\n deltaR,\n V0,\n k\n}: {\n R: number;\n deltaR: number;\n V0: number;\n k: number;\n}) {\n const S = (V0 * R) ** (1 / k);\n const deltaS = (V0 * (R + deltaR)) ** (1 / k) - S;\n const realizedPrice = deltaR / deltaS;\n const spotPrice = getPriceR({ R, V0, k });\n return Math.abs(realizedPrice - spotPrice) / spotPrice;\n}\n\n// Price walk utils\n\n/**\n * Get deltaR for a given price growth factor\n */\nexport function getDeltaR_priceGrowth({\n R,\n k,\n priceGrowth\n}: {\n R: number;\n k: number;\n priceGrowth: number;\n}) {\n return -R + (priceGrowth * R ** (1 - 1 / k)) ** (k / (-1 + k));\n}\n\n/**\n * Computes a tx distribution using a normal distribution,\n * Given a sum of tx value and a number of transactions\n *\n * Demo: https://codepen.io/anon/pen/mNqJjv?editors=0010#0\n * Very quick: < 10ms for 10000 txs\n */\nexport function getTxDistribution({\n sum,\n num,\n spread\n}: {\n sum: number;\n num: number;\n spread: number;\n}) {\n const mean = sum / num;\n const off = mean * spread;\n const x: number[] = [];\n for (let i = 0; i < num; i++) {\n x.push(randn_bm(mean - off, mean + off));\n }\n return x;\n}\n\nexport function vest_tokens({\n week,\n H, // unvested_hatch_tokens\n halflife,\n cliff\n}: {\n week: number;\n H: number;\n halflife: number;\n cliff: number;\n}) {\n // check cliff\n if (week < cliff) {\n return 0;\n } else {\n // rate of release given half - life\n const vest_fraction = 0.5 ** (1 / halflife);\n // number of tokens that vest in this week\n return H * (1 - vest_fraction);\n }\n}\n\n// Statistics utils\n\n/**\n * Random variable uniformly distributed\n */\nexport function rv_U(min: number, max: number) {\n return Math.random() * (max - min) + min;\n}\n\n/**\n * Standard Normal variate using Box-Muller transform.\n * by https://stackoverflow.com/questions/25582882/javascript-math-random-normal-distribution-gaussian-bell-curve/36481059#36481059\n */\nfunction randn_bm(min: number, max: number) {\n var u = 0,\n v = 0;\n while (u === 0) u = Math.random(); //Converting [0,1) to (0,1)\n while (v === 0) v = Math.random();\n let num = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);\n\n num = num / 10.0 + 0.5; // Translate to 0 -> 1\n if (num > 1 || num < 0) num = randn_bm(min, max); // resample between 0 and 1 if out of range\n num *= max - min; // Stretch to fill range\n num += min; // offset to min\n return num;\n}\n\n// Array utils\n\nexport function getMedian(arr: number[]) {\n const mid = Math.floor(arr.length / 2);\n const nums = [...arr].sort((a, b) => a - b);\n return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;\n}\n\nexport function getSum(arr: number[]) {\n return arr.reduce((a, b) => a + b, 0);\n}\n","import React from \"react\";\nimport {\n AreaChart,\n Area,\n XAxis,\n YAxis,\n CartesianGrid,\n Legend,\n ReferenceLine,\n ReferenceDot,\n ReferenceArea,\n ResponsiveContainer,\n Tooltip\n} from \"recharts\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport { getLinspaceTicks, getUnits } from \"./utils\";\nimport { getInitialParams, getPriceR } from \"./math\";\nimport { useTheme } from \"@material-ui/styles\";\n\nconst isAnimationActive = false;\nconst keyHorizontal = \"x\";\nconst keyVertical = \"Supply (tokens) / Collateral (DAI)\";\n\n// Do to transparency and color merging issues\n// these colors are handpicked to look the closest to the theme colors\nconst referenceLineColor = \"#b7c1cb\";\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n tooltip: {\n border: \"1px solid #313d47\",\n backgroundColor: \"#384b59\",\n padding: theme.spacing(1),\n color: \"#c7ccd2\"\n }\n })\n);\n\nfunction SupplyVsDemandChart({\n theta,\n d0,\n p0,\n p1\n}: {\n theta: number;\n d0: number;\n p0: number;\n p1: number;\n}) {\n // d0 - Initial raise, d0 (DAI)\n // theta - fraction allocated to reserve (.)\n // p0 - Hatch sale Price p0 (DAI / token)\n // returnF - Return factor (.)\n // wFee - friction coefficient (.)\n\n // Hatch parameters\n const {\n k, // Invariant power kappa (.)\n R0, // Initial reserve (DAI)\n S0, // initial supply of tokens (token)\n V0 // invariant coef\n } = getInitialParams({\n d0,\n theta,\n p0,\n p1\n });\n const R0_round = Math.round(R0);\n const S_of_R = (R: number) => S0 * (R / R0_round) ** (1 / k);\n\n // Function setup\n const f = S_of_R;\n const from = 0;\n const to = 4 * R0_round;\n const steps = 100 + 1; // Add 1 for the ticks to match\n const step = Math.round((to - from) / (steps - 1));\n\n /**\n * Prettify the result converting 1000000 to 1M\n */\n const biggest = Math.max(to, f(to));\n const { scaling, unit } = getUnits(biggest);\n\n const data = [];\n for (let i = 0; i < steps; i++) {\n const x = Math.round(from + step * i);\n data.push({\n [keyHorizontal]: x,\n [keyVertical]: f(x)\n });\n }\n\n // Chart components\n\n const theme: any = useTheme();\n const classes = useStyles();\n\n const formatter = (n: number) =>\n (+(n / scaling).toPrecision(2)).toLocaleString();\n\n function renderColorfulLegendText(value: string) {\n return {value};\n }\n\n function ReferenceLabel(props: any) {\n const { textAnchor, viewBox } = props;\n return (\n \n Initial Token Supply\n \n );\n }\n\n function CustomTooltip({ active, payload, label }: any) {\n if (active) {\n const supply = payload[0].value;\n const reserve = label;\n const price = getPriceR({ R: reserve, V0, k });\n const toolTipData: string[][] = [\n [\"Supply\", formatter(supply) + unit, \"tokens\"],\n [\"Collateral\", formatter(reserve) + unit, \"DAI\"],\n [\"Price\", price.toFixed(2), \"DAI/token\"]\n ];\n return (\n
\n \n \n {toolTipData.map(([name, value, _unit]) => (\n \n \n \n \n \n ))}\n \n
{name}{value}{_unit}
\n
\n );\n } else return null;\n }\n\n return (\n \n \n \n \n d[keyVertical]), 3)}\n tickFormatter={formatter}\n unit={unit}\n tick={{ fill: theme.palette.text.secondary }}\n domain={[0, f(to)]}\n stroke={theme.palette.text.secondary}\n />\n } />\n \n {/* Necessary because ReferenceDot types do not allow \"label\" k */}\n }\n />\n \n\n \n \n \n );\n}\n\nexport default SupplyVsDemandChart;\n","import React from \"react\";\nimport \"./dotsLoader.css\";\n\nexport default function DotsLoader() {\n return (\n
\n
\n
\n
\n
\n );\n}\n","import React, { useState, useEffect } from \"react\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Typography from \"@material-ui/core/Typography\";\nimport Grid from \"@material-ui/core/Grid\";\nimport TextWithPopover from \"./TextWithPopover\";\nimport DotsLoader from \"./DotsLoader\";\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n root: {\n margin: theme.spacing(6, 0, 3)\n },\n lightBulb: {\n verticalAlign: \"middle\",\n marginRight: theme.spacing(1)\n },\n leftContainer: {\n color: theme.palette.text.secondary\n },\n centerContainer: {\n // color: blackColor\n },\n listBoxContainer: {\n \"& > div:not(:last-child)\": {\n marginBottom: \"12px\",\n borderBottom: \"1px solid #313d47\"\n }\n },\n listBox: {\n paddingBottom: \"12px\",\n \"& > div\": {\n display: \"flex\",\n alignItems: \"center\",\n \"& p\": {\n marginBottom: 0\n }\n },\n \"& > div:not(:last-child)\": {\n paddingRight: \"12px\"\n }\n },\n valueFooter: {\n color: theme.palette.text.secondary,\n fontSize: \"80%\"\n }\n })\n);\n\nexport default function ResultParams({\n resultFields,\n simulationDuration\n}: {\n resultFields: {\n label: string;\n description: string;\n value: number | string;\n valueFooter?: string;\n }[];\n simulationDuration: number;\n}) {\n /**\n * When resizing the window the chart animation looks very bad\n * Keep the animation active only during the initial animation time,\n * but afterwards, deactivate to prevent the re-size ugly effect\n */\n const [isAnimationActive, setIsAnimationActive] = useState(\n process.env.NODE_ENV !== \"development\"\n );\n useEffect(() => {\n const timeout = setTimeout(() => {\n setIsAnimationActive(false);\n }, simulationDuration);\n return () => {\n clearTimeout(timeout);\n };\n });\n\n const classes = useStyles();\n\n return (\n
\n {resultFields.map(({ label, description, value, valueFooter }) => (\n \n \n \n \n\n \n {isAnimationActive ? (\n \n ) : (\n
\n {value}\n {valueFooter && (\n \n {valueFooter}\n \n )}\n
\n )}\n
\n
\n ))}\n
\n );\n}\n","import React, { useState, useEffect } from \"react\";\nimport {\n AreaChart,\n Area,\n XAxis,\n YAxis,\n CartesianGrid,\n Legend,\n ReferenceLine,\n ResponsiveContainer,\n Tooltip\n} from \"recharts\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport { useTheme } from \"@material-ui/styles\";\nimport { linspace, getUnits } from \"./utils\";\n\nconst keyHorizontal = \"x\";\nconst keyVerticalLeft = \"Price (DAI/token)\";\nconst keyVerticalLeft2 = \"Floor price (DAI/token)\";\nconst keyVerticalRight = \"Total funds raised (DAI)\";\nconst p1LineText = \"Post-Hatch price\";\nconst p0LineText = \"Hatch price\";\n\n// Do to transparency and color merging issues\n// these colors are handpicked to look the closest to the theme colors\nconst yLeftColor = \"#53c388\";\nconst yRightColor = \"#4090d9\";\nconst referenceLineColor = \"#b7c1cb\";\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n tooltip: {\n border: \"1px solid #313d47\",\n backgroundColor: \"#384b59\",\n padding: theme.spacing(1),\n color: \"#c7ccd2\"\n }\n })\n);\n\nfunction PriceSimulationChart({\n priceTimeseries,\n totalFundsRaisedTimeseries,\n floorpriceTimeseries,\n simulationDuration,\n p0,\n p1\n}: {\n priceTimeseries: number[];\n totalFundsRaisedTimeseries: number[];\n floorpriceTimeseries: number[];\n simulationDuration: number;\n p0: number;\n p1: number;\n}) {\n // d0 - Initial raise, d0 (DAI)\n // theta - fraction allocated to reserve (.)\n // p0 - Hatch sale Price p0 (DAI / token)\n // returnF - Return factor (.)\n // wFee - friction coefficient (.)\n\n const data = [];\n for (let t = 0; t < priceTimeseries.length; t++) {\n data.push({\n [keyHorizontal]: t,\n [keyVerticalLeft]: priceTimeseries[t] || 0,\n [keyVerticalLeft2]: floorpriceTimeseries[t] || 0,\n [keyVerticalRight]: totalFundsRaisedTimeseries[t] || 0\n });\n }\n\n /**\n * When resizing the window the chart animation looks very bad\n * Keep the animation active only during the initial animation time,\n * but afterwards, deactivate to prevent the re-size ugly effect\n */\n const [isAnimationActive, setIsAnimationActive] = useState(\n process.env.NODE_ENV !== \"development\"\n );\n useEffect(() => {\n const timeout = setTimeout(() => {\n setIsAnimationActive(false);\n }, simulationDuration + 100);\n return () => {\n clearTimeout(timeout);\n };\n });\n\n // Compute chart related math\n\n const totalFundsMin = totalFundsRaisedTimeseries[0];\n const totalFundsMax = totalFundsRaisedTimeseries.slice(-1)[0];\n const totalFundsRange = totalFundsMax - totalFundsMin;\n\n const daiFormatter = (n: number) => (+n.toFixed(2)).toLocaleString();\n const { scaling, unit } = getUnits(totalFundsMax);\n const fundsFormatter = (n: number) => (+n.toPrecision(3)).toLocaleString();\n const fundsFormatterShort = (n: number) =>\n (+(n / scaling).toPrecision(3)).toLocaleString();\n\n // Load styles\n\n const theme: any = useTheme();\n const classes = useStyles();\n\n // Chart components\n\n function renderColorfulLegendText(value: string) {\n return {value};\n }\n\n function ReferenceLabel(props: any) {\n const { textAnchor, viewBox, text, fill } = props;\n return (\n \n {text}\n \n );\n }\n\n function CustomTooltip({ active, payload, label }: any) {\n if (active) {\n const price = payload[0].value;\n const floor = payload[1].value;\n const funds = payload[2].value;\n const weekNum = label;\n const toolTipData: string[][] = [\n [\"Price\", daiFormatter(price), \"DAI/tk\"],\n [\"Floor P.\", daiFormatter(floor), \"DAI/tk\"],\n [\"Funds R.\", fundsFormatterShort(funds) + unit, \"DAI\"],\n [\"Week\", weekNum, \"\"]\n ];\n\n return (\n
\n \n \n {toolTipData.map(([name, value, unit]) => (\n \n \n \n \n \n ))}\n \n
{name}{value}{unit}
\n
\n );\n } else return null;\n }\n\n return (\n \n \n \n \n\n {/* Price time evolution */}\n \n\n {/* Capital collected from withdraw fees - AXIS */}\n \n\n } />\n\n \n \n\n }\n />\n }\n />\n\n {/* Capital collected from withdraw fees - AREA */}\n \n\n {/* }\n /> */}\n \n \n \n );\n}\n\nexport default PriceSimulationChart;\n","const low_u = 0.97;\nconst high_u = 1.07;\nconst dump = 0.75;\n\nexport const u_min_t = [\n 1,\n 0.8,\n 0.8,\n 0.9,\n 0.9,\n 0.8,\n 0.6,\n 0.5,\n 0.8,\n 0.9,\n 0.9,\n low_u,\n low_u,\n low_u,\n 0.8,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n low_u,\n low_u,\n 0.97\n];\n\nexport const u_max_t = [\n 3,\n 1.5,\n 1.01,\n 1.04,\n 1.1,\n 1.15,\n 1.15,\n 1.15,\n 1.1,\n 1.1,\n 1.2,\n 1.15,\n high_u,\n high_u,\n 1.3,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n 1.3,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n 1.2,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n 1.4,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n 1.04\n];\n","import React, { useState, useEffect, useMemo } from \"react\";\n// Material UI\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Container from \"@material-ui/core/Container\";\nimport Typography from \"@material-ui/core/Typography\";\nimport Box from \"@material-ui/core/Box\";\nimport Paper from \"@material-ui/core/Paper\";\nimport Grid from \"@material-ui/core/Grid\";\nimport Button from \"@material-ui/core/Button\";\n// Components\nimport Header from \"./Header\";\nimport CurveDesignInputParams from \"./CurveDesignInputParams\";\nimport SimulationInputParams from \"./SimulationInputParams\";\nimport SupplyVsDemandChart from \"./SupplyVsDemandChart\";\nimport ResultParams from \"./ResultParams\";\nimport PriceSimulationChart from \"./PriceSimulationChart\";\nimport HelpText from \"./HelpText\";\n// Text content\nimport {\n parameterDescriptions,\n simulationParameterDescriptions,\n resultParameterDescriptions,\n supplyVsDemandChartDescription,\n simulationChartDescription\n} from \"./parametersDescriptions\";\n// Utils\nimport { getLast, getAvg, pause } from \"./utils\";\nimport {\n getInitialParams,\n getPriceR,\n getMinPrice,\n getS,\n vest_tokens,\n getR,\n getSlippage,\n getTxDistribution,\n getDeltaR_priceGrowth,\n rv_U,\n getMedian,\n getSum\n} from \"./math\";\nimport { throttle } from \"lodash\";\n// Data\nimport { u_min_t, u_max_t } from \"./u_values\";\n// General styles\nimport \"./app.css\";\n\nconst headerOffset = 10;\nconst simulationDuration = 4000;\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n mainContainer: {\n \"& > div:not(:last-child)\": {\n paddingBottom: theme.spacing(3)\n },\n \"& > div\": {\n \"& > div\": {\n paddingTop: \"0 !important\"\n }\n },\n paddingBottom: theme.spacing(9)\n },\n simulationContainer: {\n minHeight: \"442px\"\n },\n paper: {\n width: \"100%\",\n height: \"100%\",\n minHeight: 310,\n backgroundColor: \"#293640\"\n },\n box: {\n padding: theme.spacing(3, 3)\n },\n boxButton: {\n padding: theme.spacing(3, 3)\n },\n boxHeader: {\n padding: theme.spacing(3, 3),\n height: theme.spacing(headerOffset),\n display: \"flex\",\n alignItems: \"center\",\n borderBottom: \"1px solid #313d47\"\n },\n boxBorderBottom: {\n borderBottom: \"1px solid #313d47\"\n },\n initialRaise: {\n justifyContent: \"space-between\"\n },\n boxChart: {\n width: \"100%\",\n height: \"100%\",\n minHeight: 310,\n maxHeight: 350,\n padding: theme.spacing(3, 3),\n // Correct the chart excessive margins\n paddingRight: \"5px\",\n paddingLeft: \"5px\"\n },\n boxPlaceholder: {\n padding: theme.spacing(3, 3),\n display: \"flex\",\n height: \"100%\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: theme.palette.text.secondary,\n opacity: 0.4\n },\n header: {\n backgroundColor: \"#0b1216\",\n color: \"#f8f8f8\",\n textAlign: \"center\",\n padding: theme.spacing(3, 0, 6 + headerOffset),\n marginBottom: -theme.spacing(headerOffset)\n },\n button: {\n // background: \"linear-gradient(290deg, #2ad179, #4ab47c)\", // Green gradient\n background: \"linear-gradient(290deg, #1aa059, #3d9567)\", // Darker Green gradient\n // background: \"linear-gradient(290deg, #1880e0, #3873d8)\", // blue gradient\n color: \"white\"\n },\n // Descriptions\n descriptionContainer: {\n \"& > div:not(:last-child)\": {\n paddingBottom: theme.spacing(1),\n marginBottom: theme.spacing(1),\n borderBottom: \"1px solid #3f5463\"\n },\n \"& td\": {\n verticalAlign: \"top\",\n padding: theme.spacing(0.5)\n }\n },\n descriptionTitle: {\n padding: theme.spacing(0.5)\n },\n descriptionBody: {\n color: \"#dbdfe4\"\n },\n descriptionPadding: {\n padding: theme.spacing(0.5)\n },\n d0Container: {\n \"& > div\": {\n padding: \"0 12px 0 0 !important\",\n display: \"flex\",\n alignItems: \"center\"\n }\n },\n d0Number: {\n padding: \"0 !important\",\n display: \"flex\",\n alignItems: \"center\"\n },\n d0Slidder: {\n padding: \"0 12px 0 0 !important\",\n display: \"flex\",\n alignItems: \"center\"\n }\n })\n);\n\nexport default function App() {\n const [curveParams, setCurveParams] = useState({\n theta: 0.35, // fraction allocated to reserve (.)\n p0: 0.1, // Hatch sale price p0 (DAI / token)\n p1: 0.3, // Return factor (.)\n wFee: 0.05, // friction coefficient (.)\n vHalflife: 17, // Vesting half life (weeks)\n d0: 3e6 // Initial raise, d0 (DAI)\n });\n\n const { d0, theta, p0, p1, wFee, vHalflife } = curveParams;\n\n /**\n * Throttle the curve update to prevent the expensive chart\n * to re-render too often\n */\n const setCurveParamsThrottle = useMemo(\n () => throttle(setCurveParams, 250),\n []\n );\n\n // Simulation results\n const {\n k, // Invariant power kappa (.)\n R0, // Initial reserve (DAI)\n S0, // initial supply of tokens (token)\n V0 // invariant coef\n } = getInitialParams({\n d0,\n theta,\n p0,\n p1\n });\n\n const [priceTimeseries, setPriceTimeseries] = useState([0]);\n const [withdrawFeeTimeseries, setWithdrawFeeTimeseries] = useState([0]);\n const [floorpriceTimeseries, setFloorpriceTimeseries] = useState([0]);\n const [totalReserve, setTotalReserve] = useState(R0);\n const [withdrawCount, setWithdrawCount] = useState(0);\n const [avgSlippage, setAvgSlippage] = useState(0);\n const [avgTxSize, setAvgTxSize] = useState(0);\n // Simulation state variables\n const [simulationActive, setSimulationActive] = useState(false);\n const [simulationRunning, setSimulationRunning] = useState(false);\n\n useEffect(() => {\n setSimulationActive(false);\n }, [curveParams]);\n\n // #### TEST: Immediate simulation\n\n async function startSimulation() {\n // If there's a simulation already active, clear it\n clearSimulation();\n await pause(0);\n\n // Start simulation by setting it to active\n setSimulationActive(true);\n }\n\n function clearSimulation() {\n // Stop simulation\n setSimulationActive(false);\n // Clear simulation variables\n setWithdrawCount(0);\n setPriceTimeseries([0]);\n setWithdrawFeeTimeseries([0]);\n setAvgSlippage(0);\n }\n\n useEffect(() => {\n let canContinueSimulation = true;\n\n async function simulateRandomDelta() {\n const R_t: number[] = [R0];\n const S_t: number[] = [S0];\n const p_t: number[] = [getPriceR({ R: R0, V0, k })];\n const wFee_t: number[] = [0];\n const slippage_t: number[] = [];\n const avgTxSize_t: number[] = [];\n\n // hatchers tokens = S0[section added by Z]\n const H_t: number[] = [S0]; // total hatcher tokens not vested\n const floorprice_t: number[] = []; // initially the price is the floor as all tokens are hatcher tokens\n\n // Random walk\n const numSteps = 52;\n const u_min = 0.97;\n const u_max = 1.04;\n const tx_spread = 10;\n // vesting(should this be exposed in the app ?)\n const cliff = 8; // weeks before vesting starts ~2 months\n // const halflife = 52; // 26 weeks, half life is ~6 months\n // percentage of the hatch tokens which vest per week(since that is our timescale in the sim)\n\n // numSteps = 52 take 8ms to run\n setSimulationRunning(true);\n for (let t = 0; t < numSteps; t++) {\n const txsWeek = rv_U(100, 40 * t + 100);\n\n const R = getLast(R_t);\n const S = getLast(S_t);\n const H = getLast(H_t);\n\n let R_next: number = 0,\n S_next: number = 0,\n H_next: number = 0,\n price_next: number = 0,\n txsWithdraw: number[] = [0],\n floorprice_next: number = 1,\n slippage: number = 0;\n // Run the value compution again if the price goes below the floor price\n\n /**\n * Since the values u_min and u_max are predefined, it's possible that\n * the price becomes less than the floor price. This cannot happen.\n * So the next loop has 10 opportunities to find a price greater than\n * the floor price. The for loop is used to prevent a possible infinite\n * loop if a `while` loop was used.\n */\n for (let i = 0; i < 20 && price_next < floorprice_next * 1.05; i++) {\n // enforce the effects of the unvested tokens not being burnable\n let u_lower: number, u_upper: number;\n // if (H > S) {\n // u_lower = 1;\n // } else {\n // // compute the reserve if all that supply is burned\n // const R_ratio = getR({ S: S - H, V0, k }) / R;\n // u_lower = Math.max(1 - R_ratio, u_min);\n // }\n // let priceGrowth = rv_U(u_lower, u_max);\n\n u_lower = u_min_t[t];\n u_upper = u_max_t[t];\n\n if (i > 15) {\n u_lower = 1.02;\n u_upper = u_upper + 1.04;\n }\n\n const priceGrowth = rv_U(u_lower, u_upper);\n\n const deltaR = getDeltaR_priceGrowth({ R, k, priceGrowth });\n R_next = R + deltaR;\n\n const txs = getTxDistribution({\n sum: deltaR,\n num: txsWeek,\n spread: tx_spread\n });\n // Compute slippage\n const slippage_txs = txs.map(txR =>\n getSlippage({ R, deltaR: txR, V0, k })\n );\n slippage = getMedian(slippage_txs);\n\n txsWithdraw = txs.filter(tx => tx < 0);\n\n // Vest\n const delta_H = vest_tokens({\n week: t,\n H,\n halflife: vHalflife,\n cliff\n });\n H_next = H - delta_H;\n\n // find floor price\n S_next = getS({ R, V0, k });\n floorprice_next = getMinPrice({\n S: S_next,\n H: S_next - H_next,\n V0,\n k\n });\n\n price_next = getPriceR({ R: R_next, V0, k });\n }\n\n const _avgTxSize = getMedian(txsWithdraw);\n const wFees = -wFee * getSum(txsWithdraw);\n\n R_t.push(R_next);\n S_t.push(S_next);\n H_t.push(H_next);\n p_t.push(price_next);\n slippage_t.push(slippage);\n avgTxSize_t.push(_avgTxSize);\n wFee_t.push(getLast(wFee_t) + wFees);\n\n floorprice_t.push(floorprice_next);\n setWithdrawCount(c => c + txsWithdraw.length);\n\n // Stop the simulation if it's no longer active\n if (!simulationActive || !canContinueSimulation) break;\n }\n\n // floorprice_t is missing one data point\n floorprice_t[floorprice_t.length] = floorprice_t[floorprice_t.length - 1];\n\n setPriceTimeseries(p_t);\n setWithdrawFeeTimeseries(wFee_t);\n setFloorpriceTimeseries(floorprice_t);\n setAvgSlippage(getAvg(slippage_t));\n setAvgTxSize(getAvg(avgTxSize_t.filter(n => !isNaN(n))));\n setTotalReserve(getLast(R_t));\n\n setSimulationRunning(false);\n }\n\n if (simulationActive) simulateRandomDelta();\n // Return an \"unsubscribe\" function that halts the run\n return () => {\n canContinueSimulation = false;\n };\n }, [simulationActive]);\n\n // End results computed for chart visualization\n const initialHatchFunds = d0 * theta;\n const totalFundsRaisedTimeseries = withdrawFeeTimeseries.map(\n x => x + initialHatchFunds\n );\n\n const totalInitialHatchFunds = Math.round(d0 * theta);\n const totalExitTributes = Math.round(getLast(withdrawFeeTimeseries));\n const totalFunds = totalInitialHatchFunds + totalExitTributes;\n const formatFunds = (n: number) => (+n.toPrecision(3)).toLocaleString();\n\n const resultFields = [\n {\n label: resultParameterDescriptions.totalReserve.name,\n description: resultParameterDescriptions.totalReserve.text,\n value: (+totalReserve.toPrecision(3)).toLocaleString() + \" DAI\"\n },\n {\n label: resultParameterDescriptions.slippage.name,\n description: resultParameterDescriptions.slippage.text,\n value: +(100 * avgSlippage).toFixed(3) + \" %\",\n valueFooter: `Avg tx size ${Math.round(avgTxSize).toLocaleString()} DAI`\n },\n {\n label: resultParameterDescriptions.initialHatchFunds.name,\n description: resultParameterDescriptions.initialHatchFunds.text,\n value: formatFunds(totalInitialHatchFunds) + \" DAI\"\n },\n {\n label: resultParameterDescriptions.exitTributes.name,\n description: resultParameterDescriptions.exitTributes.text,\n value: formatFunds(totalExitTributes) + \" DAI\",\n valueFooter: `From ${withdrawCount} exit txs`\n },\n {\n label: resultParameterDescriptions.totalRaised.name,\n description: resultParameterDescriptions.totalRaised.text,\n value: formatFunds(totalFunds) + \" DAI\"\n }\n ];\n\n const classes = useStyles();\n\n return (\n <>\n
\n \n
\n \n
\n\n \n \n \n \n \n Curve Design\n \n \n\n \n \n \n \n \n\n \n \n \n Preview\n \n \n\n \n \n \n \n \n \n\n \n \n \n \n \n \n\n \n \n \n Run simulation\n \n \n \n \n \n \n\n \n {simulationActive ? (\n <>\n \n \n \n Simulation\n \n \n\n \n \n \n \n \n\n \n \n \n Results\n \n \n\n \n \n \n \n \n \n ) : (\n \n \n \n \n Run a simulation to see results\n \n \n \n \n )}\n \n \n \n );\n}\n","import red from \"@material-ui/core/colors/red\";\nimport { createMuiTheme } from \"@material-ui/core/styles\";\n\n// A custom theme for this app\nconst theme = createMuiTheme({\n palette: {\n type: \"dark\",\n primary: {\n main: \"#2ecd79\"\n },\n secondary: {\n main: \"#116be0\",\n light: \"#0f8bff\",\n dark: \"#116be0\"\n },\n error: {\n main: red.A400\n },\n background: {\n default: \"#fff\",\n paper: \"#293640\"\n },\n text: {\n primary: \"#fff\",\n secondary: \"#9aa3ad\"\n }\n },\n typography: {\n h6: {\n fontWeight: 400\n }\n }\n});\n\nconsole.log(theme);\n\nexport default theme;\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport CssBaseline from '@material-ui/core/CssBaseline';\nimport { ThemeProvider } from '@material-ui/styles';\nimport App from './App';\nimport theme from './theme';\n\nReactDOM.render(\n \n {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}\n \n \n ,\n document.querySelector('#root'),\n);\n"],"sourceRoot":""} \ No newline at end of file diff --git a/static/js/main.5d956bc1.chunk.js b/static/js/main.5d956bc1.chunk.js new file mode 100644 index 0000000..5651f3a --- /dev/null +++ b/static/js/main.5d956bc1.chunk.js @@ -0,0 +1,2 @@ +(window["webpackJsonpaugmented-tbc-design"]=window["webpackJsonpaugmented-tbc-design"]||[]).push([[0],{216:function(e,t,a){e.exports=a(408)},406:function(e,t,a){},407:function(e,t,a){},408:function(e,t,a){"use strict";a.r(t);var n=a(1),r=a.n(n),i=a(14),o=a.n(i),c=a(448),l=a(447),s=a(63),u=a.n(s),m=a(114),d=a(4),p=a(409),f=a(454),h=a(446),g=a(410),b=a(450),v=a(444),x=a(445),E=a(452),y=a(443),O="https://medium.com/giveth/deep-dive-augmented-bonding-curves-3f1f7c1fa751",k=Object(p.a)(function(e){return Object(f.a)({container:{display:"flex",flexDirection:"column",alignItems:"center"},title:{},subtitle:{color:e.palette.text.secondary,margin:e.spacing(3,0,0),maxWidth:e.spacing(82)},subsubtitle:{color:e.palette.text.secondary,opacity:.6,maxWidth:e.spacing(74)},lightBulb:{verticalAlign:"middle",marginRight:e.spacing(1)},link:{color:e.palette.primary.main},logoContainer:{display:"flex",alignItems:"center",justifyContent:"center",marginBottom:e.spacing(4)},logo:{width:"25px",marginRight:"4px"},logoText:{display:"inline",fontSize:"1.1rem",fontWeight:500}})});function j(){var e=k();return r.a.createElement("div",{className:e.container},r.a.createElement("div",{className:e.logoContainer},r.a.createElement("img",{src:"./favicon.ico",className:e.logo,alt:"logo"}),r.a.createElement(g.a,{className:e.logoText},"Commons Stack")),r.a.createElement(g.a,{className:e.title,variant:"h4"},"Augmented Bonding Curve Design"),r.a.createElement(g.a,{className:e.subtitle},"Experiment with the Commons Stack's Augmented Bonding Curve component. Change the Hatch variables to explore what continuous funding streams can do for your community."),r.a.createElement(g.a,{className:e.subsubtitle},"Read more about the Augmented Bonding Curve"," ",r.a.createElement(y.a,{href:O},"here"),". Note that this is a demo for illustration purposes only, a narrative showcase of cadCAD's capabilities."))}var C=a(12),w=a(3),N=a(449),B=a(81),S=a.n(B),F=a(8),P=a(453),R=Object(F.a)({root:{height:8},thumb:{height:24,width:24,backgroundColor:"#fff",border:"2px solid currentColor",marginTop:-8,marginLeft:-12,"&:focus,&:hover,&$active":{boxShadow:"inherit"}},active:{},valueLabel:{left:"calc(-50% + 4px)"},track:{height:8,borderRadius:4},rail:{height:8,borderRadius:4},markLabel:{top:30}})(P.a),A=a(451),T=Object(p.a)(function(e){var t;return{container:{color:e.palette.text.secondary,display:"flex",fontSize:"0.9rem",cursor:"pointer",transition:"color ease 150ms","&:hover":{color:"#c3c9d0"}},popoverContainer:{padding:e.spacing(2),"& > p:not(:last-child)":{paddingBottom:e.spacing(1),marginBottom:e.spacing(1),borderBottom:"1px solid #3f5463"}},paper:(t={backgroundColor:"#384b59",maxWidth:.9*e.breakpoints.values.md},Object(C.a)(t,"@media screen and (max-width: ".concat(e.breakpoints.values.md,"px)"),{maxWidth:"90vw"}),Object(C.a)(t,"padding",e.spacing(.5)),t),descriptionBody:{color:"#dbdfe4"}}});function I(e){var t=e.content,a=e.popoverText,n=T(),i=r.a.useState(null),o=Object(d.a)(i,2),c=o[0],l=o[1];function s(){l(null)}var u=Boolean(c),m=u?"simple-popover":void 0;return r.a.createElement("div",{className:n.container},r.a.createElement("div",{"aria-describedby":m,onClick:function(e){l(e.currentTarget)}},r.a.createElement(g.a,null,t)),r.a.createElement(A.a,{PaperProps:{className:n.paper},id:m,open:u,anchorEl:c,onClose:s,onClick:s,anchorOrigin:{vertical:"bottom",horizontal:"center"},transformOrigin:{vertical:"top",horizontal:"center"}},r.a.createElement(b.a,{className:n.popoverContainer},r.a.createElement(g.a,null,t),r.a.createElement(g.a,{className:n.descriptionBody},a))))}var M=Object(p.a)(function(e){return Object(f.a)({root:{margin:e.spacing(6,0,3)},lightBulb:{verticalAlign:"middle",marginRight:e.spacing(1)},leftContainer:{color:e.palette.text.secondary},centerContainer:{},listBoxContainer:{"& > div:not(:last-child)":{paddingBottom:"12px",marginBottom:"12px",borderBottom:"1px solid #313d47"}},listBox:{"& > div":{display:"flex",alignItems:"center","& p":{marginBottom:0}},"& > div:not(:last-child)":{paddingRight:"12px"}},slider:{color:e.palette.primary.main}})});function D(e){var t=e.inputRef,a=e.onChange,n=e.prefix,i=e.suffix,o=Object(w.a)(e,["inputRef","onChange","prefix","suffix"]);return r.a.createElement(S.a,Object.assign({},o,{getInputRef:t,onValueChange:function(e){a({target:{value:e.value}})},thousandSeparator:!0,prefix:n,suffix:i}))}function H(e){var t=e.inputFields,a=e.onChangeCommited,n=M();return r.a.createElement("div",{className:n.listBoxContainer},t.map(function(e){var t=e.label,i=e.description,o=e.value,c=e.setter,l=e.min,s=e.max,u=e.step,m=e.prefix,d=e.suffix,p=e.format,f=e.toText,h=e.toNum;function g(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;isNaN(e)&&(e=0),e>s?e=s:ee*N&&b(e*N)},min:.01,max:1,step:.01,toText:function(e){return String(+e.toFixed(2))},toNum:function(e){return parseFloat(e)},format:function(e){return"$".concat(e)}},{label:"".concat(V.p1.name," (DAI/token)"),description:V.p1.text,value:g,setter:b,min:Number((B*(m||.1)).toFixed(2)),max:Number((N*m).toFixed(2)),step:.01,toText:function(e){return String(+e.toFixed(2))},toNum:function(e){return parseFloat(e)},format:function(e){return"$".concat(e)}},{label:V.wFee.name,description:V.wFee.text,value:E,setter:y,min:0,max:.1,step:.001,suffix:"%",format:function(e){return"".concat(+(100*e).toFixed(1),"%")},toText:function(e){return String(+(100*e).toFixed(1))},toNum:function(e){return.01*parseFloat(e)}},{label:"".concat(V.vHalflife.name," (weeks)"),description:V.vHalflife.text,value:j,setter:w,min:1,max:104,step:1,suffix:"",format:function(e){return String(Math.round(e))},toText:function(e){return String(Math.round(e))},toNum:function(e){return Math.round(parseInt(e))}}];return r.a.createElement(H,{inputFields:S,onChangeCommited:function(){a(function(e){return function(e){for(var t=1;t div:not(:last-child)":{paddingBottom:e.spacing(1),marginBottom:e.spacing(1),borderBottom:"1px solid #3f5463"},"& td":{verticalAlign:"top",padding:e.spacing(.5)}},descriptionTitle:{padding:e.spacing(.5)},descriptionBody:{color:"#dbdfe4",padding:e.spacing(.5)},descriptionPadding:{padding:e.spacing(.5)}}});function Q(e){var t=e.text,a=e.title,n=e.table,i=e.body,o=U(),c=r.a.useState(null),l=Object(d.a)(c,2),s=l[0],u=l[1];function m(){u(null)}var p=Boolean(s),f=p?"simple-popover":void 0;return r.a.createElement("div",{className:o.container},r.a.createElement(J.a,{onClick:function(e){u(e.currentTarget)}}),r.a.createElement(A.a,{PaperProps:{className:o.paper},id:f,open:p,anchorEl:s,onClose:m,onClick:m,anchorOrigin:{vertical:"bottom",horizontal:"center"},transformOrigin:{vertical:"top",horizontal:"center"}},r.a.createElement(b.a,{className:o.popoverContainer},r.a.createElement("div",{className:o.descriptionContainer},a&&r.a.createElement("div",null,r.a.createElement(g.a,{className:o.descriptionTitle},a)),i&&r.a.createElement("div",null,r.a.createElement(g.a,{className:o.descriptionBody},i)),n&&r.a.createElement("div",null,r.a.createElement("table",null,r.a.createElement("tbody",null,n.map(function(e){var t=e.name,a=e.text;return r.a.createElement("tr",{key:t},r.a.createElement("td",null,r.a.createElement(g.a,null,t)),r.a.createElement("td",null,r.a.createElement(g.a,{className:o.descriptionBody},a)))})))),t))))}var X=Object(p.a)(function(e){return Object(f.a)({root:{margin:e.spacing(6,0,3)},lightBulb:{verticalAlign:"middle",marginRight:e.spacing(1)},leftContainer:{},centerContainer:{},listBoxContainer:{"& > div:not(:last-child)":{paddingBottom:"12px",marginBottom:"12px",borderBottom:"1px solid #313d47"}},listBox:{"& > div":{display:"flex",alignItems:"center","& p":{marginBottom:0}},"& > div:not(:last-child)":{paddingRight:"12px"}},slider:{color:e.palette.primary.main}})});function Y(e){var t=e.inputRef,a=e.onChange,n=e.prefix,i=e.suffix,o=Object(w.a)(e,["inputRef","onChange","prefix","suffix"]);return r.a.createElement(S.a,Object.assign({},o,{getInputRef:t,onValueChange:function(e){a({target:{value:e.value}})},thousandSeparator:!0,prefix:n,suffix:i}))}function Z(e){var t=e.inputFields,a=e.onChangeCommited,n=X();return r.a.createElement("div",{className:n.listBoxContainer},t.map(function(e){var t=e.label,i=e.description,o=e.value,c=e.setter,l=e.min,s=e.max,u=e.step,m=e.prefix,d=e.suffix,p=e.format,f=e.toText,h=e.toNum;function b(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;isNaN(e)&&(e=0),e>s?e=s:e5e8?[1e9,"B"]:e>5e5?[1e6,"M"]:e>500?[1e3,"K"]:[1,""],a=Object(d.a)(t,2);return{scaling:a[0],unit:a[1]}}var le=a(19);function se(e){var t=e.d0,a=e.theta,n=e.p0,r=e.p1/n/(1-a),i=(1-a)*t,o=t/n;return{k:r,R0:i,S0:o,V0:Math.pow(o,r)/i}}function ue(e){var t=e.S,a=e.V0,n=e.k;return Math.pow(t,n)/a}function me(e){var t=e.R,a=e.V0,n=e.k;return Math.pow(a*t,1/n)}function de(e){var t=e.S,a=e.H,n=e.V0,r=e.k;if(t===a){var i=pe({R:ue({S:t,V0:n,k:r}),V0:n,k:r});return Math.abs(i)}return pe({R:ue({S:t-a,V0:n,k:r}),V0:n,k:r})}function pe(e){var t=e.R,a=e.V0,n=e.k;return n*Math.pow(t,(n-1)/n)/Math.pow(a,1/n)}function fe(e){var t=e.R,a=e.deltaR,n=e.V0,r=e.k,i=Math.pow(n*t,1/r),o=a/(Math.pow(n*(t+a),1/r)-i),c=pe({R:t,V0:n,k:r});return Math.abs(o-c)/c}function he(e){var t=e.R,a=e.k,n=e.priceGrowth;return-t+Math.pow(n*Math.pow(t,1-1/a),a/(-1+a))}function ge(e){for(var t=e.sum,a=e.num,n=t/a,r=n*e.spread,i=[],o=0;o1||r<0)&&(r=xe(e,t)),r*=t-e,r+=e}function Ee(e){var t=Math.floor(e.length/2),a=Object(le.a)(e).sort(function(e,t){return e-t});return e.length%2!==0?a[t]:(a[t-1]+a[t])/2}var ye=a(185),Oe=!1,ke="x",je="Supply (tokens) / Collateral (DAI)",Ce="#b7c1cb",we=Object(p.a)(function(e){return Object(f.a)({tooltip:{border:"1px solid #313d47",backgroundColor:"#384b59",padding:e.spacing(1),color:"#c7ccd2"}})});var Ne=function(e){for(var t=e.theta,a=se({d0:e.d0,theta:t,p0:e.p0,p1:e.p1}),n=a.k,i=a.R0,o=a.S0,c=a.V0,l=Math.round(i),s=function(e){return o*Math.pow(e/l,1/n)},u=4*l,m=Math.round((u-0)/100),p=ce(Math.max(u,s(u))),f=p.scaling,h=p.unit,g=[],b=0;b<101;b++){var v,x=Math.round(0+m*b);g.push((v={},Object(C.a)(v,ke,x),Object(C.a)(v,je,s(x)),v))}var E=Object(ye.a)(),y=we(),O=function(e){return(+(e/f).toPrecision(2)).toLocaleString()};return r.a.createElement(te.g,{debounce:1},r.a.createElement(te.b,{width:0,height:400,data:g,margin:{top:10,right:30,left:0,bottom:0}},r.a.createElement(te.c,{vertical:!1,stroke:E.palette.text.secondary,strokeOpacity:.13}),r.a.createElement(te.i,{interval:24,dataKey:ke,tickFormatter:O,unit:h,tick:{fill:E.palette.text.secondary},stroke:E.palette.text.secondary}),r.a.createElement(te.j,{interval:"preserveStartEnd",ticks:ne(g.map(function(e){return e[je]}),3),tickFormatter:O,unit:h,tick:{fill:E.palette.text.secondary},domain:[0,s(u)],stroke:E.palette.text.secondary}),r.a.createElement(te.h,{content:r.a.createElement(function(e){var t=e.active,a=e.payload,i=e.label;if(t){var o=a[0].value,l=i,s=pe({R:l,V0:c,k:n}),u=[["Supply",O(o)+h,"tokens"],["Collateral",O(l)+h,"DAI"],["Price",s.toFixed(2),"DAI/token"]];return r.a.createElement("div",{className:y.tooltip},r.a.createElement("table",null,r.a.createElement("tbody",null,u.map(function(e){var t=Object(d.a)(e,3),a=t[0],n=t[1],i=t[2];return r.a.createElement("tr",{key:a},r.a.createElement("td",null,a),r.a.createElement("td",null,n),r.a.createElement("td",null,i))}))))}return null},null)}),r.a.createElement(te.a,{isAnimationActive:Oe,type:"monotone",dataKey:je,stroke:E.palette.primary.main,fill:E.palette.primary.main,fillOpacity:.3,strokeWidth:2}),r.a.createElement(te.f,{x:l,y:s(l),stroke:"transparent",strokeDasharray:"9 0",label:r.a.createElement(function(e){var t=e.textAnchor,a=e.viewBox;return r.a.createElement("text",{x:a.x+a.width/4+10,y:a.y+20,fill:Ce,textAnchor:t},"Initial Token Supply")},null)}),r.a.createElement(te.e,{x:l,y:s(l),r:6,fill:E.palette.primary.main,stroke:2}),r.a.createElement(te.d,{formatter:function(e){return r.a.createElement("span",{style:{color:E.palette.text.secondary}},e)}})))};a(406);function Be(){return r.a.createElement("div",{className:"spinner"},r.a.createElement("div",{className:"bounce1"}),r.a.createElement("div",{className:"bounce2"}),r.a.createElement("div",{className:"bounce3"}))}var Se=Object(p.a)(function(e){return Object(f.a)({root:{margin:e.spacing(6,0,3)},lightBulb:{verticalAlign:"middle",marginRight:e.spacing(1)},leftContainer:{color:e.palette.text.secondary},centerContainer:{},listBoxContainer:{"& > div:not(:last-child)":{marginBottom:"12px",borderBottom:"1px solid #313d47"}},listBox:{paddingBottom:"12px","& > div":{display:"flex",alignItems:"center","& p":{marginBottom:0}},"& > div:not(:last-child)":{paddingRight:"12px"}},valueFooter:{color:e.palette.text.secondary,fontSize:"80%"}})});function Fe(e){var t=e.resultFields,a=e.simulationDuration,i=Object(n.useState)(!0),o=Object(d.a)(i,2),c=o[0],l=o[1];Object(n.useEffect)(function(){var e=setTimeout(function(){l(!1)},a);return function(){clearTimeout(e)}});var s=Se();return r.a.createElement("div",{className:s.listBoxContainer},t.map(function(e){var t=e.label,a=e.description,n=e.value,i=e.valueFooter;return r.a.createElement(x.a,{key:t,container:!0,spacing:0,className:s.listBox},r.a.createElement(x.a,{item:!0,xs:8,className:s.leftContainer},r.a.createElement(I,{content:t,popoverText:a})),r.a.createElement(x.a,{item:!0,xs:4,className:s.centerContainer},c?r.a.createElement(Be,null):r.a.createElement("div",null,r.a.createElement(g.a,null,n),i&&r.a.createElement(g.a,{className:s.valueFooter},i))))}))}var Pe="x",Re="Price (DAI/token)",Ae="Floor price (DAI/token)",Te="Total funds raised (DAI)",Ie="Post-Hatch price",Me="Hatch price",De="#53c388",He="#4090d9",Ve="#b7c1cb",Le=Object(p.a)(function(e){return Object(f.a)({tooltip:{border:"1px solid #313d47",backgroundColor:"#384b59",padding:e.spacing(1),color:"#c7ccd2"}})});var We=function(e){for(var t=e.priceTimeseries,a=e.totalFundsRaisedTimeseries,i=e.floorpriceTimeseries,o=e.simulationDuration,c=e.p0,l=e.p1,s=[],u=0;u div:not(:last-child)":{paddingBottom:e.spacing(3)},"& > div":{"& > div":{paddingTop:"0 !important"}},paddingBottom:e.spacing(9)},simulationContainer:{minHeight:"442px"},paper:{width:"100%",height:"100%",minHeight:310,backgroundColor:"#293640"},box:{padding:e.spacing(3,3)},boxButton:{padding:e.spacing(3,3)},boxHeader:{padding:e.spacing(3,3),height:e.spacing(10),display:"flex",alignItems:"center",borderBottom:"1px solid #313d47"},boxBorderBottom:{borderBottom:"1px solid #313d47"},initialRaise:{justifyContent:"space-between"},boxChart:{width:"100%",height:"100%",minHeight:310,maxHeight:350,padding:e.spacing(3,3),paddingRight:"5px",paddingLeft:"5px"},boxPlaceholder:{padding:e.spacing(3,3),display:"flex",height:"100%",alignItems:"center",justifyContent:"center",color:e.palette.text.secondary,opacity:.4},header:{backgroundColor:"#0b1216",color:"#f8f8f8",textAlign:"center",padding:e.spacing(3,0,16),marginBottom:-e.spacing(10)},button:{background:"linear-gradient(290deg, #1aa059, #3d9567)",color:"white"},descriptionContainer:{"& > div:not(:last-child)":{paddingBottom:e.spacing(1),marginBottom:e.spacing(1),borderBottom:"1px solid #3f5463"},"& td":{verticalAlign:"top",padding:e.spacing(.5)}},descriptionTitle:{padding:e.spacing(.5)},descriptionBody:{color:"#dbdfe4"},descriptionPadding:{padding:e.spacing(.5)},d0Container:{"& > div":{padding:"0 12px 0 0 !important",display:"flex",alignItems:"center"}},d0Number:{padding:"0 !important",display:"flex",alignItems:"center"},d0Slidder:{padding:"0 12px 0 0 !important",display:"flex",alignItems:"center"}})});var Je=a(183),Ue=a.n(Je),Qe=a(184),Xe=Object(Qe.a)({palette:{type:"dark",primary:{main:"#2ecd79"},secondary:{main:"#116be0",light:"#0f8bff",dark:"#116be0"},error:{main:Ue.a.A400},background:{default:"#fff",paper:"#293640"},text:{primary:"#fff",secondary:"#9aa3ad"}},typography:{h6:{fontWeight:400}}});console.log(Xe);var Ye=Xe;o.a.render(r.a.createElement(l.a,{theme:Ye},r.a.createElement(c.a,null),r.a.createElement(function(){var e=Object(n.useState)({theta:.35,p0:.1,p1:.3,wFee:.05,vHalflife:17,d0:3e6}),t=Object(d.a)(e,2),a=t[0],i=t[1],o=a.d0,c=a.theta,l=a.p0,s=a.p1,p=a.wFee,f=a.vHalflife,y=Object(n.useMemo)(function(){return Object(ze.throttle)(i,250)},[]),O=se({d0:o,theta:c,p0:l,p1:s}),k=O.k,C=O.R0,w=O.S0,N=O.V0,B=Object(n.useState)([0]),S=Object(d.a)(B,2),F=S[0],P=S[1],R=Object(n.useState)([0]),A=Object(d.a)(R,2),T=A[0],I=A[1],M=Object(n.useState)([0]),D=Object(d.a)(M,2),H=D[0],$=D[1],G=Object(n.useState)(C),J=Object(d.a)(G,2),U=J[0],X=J[1],Y=Object(n.useState)(0),Z=Object(d.a)(Y,2),_=Z[0],te=Z[1],ae=Object(n.useState)(0),ne=Object(d.a)(ae,2),ce=ne[0],le=ne[1],ue=Object(n.useState)(0),xe=Object(d.a)(ue,2),ye=xe[0],Oe=xe[1],ke=Object(n.useState)(!1),je=Object(d.a)(ke,2),Ce=je[0],we=je[1],Be=Object(n.useState)(!1),Se=Object(d.a)(Be,2),Pe=Se[0],Re=Se[1];function Ae(){return(Ae=Object(m.a)(u.a.mark(function e(){return u.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return Te(),e.next=3,oe(0);case 3:we(!0);case 4:case"end":return e.stop()}},e)}))).apply(this,arguments)}function Te(){we(!1),te(0),P([0]),I([0]),le(0)}Object(n.useEffect)(function(){we(!1)},[a]),Object(n.useEffect)(function(){var e=!0;function t(){return(t=Object(m.a)(u.a.mark(function t(){var a,n,r,i,o,c,l,s,m,d,h;return u.a.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:a=[C],n=[w],r=[pe({R:C,V0:N,k:k})],i=[0],o=[],c=[],l=[w],s=[],m=52,.97,1.04,10,8,Re(!0),d=function(t){for(var u=ve(100,40*t+100),m=re(a),d=(re(n),re(l)),h=0,g=0,b=0,v=0,x=[0],E=1,y=0,O=0;O<20&&v<1.05*E;O++){var j=void 0,C=void 0;j=Ke[t],C=$e[t],O>15&&(j=1.02,C+=1.04);var w=ve(j,C),B=he({R:m,k:k,priceGrowth:w});h=m+B;var S=ge({sum:B,num:u,spread:10});y=Ee(S.map(function(e){return fe({R:m,deltaR:e,V0:N,k:k})})),x=S.filter(function(e){return e<0}),b=d-be({week:t,H:d,halflife:f,cliff:8}),E=de({S:g=me({R:m,V0:N,k:k}),H:g-b,V0:N,k:k}),v=pe({R:h,V0:N,k:k})}var F=Ee(x),P=-p*x.reduce(function(e,t){return e+t},0);if(a.push(h),n.push(g),l.push(b),r.push(v),o.push(y),c.push(F),i.push(re(i)+P),s.push(E),te(function(e){return e+x.length}),!Ce||!e)return"break"},h=0;case 16:if(!(h\n createStyles({\n container: {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\"\n },\n title: {\n // color: theme.palette.text.secondary,\n },\n subtitle: {\n color: theme.palette.text.secondary,\n margin: theme.spacing(3, 0, 0),\n maxWidth: theme.spacing(82)\n },\n subsubtitle: {\n color: theme.palette.text.secondary,\n opacity: 0.6,\n maxWidth: theme.spacing(74)\n },\n lightBulb: {\n verticalAlign: \"middle\",\n marginRight: theme.spacing(1)\n },\n link: {\n color: theme.palette.primary.main\n },\n logoContainer: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n marginBottom: theme.spacing(4)\n },\n logo: {\n width: \"25px\",\n marginRight: \"4px\"\n },\n logoText: {\n display: \"inline\",\n fontSize: \"1.1rem\",\n fontWeight: 500\n }\n })\n);\n\nexport default function Header() {\n const classes = useStyles();\n return (\n
\n
\n \"logo\"\n Commons Stack\n
\n\n \n Augmented Bonding Curve Design\n \n\n \n Experiment with the Commons Stack's Augmented Bonding Curve component.\n Change the Hatch variables to explore what continuous funding streams \n can do for your community.\n \n \n Read more about the Augmented Bonding Curve{\" \"}\n here. Note that this is a demo for\n illustration purposes only, a narrative showcase of cadCAD's\n capabilities.\n \n
\n );\n}\n","import { withStyles } from \"@material-ui/core/styles\";\nimport Slider from \"@material-ui/core/Slider\";\n\nexport default withStyles({\n root: {\n height: 8\n },\n thumb: {\n height: 24,\n width: 24,\n backgroundColor: \"#fff\",\n border: \"2px solid currentColor\",\n marginTop: -8,\n marginLeft: -12,\n \"&:focus,&:hover,&$active\": {\n boxShadow: \"inherit\"\n }\n },\n active: {},\n valueLabel: {\n left: \"calc(-50% + 4px)\"\n },\n track: {\n height: 8,\n borderRadius: 4\n },\n rail: {\n height: 8,\n borderRadius: 4\n },\n markLabel: {\n top: 30\n }\n})(Slider);\n","import React from \"react\";\nimport { makeStyles } from \"@material-ui/core/styles\";\nimport Popover from \"@material-ui/core/Popover\";\nimport Typography from \"@material-ui/core/Typography\";\nimport Box from \"@material-ui/core/Box\";\n\nconst useStyles = makeStyles(theme => ({\n container: {\n color: theme.palette.text.secondary,\n display: \"flex\",\n fontSize: \"0.9rem\",\n cursor: \"pointer\",\n transition: \"color ease 150ms\",\n \"&:hover\": {\n color: \"#c3c9d0\"\n }\n },\n popoverContainer: {\n padding: theme.spacing(2),\n \"& > p:not(:last-child)\": {\n paddingBottom: theme.spacing(1),\n marginBottom: theme.spacing(1),\n borderBottom: \"1px solid #3f5463\"\n }\n },\n paper: {\n backgroundColor: \"#384b59\",\n maxWidth: theme.breakpoints.values.md * 0.9,\n [`@media screen and (max-width: ${theme.breakpoints.values.md}px)`]: {\n maxWidth: \"90vw\"\n },\n padding: theme.spacing(0.5)\n },\n descriptionBody: {\n color: \"#dbdfe4\"\n }\n}));\n\nexport default function TextWithPopover({\n content,\n popoverText\n}: {\n content: string;\n popoverText: string;\n}) {\n const classes = useStyles();\n const [anchorEl, setAnchorEl] = React.useState(null);\n\n function handleClick(event: any) {\n setAnchorEl(event.currentTarget);\n }\n\n function handleClose() {\n setAnchorEl(null);\n }\n\n const open = Boolean(anchorEl);\n const id = open ? \"simple-popover\" : undefined;\n\n return (\n
\n
\n {content}\n
\n \n \n {content}\n \n {popoverText}\n \n \n \n
\n );\n}\n","import React from \"react\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Grid from \"@material-ui/core/Grid\";\nimport TextField from \"@material-ui/core/TextField\";\nimport NumberFormat from \"react-number-format\";\nimport { InputFieldInterface } from \"./types\";\nimport PrettoSlider from \"./PrettoSlider\";\nimport TextWithPopover from \"./TextWithPopover\";\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n root: {\n margin: theme.spacing(6, 0, 3)\n },\n lightBulb: {\n verticalAlign: \"middle\",\n marginRight: theme.spacing(1)\n },\n leftContainer: {\n color: theme.palette.text.secondary\n },\n centerContainer: {\n // color: blackColor\n },\n listBoxContainer: {\n \"& > div:not(:last-child)\": {\n paddingBottom: \"12px\",\n marginBottom: \"12px\",\n borderBottom: \"1px solid #313d47\"\n }\n },\n listBox: {\n \"& > div\": {\n display: \"flex\",\n alignItems: \"center\",\n \"& p\": {\n marginBottom: 0\n }\n },\n \"& > div:not(:last-child)\": {\n paddingRight: \"12px\"\n }\n },\n slider: {\n color: theme.palette.primary.main\n }\n })\n);\n\nfunction NumberFormatCustom(props: any) {\n const { inputRef, onChange, prefix, suffix, ...other } = props;\n\n return (\n {\n onChange({ target: { value: values.value } });\n }}\n thousandSeparator\n prefix={prefix}\n suffix={suffix}\n />\n );\n}\n\nexport default function InputParams({\n inputFields,\n onChangeCommited\n}: {\n inputFields: InputFieldInterface[];\n onChangeCommited(): void;\n}) {\n const classes = useStyles();\n\n return (\n
\n {inputFields.map(\n ({\n label,\n description,\n value,\n setter,\n min,\n max,\n step,\n prefix,\n suffix,\n format,\n toText,\n toNum\n }) => {\n function sanitizeInput(num: number = 0) {\n if (isNaN(num)) num = 0;\n if (num > max) num = max;\n else if (num < min) num = min;\n setter(num);\n }\n\n return (\n \n \n \n \n\n \n {\n sanitizeInput(\n toNum ? toNum(e.target.value) : parseFloat(e.target.value)\n );\n onChangeCommited();\n }}\n InputProps={{\n inputComponent: NumberFormatCustom,\n disableUnderline: true,\n inputProps: {\n prefix,\n suffix\n }\n }}\n value={toText ? toText(value) : value}\n />\n \n\n \n sanitizeInput(Number(newValue))}\n onChangeCommitted={onChangeCommited}\n value={value}\n min={min}\n max={max}\n step={step}\n valueLabelFormat={value => format(value).replace(\"$\", \"\")}\n />\n \n \n );\n }\n )}\n
\n );\n}\n","export interface DescriptionObject {\n [key: string]: { name: string; text: string };\n}\n\nexport const parameterDescriptions: DescriptionObject = {\n theta: {\n name: \"Hatch Raise % to funding pool\",\n text:\n \"The percentage of the funds raised in the Hatch going directly to funding pool to be used to support the Commons, the rest goes to the collateral pool\"\n },\n p0: {\n name: \"Hatch price\",\n text: \"The price paid per token by when hatching the project\"\n },\n p1: {\n name: \"Post-Hatch price\",\n text:\n \"The price per token after the Hatch ends, the curve is set, and anyone can interact with the bonding curve\"\n },\n wFee: {\n name: \"Exit tribute\",\n text:\n \"The percentage that goes to the funding pool when token holders 'sell' by burning their token at the price determined by the bonding curve\"\n },\n vHalflife: {\n name: \"Vesting half-life\",\n text:\n \"Tokens that are purchased during the Hatch are locked for 8 weeks and then released slowly such that 50% of the tokens will be able to be sold after this many weeks and 87.5% of the tokens after 3x this many weeks\"\n },\n d0: {\n name: \"Hatch Raise\",\n text: \"Amount of funds contributed during the hatch period\"\n }\n};\n\nexport const supplyVsDemandChartDescription =\n \"Visualization of the bonding curve up to 4x the initial size of the Collateral Pool Post-Hatch. This result is deterministic given the curve parameters and the Hatch raise. It will never change regardless of the campaign's performance, it simply shows how the price will react to changes in the Collateral Pool.\";\n\nexport const simulationChartDescription =\n \"This chart shows a 52 week simulation of discrete transactions interacting with the Augmented Bonding Curve. Each transaction adds to or subtracts reserve from the system, modifying the price over time. The frequency, size and direction of each transaction is computed from a set of bounded random functions. This is a NOT a cadCAD simulation, but it showcases the intention behind cadCAD.\";\n\nexport const simulationParameterDescriptions: DescriptionObject = {\n price: {\n name: \"Price\",\n text: \"Price of the token over time.\"\n },\n floorPrice: {\n name: \"Floor price\",\n text:\n \"Lower bound of the price guaranteed by the vesting of hatch tokens. It decreases over time as more hatch tokens are allowed to be traded\"\n },\n totalRaised: {\n name: \"Total funds raised\",\n text: \"Cumulative sum of the funds sent to the Funding Pool\"\n }\n};\n\nexport const resultParameterDescriptions: DescriptionObject = {\n totalReserve: {\n name: \"Collateral pool balance\",\n text: \"Total DAI in the collateral pool at the end of the simulated period\"\n },\n slippage: {\n name: \"Median slippage\",\n text:\n \"Median of change in price a user experiences from the current price to the price received for exiting/selling/burning\"\n },\n initialHatchFunds: {\n name: \"Funds generated from Raise Hatch\",\n text: \"Funds raised during the Hatch that go directly to the cause\"\n },\n exitTributes: {\n name: \"Funds generated from exit tributes\",\n text:\n \"Cumulative sum of exit tributes collected from only exit / sell / burn transactions\"\n },\n totalRaised: {\n name: \"Total funds raised for your community\",\n text: \"Sum of funds from Raise Hatch + funds from exit tributes\"\n }\n};\n","import React, { useState, useEffect } from \"react\";\nimport { InputFieldInterface, CurveParamsInterface } from \"./types\";\nimport InputParams from \"./InputParams\";\nimport { parameterDescriptions } from \"./parametersDescriptions\";\n\nexport default function CurveDesignInputParams({\n curveParams,\n setCurveParams\n}: {\n curveParams: CurveParamsInterface;\n setCurveParams(newCurveParams: any): void;\n}) {\n const [theta, setTheta] = useState(curveParams.theta); // fraction allocated to reserve (.)\n const [p0, setP0] = useState(curveParams.p0); // Hatch sale Price p0 (DAI / token)\n const [p1, setP1] = useState(curveParams.p1); // Return factor (.)\n const [wFee, setWFee] = useState(curveParams.wFee); // friction coefficient (.)\n const [vHalflife, setVHalflife] = useState(curveParams.vHalflife); // friction coefficient (.)\n\n useEffect(() => {\n setTheta(curveParams.theta);\n setP0(curveParams.p0);\n setP1(curveParams.p1);\n setWFee(curveParams.wFee);\n setVHalflife(curveParams.vHalflife);\n }, [curveParams]);\n\n const maxReturnRate = 10;\n const minP1P0Rate = 1.5;\n\n function _setP0(newP0: number) {\n setP0(newP0);\n if (p1 < newP0 * minP1P0Rate) setP1(newP0 * minP1P0Rate);\n else if (p1 > newP0 * maxReturnRate) setP1(newP0 * maxReturnRate);\n }\n\n function setParentCurveParams() {\n setCurveParams((params: CurveParamsInterface) => ({\n ...params,\n theta,\n p0,\n p1,\n wFee,\n vHalflife\n }));\n }\n\n const inputFields: InputFieldInterface[] = [\n {\n label: parameterDescriptions.theta.name,\n description: parameterDescriptions.theta.text,\n value: theta,\n setter: setTheta,\n min: 0,\n max: 0.9,\n step: 0.01,\n suffix: \"%\",\n format: (n: number) => `${Math.round(100 * n)}%`,\n toText: (n: number) => String(+(n * 1e2).toFixed(0)),\n toNum: (n: string) => parseFloat(n) * 1e-2\n },\n {\n label: `${parameterDescriptions.p0.name} (DAI/token)`,\n description: parameterDescriptions.p0.text,\n value: p0,\n setter: _setP0,\n min: 0.01,\n max: 1,\n step: 0.01,\n toText: (n: number) => String(+n.toFixed(2)),\n toNum: (n: string) => parseFloat(n),\n format: (n: number) => `$${n}`\n },\n {\n label: `${parameterDescriptions.p1.name} (DAI/token)`,\n description: parameterDescriptions.p1.text,\n value: p1,\n setter: setP1,\n min: Number((minP1P0Rate * (p0 || 0.1)).toFixed(2)),\n max: Number((maxReturnRate * p0).toFixed(2)),\n step: 0.01,\n toText: (n: number) => String(+n.toFixed(2)),\n toNum: (n: string) => parseFloat(n),\n format: (n: number) => `$${n}`\n },\n {\n label: parameterDescriptions.wFee.name,\n description: parameterDescriptions.wFee.text,\n value: wFee,\n setter: setWFee,\n min: 0,\n max: 0.1,\n step: 0.001,\n suffix: \"%\",\n format: (n: number) => `${+(100 * n).toFixed(1)}%`,\n toText: (n: number) => String(+(n * 1e2).toFixed(1)),\n toNum: (n: string) => parseFloat(n) * 1e-2\n },\n {\n label: `${parameterDescriptions.vHalflife.name} (weeks)`,\n description: parameterDescriptions.vHalflife.text,\n value: vHalflife,\n setter: setVHalflife,\n min: 1,\n max: 52 * 2,\n step: 1,\n suffix: \"\",\n format: (n: number) => String(Math.round(n)),\n toText: (n: number) => String(Math.round(n)),\n toNum: (n: string) => Math.round(parseInt(n))\n }\n ];\n\n return (\n \n );\n}\n","import React from \"react\";\nimport { makeStyles } from \"@material-ui/core/styles\";\nimport Popover from \"@material-ui/core/Popover\";\nimport Typography from \"@material-ui/core/Typography\";\nimport Box from \"@material-ui/core/Box\";\nimport HelpIcon from \"@material-ui/icons/HelpOutline\";\n\nconst useStyles = makeStyles(theme => ({\n container: {\n display: \"flex\",\n marginLeft: \"6px\",\n fontSize: \"0.9rem\",\n cursor: \"pointer\",\n transition: \"opacity ease 150ms\",\n opacity: 0.2,\n \"&:hover\": {\n opacity: 0.85\n }\n },\n popoverContainer: {\n padding: theme.spacing(2)\n },\n paper: {\n backgroundColor: \"#384b59\",\n maxWidth: theme.breakpoints.values.md * 0.9,\n [`@media screen and (max-width: ${theme.breakpoints.values.md}px)`]: {\n maxWidth: \"90vw\"\n }\n },\n // Descriptions\n descriptionContainer: {\n \"& > div:not(:last-child)\": {\n paddingBottom: theme.spacing(1),\n marginBottom: theme.spacing(1),\n borderBottom: \"1px solid #3f5463\"\n },\n \"& td\": {\n verticalAlign: \"top\",\n padding: theme.spacing(0.5)\n }\n },\n descriptionTitle: {\n padding: theme.spacing(0.5)\n },\n descriptionBody: {\n color: \"#dbdfe4\",\n padding: theme.spacing(0.5)\n },\n descriptionPadding: {\n padding: theme.spacing(0.5)\n }\n}));\n\nexport default function SimplePopover({\n text,\n title,\n table,\n body\n}: {\n text?: any;\n title?: string;\n table?: { name: string; text: string }[];\n body?: string;\n}) {\n const classes = useStyles();\n const [anchorEl, setAnchorEl] = React.useState(null);\n\n function handleClick(e: any) {\n setAnchorEl(e.currentTarget);\n }\n\n function handleClose() {\n setAnchorEl(null);\n }\n\n const open = Boolean(anchorEl);\n const id = open ? \"simple-popover\" : undefined;\n\n return (\n
\n \n\n \n \n
\n {title && (\n
\n \n {title}\n \n
\n )}\n\n {body && (\n
\n \n {body}\n \n
\n )}\n\n {table && (\n
\n \n \n {table.map(({ name, text }) => (\n \n \n \n \n ))}\n \n
\n {name}\n \n \n {text}\n \n
\n
\n )}\n\n {text}\n
\n
\n \n
\n );\n}\n","import React from \"react\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Grid from \"@material-ui/core/Grid\";\nimport TextField from \"@material-ui/core/TextField\";\nimport Typography from \"@material-ui/core/Typography\";\nimport NumberFormat from \"react-number-format\";\nimport { InputFieldInterface } from \"./types\";\nimport PrettoSlider from \"./PrettoSlider\";\nimport HelpText from \"./HelpText\";\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n root: {\n margin: theme.spacing(6, 0, 3)\n },\n lightBulb: {\n verticalAlign: \"middle\",\n marginRight: theme.spacing(1)\n },\n leftContainer: {\n // color: theme.palette.text.secondary\n },\n centerContainer: {\n // color: blackColor\n },\n listBoxContainer: {\n \"& > div:not(:last-child)\": {\n paddingBottom: \"12px\",\n marginBottom: \"12px\",\n borderBottom: \"1px solid #313d47\"\n }\n },\n listBox: {\n \"& > div\": {\n display: \"flex\",\n alignItems: \"center\",\n \"& p\": {\n marginBottom: 0\n }\n },\n \"& > div:not(:last-child)\": {\n paddingRight: \"12px\"\n }\n },\n slider: {\n color: theme.palette.primary.main\n }\n })\n);\n\nfunction NumberFormatCustom(props: any) {\n const { inputRef, onChange, prefix, suffix, ...other } = props;\n\n return (\n {\n onChange({ target: { value: values.value } });\n }}\n thousandSeparator\n prefix={prefix}\n suffix={suffix}\n />\n );\n}\n\nexport default function InputParamBig({\n inputFields,\n onChangeCommited\n}: {\n inputFields: InputFieldInterface[];\n onChangeCommited(): void;\n}) {\n const classes = useStyles();\n\n return (\n
\n {inputFields.map(\n ({\n label,\n description,\n value,\n setter,\n min,\n max,\n step,\n prefix,\n suffix,\n format,\n toText,\n toNum\n }) => {\n function sanitizeInput(num: number = 0) {\n if (isNaN(num)) num = 0;\n if (num > max) num = max;\n else if (num < min) num = min;\n setter(num);\n }\n\n return (\n \n \n {label}\n \n \n\n \n {\n sanitizeInput(\n toNum ? toNum(e.target.value) : parseFloat(e.target.value)\n );\n onChangeCommited();\n }}\n InputProps={{\n inputComponent: NumberFormatCustom,\n disableUnderline: true,\n inputProps: {\n prefix,\n suffix\n }\n }}\n value={toText ? toText(value) : value}\n />\n \n\n \n sanitizeInput(Number(newValue))}\n onChangeCommitted={onChangeCommited}\n value={value}\n min={min}\n max={max}\n step={step}\n valueLabelFormat={value => format(value).replace(\"$\", \"\")}\n />\n \n \n );\n }\n )}\n
\n );\n}\n","import React, { useState, useEffect } from \"react\";\nimport { InputFieldInterface, CurveParamsInterface } from \"./types\";\nimport InputParamBig from \"./InputParamBig\";\nimport { parameterDescriptions } from \"./parametersDescriptions\";\n\nexport default function SimulationInputParams({\n curveParams,\n setCurveParams\n}: {\n curveParams: CurveParamsInterface;\n setCurveParams(newCurveParams: any): void;\n}) {\n const [d0, setD0] = useState(3e6); // Initial raise, d0 (DAI)\n\n useEffect(() => {\n setD0(curveParams.d0);\n }, [curveParams]);\n\n function setParentCurveParams() {\n setCurveParams((params: CurveParamsInterface) => ({\n ...params,\n d0\n }));\n }\n\n const inputFields: InputFieldInterface[] = [\n {\n label: `${parameterDescriptions.d0.name}`,\n description: parameterDescriptions.d0.text,\n value: d0,\n setter: setD0,\n min: 0.1e6,\n max: 10e6,\n step: 0.1e6,\n suffix: \"M\",\n format: (n: number) => `$${+(n * 1e-6).toFixed(1)}M`,\n toText: (n: number) => String(+(n * 1e-6).toFixed(1)),\n toNum: (n: string) => Math.floor(parseFloat(n) * 1e6)\n }\n ];\n\n return (\n \n );\n}\n","/**\n * Returns an equally spaced array of numbers `from`, `to` with `steps`.\n */\nexport function linspace({\n from = 0,\n to,\n steps\n}: {\n from?: number;\n to: number;\n steps: number;\n}) {\n const arr = [];\n for (let x = from; x <= to; x += (to - from) / steps) arr.push(x);\n return arr;\n}\n\n/**\n * Returns a uniform distribution of `num` ticks\n */\nexport function getLinspaceTicks(data: number[], num: number) {\n const desiredPoints = [];\n const step = (data[data.length - 1] - data[0]) / num;\n for (let x = data[0]; x < data[data.length - 1]; x += step) {\n desiredPoints.push(x);\n }\n if (desiredPoints.length < num + 1) desiredPoints.push(data[data.length - 1]);\n\n return desiredPoints;\n}\n\n/**\n * Returns the last element of an array\n */\nexport function getLast(a: number[]) {\n return a[a.length - 1];\n}\n\n/**\n * Returns the average of an array\n */\nexport function getAvg(a: number[]) {\n return a.reduce((t, c) => t + Math.abs(c), 0) / a.length;\n}\n\n/**\n * Waits `ms` miliseconds and resolves\n */\nexport function pause(ms: number) {\n return new Promise(r => setTimeout(r, ms));\n}\n\n/**\n * Parse the units of big numbers\n */\nexport function getUnits(\n biggestNum: number\n): { scaling: number; unit: string } {\n const [scaling, unit] =\n // Billion\n biggestNum > 0.5e9\n ? [1e9, \"B\"]\n : // Million\n biggestNum > 0.5e6\n ? [1e6, \"M\"]\n : // 1 thousand\n biggestNum > 0.5e3\n ? [1e3, \"K\"]\n : // No scale\n [1, \"\"];\n return { scaling, unit };\n}\n","/**\n * Computes the initial params given the \"user friendly\" params:\n * - Initial raise, `d0` (DAI)\n * - fraction allocated to reserve, `theta`\n * - Hatch sale price, `p0` (DAI / token)\n * - Return factor, `returnF`\n */\nexport function getInitialParams({\n d0,\n theta,\n p0,\n p1\n}: {\n d0: number;\n theta: number;\n p0: number;\n p1: number;\n}) {\n const k = p1 / p0 / (1 - theta); // Invariant power kappa (.)\n const R0 = (1 - theta) * d0; // Initial reserve (DAI)\n const S0 = d0 / p0; // initial supply of tokens (token)\n const V0 = S0 ** k / R0; // invariant coef\n return { k, R0, S0, V0 };\n}\n\nexport function getR({ S, V0, k }: { S: number; V0: number; k: number }) {\n return S ** k / V0;\n}\n\nexport function getS({ R, V0, k }: { R: number; V0: number; k: number }) {\n return (V0 * R) ** (1 / k);\n}\n\n// compute the price if all that supply is burned\nexport function getMinPrice({\n S,\n H,\n V0,\n k\n}: {\n S: number;\n H: number;\n V0: number;\n k: number;\n}) {\n if (S === H) {\n const myR = getR({ S, V0, k });\n const myP = getPriceR({ R: myR, V0, k }); // numerical precision make complex numbers just suppress it\n return Math.abs(myP);\n } else {\n // compute the reserve if all that supply is burned\n const minR = getR({ S: S - H, V0, k });\n return getPriceR({ R: minR, V0, k });\n }\n}\n\n/**\n * Computes the price at a specific reserve `R`\n */\nexport function getPriceR({ R, V0, k }: { R: number; V0: number; k: number }) {\n return (k * R ** ((k - 1) / k)) / V0 ** (1 / k);\n}\n\n/**\n * Compute slippage at a point `R`, given a `deltaR`\n */\nexport function getSlippage({\n R,\n deltaR,\n V0,\n k\n}: {\n R: number;\n deltaR: number;\n V0: number;\n k: number;\n}) {\n const S = (V0 * R) ** (1 / k);\n const deltaS = (V0 * (R + deltaR)) ** (1 / k) - S;\n const realizedPrice = deltaR / deltaS;\n const spotPrice = getPriceR({ R, V0, k });\n return Math.abs(realizedPrice - spotPrice) / spotPrice;\n}\n\n// Price walk utils\n\n/**\n * Get deltaR for a given price growth factor\n */\nexport function getDeltaR_priceGrowth({\n R,\n k,\n priceGrowth\n}: {\n R: number;\n k: number;\n priceGrowth: number;\n}) {\n return -R + (priceGrowth * R ** (1 - 1 / k)) ** (k / (-1 + k));\n}\n\n/**\n * Computes a tx distribution using a normal distribution,\n * Given a sum of tx value and a number of transactions\n *\n * Demo: https://codepen.io/anon/pen/mNqJjv?editors=0010#0\n * Very quick: < 10ms for 10000 txs\n */\nexport function getTxDistribution({\n sum,\n num,\n spread\n}: {\n sum: number;\n num: number;\n spread: number;\n}) {\n const mean = sum / num;\n const off = mean * spread;\n const x: number[] = [];\n for (let i = 0; i < num; i++) {\n x.push(randn_bm(mean - off, mean + off));\n }\n return x;\n}\n\nexport function vest_tokens({\n week,\n H, // unvested_hatch_tokens\n halflife,\n cliff\n}: {\n week: number;\n H: number;\n halflife: number;\n cliff: number;\n}) {\n // check cliff\n if (week < cliff) {\n return 0;\n } else {\n // rate of release given half - life\n const vest_fraction = 0.5 ** (1 / halflife);\n // number of tokens that vest in this week\n return H * (1 - vest_fraction);\n }\n}\n\n// Statistics utils\n\n/**\n * Random variable uniformly distributed\n */\nexport function rv_U(min: number, max: number) {\n return Math.random() * (max - min) + min;\n}\n\n/**\n * Standard Normal variate using Box-Muller transform.\n * by https://stackoverflow.com/questions/25582882/javascript-math-random-normal-distribution-gaussian-bell-curve/36481059#36481059\n */\nfunction randn_bm(min: number, max: number) {\n var u = 0,\n v = 0;\n while (u === 0) u = Math.random(); //Converting [0,1) to (0,1)\n while (v === 0) v = Math.random();\n let num = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);\n\n num = num / 10.0 + 0.5; // Translate to 0 -> 1\n if (num > 1 || num < 0) num = randn_bm(min, max); // resample between 0 and 1 if out of range\n num *= max - min; // Stretch to fill range\n num += min; // offset to min\n return num;\n}\n\n// Array utils\n\nexport function getMedian(arr: number[]) {\n const mid = Math.floor(arr.length / 2);\n const nums = [...arr].sort((a, b) => a - b);\n return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;\n}\n\nexport function getSum(arr: number[]) {\n return arr.reduce((a, b) => a + b, 0);\n}\n","import React from \"react\";\nimport {\n AreaChart,\n Area,\n XAxis,\n YAxis,\n CartesianGrid,\n Legend,\n ReferenceLine,\n ReferenceDot,\n ReferenceArea,\n ResponsiveContainer,\n Tooltip\n} from \"recharts\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport { getLinspaceTicks, getUnits } from \"./utils\";\nimport { getInitialParams, getPriceR } from \"./math\";\nimport { useTheme } from \"@material-ui/styles\";\n\nconst isAnimationActive = false;\nconst keyHorizontal = \"x\";\nconst keyVertical = \"Supply (tokens) / Collateral (DAI)\";\n\n// Do to transparency and color merging issues\n// these colors are handpicked to look the closest to the theme colors\nconst referenceLineColor = \"#b7c1cb\";\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n tooltip: {\n border: \"1px solid #313d47\",\n backgroundColor: \"#384b59\",\n padding: theme.spacing(1),\n color: \"#c7ccd2\"\n }\n })\n);\n\nfunction SupplyVsDemandChart({\n theta,\n d0,\n p0,\n p1\n}: {\n theta: number;\n d0: number;\n p0: number;\n p1: number;\n}) {\n // d0 - Initial raise, d0 (DAI)\n // theta - fraction allocated to reserve (.)\n // p0 - Hatch sale Price p0 (DAI / token)\n // returnF - Return factor (.)\n // wFee - friction coefficient (.)\n\n // Hatch parameters\n const {\n k, // Invariant power kappa (.)\n R0, // Initial reserve (DAI)\n S0, // initial supply of tokens (token)\n V0 // invariant coef\n } = getInitialParams({\n d0,\n theta,\n p0,\n p1\n });\n const R0_round = Math.round(R0);\n const S_of_R = (R: number) => S0 * (R / R0_round) ** (1 / k);\n\n // Function setup\n const f = S_of_R;\n const from = 0;\n const to = 4 * R0_round;\n const steps = 100 + 1; // Add 1 for the ticks to match\n const step = Math.round((to - from) / (steps - 1));\n\n /**\n * Prettify the result converting 1000000 to 1M\n */\n const biggest = Math.max(to, f(to));\n const { scaling, unit } = getUnits(biggest);\n\n const data = [];\n for (let i = 0; i < steps; i++) {\n const x = Math.round(from + step * i);\n data.push({\n [keyHorizontal]: x,\n [keyVertical]: f(x)\n });\n }\n\n // Chart components\n\n const theme: any = useTheme();\n const classes = useStyles();\n\n const formatter = (n: number) =>\n (+(n / scaling).toPrecision(2)).toLocaleString();\n\n function renderColorfulLegendText(value: string) {\n return {value};\n }\n\n function ReferenceLabel(props: any) {\n const { textAnchor, viewBox } = props;\n return (\n \n Initial Token Supply\n \n );\n }\n\n function CustomTooltip({ active, payload, label }: any) {\n if (active) {\n const supply = payload[0].value;\n const reserve = label;\n const price = getPriceR({ R: reserve, V0, k });\n const toolTipData: string[][] = [\n [\"Supply\", formatter(supply) + unit, \"tokens\"],\n [\"Collateral\", formatter(reserve) + unit, \"DAI\"],\n [\"Price\", price.toFixed(2), \"DAI/token\"]\n ];\n return (\n
\n \n \n {toolTipData.map(([name, value, _unit]) => (\n \n \n \n \n \n ))}\n \n
{name}{value}{_unit}
\n
\n );\n } else return null;\n }\n\n return (\n \n \n \n \n d[keyVertical]), 3)}\n tickFormatter={formatter}\n unit={unit}\n tick={{ fill: theme.palette.text.secondary }}\n domain={[0, f(to)]}\n stroke={theme.palette.text.secondary}\n />\n } />\n \n {/* Necessary because ReferenceDot types do not allow \"label\" k */}\n }\n />\n \n\n \n \n \n );\n}\n\nexport default SupplyVsDemandChart;\n","import React from \"react\";\nimport \"./dotsLoader.css\";\n\nexport default function DotsLoader() {\n return (\n
\n
\n
\n
\n
\n );\n}\n","import React, { useState, useEffect } from \"react\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Typography from \"@material-ui/core/Typography\";\nimport Grid from \"@material-ui/core/Grid\";\nimport TextWithPopover from \"./TextWithPopover\";\nimport DotsLoader from \"./DotsLoader\";\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n root: {\n margin: theme.spacing(6, 0, 3)\n },\n lightBulb: {\n verticalAlign: \"middle\",\n marginRight: theme.spacing(1)\n },\n leftContainer: {\n color: theme.palette.text.secondary\n },\n centerContainer: {\n // color: blackColor\n },\n listBoxContainer: {\n \"& > div:not(:last-child)\": {\n marginBottom: \"12px\",\n borderBottom: \"1px solid #313d47\"\n }\n },\n listBox: {\n paddingBottom: \"12px\",\n \"& > div\": {\n display: \"flex\",\n alignItems: \"center\",\n \"& p\": {\n marginBottom: 0\n }\n },\n \"& > div:not(:last-child)\": {\n paddingRight: \"12px\"\n }\n },\n valueFooter: {\n color: theme.palette.text.secondary,\n fontSize: \"80%\"\n }\n })\n);\n\nexport default function ResultParams({\n resultFields,\n simulationDuration\n}: {\n resultFields: {\n label: string;\n description: string;\n value: number | string;\n valueFooter?: string;\n }[];\n simulationDuration: number;\n}) {\n /**\n * When resizing the window the chart animation looks very bad\n * Keep the animation active only during the initial animation time,\n * but afterwards, deactivate to prevent the re-size ugly effect\n */\n const [isAnimationActive, setIsAnimationActive] = useState(\n process.env.NODE_ENV !== \"development\"\n );\n useEffect(() => {\n const timeout = setTimeout(() => {\n setIsAnimationActive(false);\n }, simulationDuration);\n return () => {\n clearTimeout(timeout);\n };\n });\n\n const classes = useStyles();\n\n return (\n
\n {resultFields.map(({ label, description, value, valueFooter }) => (\n \n \n \n \n\n \n {isAnimationActive ? (\n \n ) : (\n
\n {value}\n {valueFooter && (\n \n {valueFooter}\n \n )}\n
\n )}\n
\n
\n ))}\n
\n );\n}\n","import React, { useState, useEffect } from \"react\";\nimport {\n AreaChart,\n Area,\n XAxis,\n YAxis,\n CartesianGrid,\n Legend,\n ReferenceLine,\n ResponsiveContainer,\n Tooltip\n} from \"recharts\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport { useTheme } from \"@material-ui/styles\";\nimport { linspace, getUnits } from \"./utils\";\n\nconst keyHorizontal = \"x\";\nconst keyVerticalLeft = \"Price (DAI/token)\";\nconst keyVerticalLeft2 = \"Floor price (DAI/token)\";\nconst keyVerticalRight = \"Total funds raised (DAI)\";\nconst p1LineText = \"Post-Hatch price\";\nconst p0LineText = \"Hatch price\";\n\n// Do to transparency and color merging issues\n// these colors are handpicked to look the closest to the theme colors\nconst yLeftColor = \"#53c388\";\nconst yRightColor = \"#4090d9\";\nconst referenceLineColor = \"#b7c1cb\";\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n tooltip: {\n border: \"1px solid #313d47\",\n backgroundColor: \"#384b59\",\n padding: theme.spacing(1),\n color: \"#c7ccd2\"\n }\n })\n);\n\nfunction PriceSimulationChart({\n priceTimeseries,\n totalFundsRaisedTimeseries,\n floorpriceTimeseries,\n simulationDuration,\n p0,\n p1\n}: {\n priceTimeseries: number[];\n totalFundsRaisedTimeseries: number[];\n floorpriceTimeseries: number[];\n simulationDuration: number;\n p0: number;\n p1: number;\n}) {\n // d0 - Initial raise, d0 (DAI)\n // theta - fraction allocated to reserve (.)\n // p0 - Hatch sale Price p0 (DAI / token)\n // returnF - Return factor (.)\n // wFee - friction coefficient (.)\n\n const data = [];\n for (let t = 0; t < priceTimeseries.length; t++) {\n data.push({\n [keyHorizontal]: t,\n [keyVerticalLeft]: priceTimeseries[t] || 0,\n [keyVerticalLeft2]: floorpriceTimeseries[t] || 0,\n [keyVerticalRight]: totalFundsRaisedTimeseries[t] || 0\n });\n }\n\n /**\n * When resizing the window the chart animation looks very bad\n * Keep the animation active only during the initial animation time,\n * but afterwards, deactivate to prevent the re-size ugly effect\n */\n const [isAnimationActive, setIsAnimationActive] = useState(\n process.env.NODE_ENV !== \"development\"\n );\n useEffect(() => {\n const timeout = setTimeout(() => {\n setIsAnimationActive(false);\n }, simulationDuration + 100);\n return () => {\n clearTimeout(timeout);\n };\n });\n\n // Compute chart related math\n\n const totalFundsMin = totalFundsRaisedTimeseries[0];\n const totalFundsMax = totalFundsRaisedTimeseries.slice(-1)[0];\n const totalFundsRange = totalFundsMax - totalFundsMin;\n\n const daiFormatter = (n: number) => (+n.toFixed(2)).toLocaleString();\n const { scaling, unit } = getUnits(totalFundsMax);\n const fundsFormatter = (n: number) => (+n.toPrecision(3)).toLocaleString();\n const fundsFormatterShort = (n: number) =>\n (+(n / scaling).toPrecision(3)).toLocaleString();\n\n // Load styles\n\n const theme: any = useTheme();\n const classes = useStyles();\n\n // Chart components\n\n function renderColorfulLegendText(value: string) {\n return {value};\n }\n\n function ReferenceLabel(props: any) {\n const { textAnchor, viewBox, text, fill } = props;\n return (\n \n {text}\n \n );\n }\n\n function CustomTooltip({ active, payload, label }: any) {\n if (active) {\n const price = payload[0].value;\n const floor = payload[1].value;\n const funds = payload[2].value;\n const weekNum = label;\n const toolTipData: string[][] = [\n [\"Price\", daiFormatter(price), \"DAI/tk\"],\n [\"Floor P.\", daiFormatter(floor), \"DAI/tk\"],\n [\"Funds R.\", fundsFormatterShort(funds) + unit, \"DAI\"],\n [\"Week\", weekNum, \"\"]\n ];\n\n return (\n
\n \n \n {toolTipData.map(([name, value, unit]) => (\n \n \n \n \n \n ))}\n \n
{name}{value}{unit}
\n
\n );\n } else return null;\n }\n\n return (\n \n \n \n \n\n {/* Price time evolution */}\n \n\n {/* Capital collected from withdraw fees - AXIS */}\n \n\n } />\n\n \n \n\n }\n />\n }\n />\n\n {/* Capital collected from withdraw fees - AREA */}\n \n\n {/* }\n /> */}\n \n \n \n );\n}\n\nexport default PriceSimulationChart;\n","const low_u = 0.97;\nconst high_u = 1.07;\nconst dump = 0.75;\n\nexport const u_min_t = [\n 1,\n 0.8,\n 0.8,\n 0.9,\n 0.9,\n 0.8,\n 0.6,\n 0.5,\n 0.8,\n 0.9,\n 0.9,\n low_u,\n low_u,\n low_u,\n 0.8,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n low_u,\n low_u,\n low_u,\n dump,\n low_u,\n low_u,\n low_u,\n low_u,\n low_u,\n 0.97\n];\n\nexport const u_max_t = [\n 3,\n 1.5,\n 1.01,\n 1.04,\n 1.1,\n 1.15,\n 1.15,\n 1.15,\n 1.1,\n 1.1,\n 1.2,\n 1.15,\n high_u,\n high_u,\n 1.3,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n 1.3,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n 1.2,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n 1.4,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n high_u,\n 1.04\n];\n","import React, { useState, useEffect, useMemo } from \"react\";\n// Material UI\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Container from \"@material-ui/core/Container\";\nimport Typography from \"@material-ui/core/Typography\";\nimport Box from \"@material-ui/core/Box\";\nimport Paper from \"@material-ui/core/Paper\";\nimport Grid from \"@material-ui/core/Grid\";\nimport Button from \"@material-ui/core/Button\";\n// Components\nimport Header from \"./Header\";\nimport CurveDesignInputParams from \"./CurveDesignInputParams\";\nimport SimulationInputParams from \"./SimulationInputParams\";\nimport SupplyVsDemandChart from \"./SupplyVsDemandChart\";\nimport ResultParams from \"./ResultParams\";\nimport PriceSimulationChart from \"./PriceSimulationChart\";\nimport HelpText from \"./HelpText\";\n// Text content\nimport {\n parameterDescriptions,\n simulationParameterDescriptions,\n resultParameterDescriptions,\n supplyVsDemandChartDescription,\n simulationChartDescription\n} from \"./parametersDescriptions\";\n// Utils\nimport { getLast, getAvg, pause } from \"./utils\";\nimport {\n getInitialParams,\n getPriceR,\n getMinPrice,\n getS,\n vest_tokens,\n getR,\n getSlippage,\n getTxDistribution,\n getDeltaR_priceGrowth,\n rv_U,\n getMedian,\n getSum\n} from \"./math\";\nimport { throttle } from \"lodash\";\n// Data\nimport { u_min_t, u_max_t } from \"./u_values\";\n// General styles\nimport \"./app.css\";\n\nconst headerOffset = 10;\nconst simulationDuration = 4000;\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n mainContainer: {\n \"& > div:not(:last-child)\": {\n paddingBottom: theme.spacing(3)\n },\n \"& > div\": {\n \"& > div\": {\n paddingTop: \"0 !important\"\n }\n },\n paddingBottom: theme.spacing(9)\n },\n simulationContainer: {\n minHeight: \"442px\"\n },\n paper: {\n width: \"100%\",\n height: \"100%\",\n minHeight: 310,\n backgroundColor: \"#293640\"\n },\n box: {\n padding: theme.spacing(3, 3)\n },\n boxButton: {\n padding: theme.spacing(3, 3)\n },\n boxHeader: {\n padding: theme.spacing(3, 3),\n height: theme.spacing(headerOffset),\n display: \"flex\",\n alignItems: \"center\",\n borderBottom: \"1px solid #313d47\"\n },\n boxBorderBottom: {\n borderBottom: \"1px solid #313d47\"\n },\n initialRaise: {\n justifyContent: \"space-between\"\n },\n boxChart: {\n width: \"100%\",\n height: \"100%\",\n minHeight: 310,\n maxHeight: 350,\n padding: theme.spacing(3, 3),\n // Correct the chart excessive margins\n paddingRight: \"5px\",\n paddingLeft: \"5px\"\n },\n boxPlaceholder: {\n padding: theme.spacing(3, 3),\n display: \"flex\",\n height: \"100%\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: theme.palette.text.secondary,\n opacity: 0.4\n },\n header: {\n backgroundColor: \"#0b1216\",\n color: \"#f8f8f8\",\n textAlign: \"center\",\n padding: theme.spacing(3, 0, 6 + headerOffset),\n marginBottom: -theme.spacing(headerOffset)\n },\n button: {\n // background: \"linear-gradient(290deg, #2ad179, #4ab47c)\", // Green gradient\n background: \"linear-gradient(290deg, #1aa059, #3d9567)\", // Darker Green gradient\n // background: \"linear-gradient(290deg, #1880e0, #3873d8)\", // blue gradient\n color: \"white\"\n },\n // Descriptions\n descriptionContainer: {\n \"& > div:not(:last-child)\": {\n paddingBottom: theme.spacing(1),\n marginBottom: theme.spacing(1),\n borderBottom: \"1px solid #3f5463\"\n },\n \"& td\": {\n verticalAlign: \"top\",\n padding: theme.spacing(0.5)\n }\n },\n descriptionTitle: {\n padding: theme.spacing(0.5)\n },\n descriptionBody: {\n color: \"#dbdfe4\"\n },\n descriptionPadding: {\n padding: theme.spacing(0.5)\n },\n d0Container: {\n \"& > div\": {\n padding: \"0 12px 0 0 !important\",\n display: \"flex\",\n alignItems: \"center\"\n }\n },\n d0Number: {\n padding: \"0 !important\",\n display: \"flex\",\n alignItems: \"center\"\n },\n d0Slidder: {\n padding: \"0 12px 0 0 !important\",\n display: \"flex\",\n alignItems: \"center\"\n }\n })\n);\n\nexport default function App() {\n const [curveParams, setCurveParams] = useState({\n theta: 0.35, // fraction allocated to reserve (.)\n p0: 0.1, // Hatch sale price p0 (DAI / token)\n p1: 0.3, // Return factor (.)\n wFee: 0.05, // friction coefficient (.)\n vHalflife: 17, // Vesting half life (weeks)\n d0: 3e6 // Initial raise, d0 (DAI)\n });\n\n const { d0, theta, p0, p1, wFee, vHalflife } = curveParams;\n\n /**\n * Throttle the curve update to prevent the expensive chart\n * to re-render too often\n */\n const setCurveParamsThrottle = useMemo(\n () => throttle(setCurveParams, 250),\n []\n );\n\n // Simulation results\n const {\n k, // Invariant power kappa (.)\n R0, // Initial reserve (DAI)\n S0, // initial supply of tokens (token)\n V0 // invariant coef\n } = getInitialParams({\n d0,\n theta,\n p0,\n p1\n });\n\n const [priceTimeseries, setPriceTimeseries] = useState([0]);\n const [withdrawFeeTimeseries, setWithdrawFeeTimeseries] = useState([0]);\n const [floorpriceTimeseries, setFloorpriceTimeseries] = useState([0]);\n const [totalReserve, setTotalReserve] = useState(R0);\n const [withdrawCount, setWithdrawCount] = useState(0);\n const [avgSlippage, setAvgSlippage] = useState(0);\n const [avgTxSize, setAvgTxSize] = useState(0);\n // Simulation state variables\n const [simulationActive, setSimulationActive] = useState(false);\n const [simulationRunning, setSimulationRunning] = useState(false);\n\n useEffect(() => {\n setSimulationActive(false);\n }, [curveParams]);\n\n // #### TEST: Immediate simulation\n\n async function startSimulation() {\n // If there's a simulation already active, clear it\n clearSimulation();\n await pause(0);\n\n // Start simulation by setting it to active\n setSimulationActive(true);\n }\n\n function clearSimulation() {\n // Stop simulation\n setSimulationActive(false);\n // Clear simulation variables\n setWithdrawCount(0);\n setPriceTimeseries([0]);\n setWithdrawFeeTimeseries([0]);\n setAvgSlippage(0);\n }\n\n useEffect(() => {\n let canContinueSimulation = true;\n\n async function simulateRandomDelta() {\n const R_t: number[] = [R0];\n const S_t: number[] = [S0];\n const p_t: number[] = [getPriceR({ R: R0, V0, k })];\n const wFee_t: number[] = [0];\n const slippage_t: number[] = [];\n const avgTxSize_t: number[] = [];\n\n // hatchers tokens = S0[section added by Z]\n const H_t: number[] = [S0]; // total hatcher tokens not vested\n const floorprice_t: number[] = []; // initially the price is the floor as all tokens are hatcher tokens\n\n // Random walk\n const numSteps = 52;\n const u_min = 0.97;\n const u_max = 1.04;\n const tx_spread = 10;\n // vesting(should this be exposed in the app ?)\n const cliff = 8; // weeks before vesting starts ~2 months\n // const halflife = 52; // 26 weeks, half life is ~6 months\n // percentage of the hatch tokens which vest per week(since that is our timescale in the sim)\n\n // numSteps = 52 take 8ms to run\n setSimulationRunning(true);\n for (let t = 0; t < numSteps; t++) {\n const txsWeek = rv_U(100, 40 * t + 100);\n\n const R = getLast(R_t);\n const S = getLast(S_t);\n const H = getLast(H_t);\n\n let R_next: number = 0,\n S_next: number = 0,\n H_next: number = 0,\n price_next: number = 0,\n txsWithdraw: number[] = [0],\n floorprice_next: number = 1,\n slippage: number = 0;\n // Run the value compution again if the price goes below the floor price\n\n /**\n * Since the values u_min and u_max are predefined, it's possible that\n * the price becomes less than the floor price. This cannot happen.\n * So the next loop has 10 opportunities to find a price greater than\n * the floor price. The for loop is used to prevent a possible infinite\n * loop if a `while` loop was used.\n */\n for (let i = 0; i < 20 && price_next < floorprice_next * 1.05; i++) {\n // enforce the effects of the unvested tokens not being burnable\n let u_lower: number, u_upper: number;\n // if (H > S) {\n // u_lower = 1;\n // } else {\n // // compute the reserve if all that supply is burned\n // const R_ratio = getR({ S: S - H, V0, k }) / R;\n // u_lower = Math.max(1 - R_ratio, u_min);\n // }\n // let priceGrowth = rv_U(u_lower, u_max);\n\n u_lower = u_min_t[t];\n u_upper = u_max_t[t];\n\n if (i > 15) {\n u_lower = 1.02;\n u_upper = u_upper + 1.04;\n }\n\n const priceGrowth = rv_U(u_lower, u_upper);\n\n const deltaR = getDeltaR_priceGrowth({ R, k, priceGrowth });\n R_next = R + deltaR;\n\n const txs = getTxDistribution({\n sum: deltaR,\n num: txsWeek,\n spread: tx_spread\n });\n // Compute slippage\n const slippage_txs = txs.map(txR =>\n getSlippage({ R, deltaR: txR, V0, k })\n );\n slippage = getMedian(slippage_txs);\n\n txsWithdraw = txs.filter(tx => tx < 0);\n\n // Vest\n const delta_H = vest_tokens({\n week: t,\n H,\n halflife: vHalflife,\n cliff\n });\n H_next = H - delta_H;\n\n // find floor price\n S_next = getS({ R, V0, k });\n floorprice_next = getMinPrice({\n S: S_next,\n H: S_next - H_next,\n V0,\n k\n });\n\n price_next = getPriceR({ R: R_next, V0, k });\n }\n\n const _avgTxSize = getMedian(txsWithdraw);\n const wFees = -wFee * getSum(txsWithdraw);\n\n R_t.push(R_next);\n S_t.push(S_next);\n H_t.push(H_next);\n p_t.push(price_next);\n slippage_t.push(slippage);\n avgTxSize_t.push(_avgTxSize);\n wFee_t.push(getLast(wFee_t) + wFees);\n\n floorprice_t.push(floorprice_next);\n setWithdrawCount(c => c + txsWithdraw.length);\n\n // Stop the simulation if it's no longer active\n if (!simulationActive || !canContinueSimulation) break;\n }\n\n // floorprice_t is missing one data point\n floorprice_t[floorprice_t.length] = floorprice_t[floorprice_t.length - 1];\n\n setPriceTimeseries(p_t);\n setWithdrawFeeTimeseries(wFee_t);\n setFloorpriceTimeseries(floorprice_t);\n setAvgSlippage(getAvg(slippage_t));\n setAvgTxSize(getAvg(avgTxSize_t.filter(n => !isNaN(n))));\n setTotalReserve(getLast(R_t));\n\n setSimulationRunning(false);\n }\n\n if (simulationActive) simulateRandomDelta();\n // Return an \"unsubscribe\" function that halts the run\n return () => {\n canContinueSimulation = false;\n };\n }, [simulationActive]);\n\n // End results computed for chart visualization\n const initialHatchFunds = d0 * theta;\n const totalFundsRaisedTimeseries = withdrawFeeTimeseries.map(\n x => x + initialHatchFunds\n );\n\n const totalInitialHatchFunds = Math.round(d0 * theta);\n const totalExitTributes = Math.round(getLast(withdrawFeeTimeseries));\n const totalFunds = totalInitialHatchFunds + totalExitTributes;\n const formatFunds = (n: number) => (+n.toPrecision(3)).toLocaleString();\n\n const resultFields = [\n {\n label: resultParameterDescriptions.totalReserve.name,\n description: resultParameterDescriptions.totalReserve.text,\n value: (+totalReserve.toPrecision(3)).toLocaleString() + \" DAI\"\n },\n {\n label: resultParameterDescriptions.slippage.name,\n description: resultParameterDescriptions.slippage.text,\n value: +(100 * avgSlippage).toFixed(3) + \" %\",\n valueFooter: `Avg tx size ${Math.round(avgTxSize).toLocaleString()} DAI`\n },\n {\n label: resultParameterDescriptions.initialHatchFunds.name,\n description: resultParameterDescriptions.initialHatchFunds.text,\n value: formatFunds(totalInitialHatchFunds) + \" DAI\"\n },\n {\n label: resultParameterDescriptions.exitTributes.name,\n description: resultParameterDescriptions.exitTributes.text,\n value: formatFunds(totalExitTributes) + \" DAI\",\n valueFooter: `From ${withdrawCount} exit txs`\n },\n {\n label: resultParameterDescriptions.totalRaised.name,\n description: resultParameterDescriptions.totalRaised.text,\n value: formatFunds(totalFunds) + \" DAI\"\n }\n ];\n\n const classes = useStyles();\n\n return (\n <>\n
\n \n
\n \n
\n\n \n \n \n \n \n Curve Design\n \n \n\n \n \n \n \n \n\n \n \n \n Preview\n \n \n\n \n \n \n \n \n \n\n \n \n \n \n \n \n\n \n \n \n Run simulation\n \n \n \n \n \n \n\n \n {simulationActive ? (\n <>\n \n \n \n Simulation\n \n \n\n \n \n \n \n \n\n \n \n \n Results\n \n \n\n \n \n \n \n \n \n ) : (\n \n \n \n \n Run a simulation to see results\n \n \n \n \n )}\n \n \n \n );\n}\n","import red from \"@material-ui/core/colors/red\";\nimport { createMuiTheme } from \"@material-ui/core/styles\";\n\n// A custom theme for this app\nconst theme = createMuiTheme({\n palette: {\n type: \"dark\",\n primary: {\n main: \"#2ecd79\"\n },\n secondary: {\n main: \"#116be0\",\n light: \"#0f8bff\",\n dark: \"#116be0\"\n },\n error: {\n main: red.A400\n },\n background: {\n default: \"#fff\",\n paper: \"#293640\"\n },\n text: {\n primary: \"#fff\",\n secondary: \"#9aa3ad\"\n }\n },\n typography: {\n h6: {\n fontWeight: 400\n }\n }\n});\n\nconsole.log(theme);\n\nexport default theme;\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport CssBaseline from '@material-ui/core/CssBaseline';\nimport { ThemeProvider } from '@material-ui/styles';\nimport App from './App';\nimport theme from './theme';\n\nReactDOM.render(\n \n {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}\n \n \n ,\n document.querySelector('#root'),\n);\n"],"sourceRoot":""} \ No newline at end of file