├── .gitignore ├── .gitmodules ├── Makefile ├── README.md ├── bin └── deploy ├── docs ├── async.min.js ├── babel.min.js ├── ecc.js ├── eos_sale_abi.js ├── eos_token_abi.js ├── index.css ├── index.html ├── index.js ├── lib.js ├── moment.min.js ├── react-dom.min.js └── react.min.js └── src ├── eos_sale.sol ├── eos_sale.t.sol └── eos_sale_util.sol /.gitignore: -------------------------------------------------------------------------------- 1 | /out 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/ds-test"] 2 | path = lib/ds-test 3 | url = https://github.com/dapphub/ds-test 4 | [submodule "lib/ds-auth"] 5 | path = lib/ds-auth 6 | url = https://github.com/dapphub/ds-auth 7 | [submodule "lib/ds-math"] 8 | path = lib/ds-math 9 | url = https://github.com/dapphub/ds-math 10 | [submodule "lib/ds-token"] 11 | path = lib/ds-token 12 | url = https://github.com/dapphub/ds-token 13 | [submodule "lib/ds-exec"] 14 | path = lib/ds-exec 15 | url = https://github.com/dapphub/ds-exec 16 | [submodule "lib/ds-guard"] 17 | path = lib/ds-guard 18 | url = https://github.com/dapphub/ds-guard 19 | [submodule "lib/gnosis-multisig"] 20 | path = lib/gnosis-multisig 21 | url = https://github.com/dapphub/gnosis-multisig 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all :; dapp build 2 | test :; dapp test 3 | clean :; dapp clean 4 | deploy :; bin/deploy 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The Web Interface is being updated... 2 | 3 | https://etherscan.io/address/0xd0a6e6c54dbc68db5db3a091b171a77407ff7ccf 4 | -------------------------------------------------------------------------------- /bin/deploy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | export DAPP_NO_SAVE=1 5 | export ETH_GAS=4000000 6 | 7 | token=$(set -x; dapp create DSToken \ 8 | $(seth --to-bytes32 $(seth --from-ascii EOS)) 9 | ) 10 | 11 | sale=$(set -x; dapp create EOSSale 7 \ 12 | $(seth --to-uint256 $(seth --to-wei 1000000000 eth)) \ 13 | $(date +%s -d '1 second') \ 14 | $(date +%s -d '1 hour') \ 15 | $(seth --to-uint256 $(seth --to-wei 100000000 eth)) \ 16 | $(seth --from-ascii abcdefghijklmnopqrstuvwxyzABCDEFG) 17 | ) 18 | 19 | (set -x; seth send "$token" "setOwner(address)" "$sale") 20 | (set -x; seth send "$sale" "initialize(address)" "$token") 21 | 22 | echo "eos_token=$token" 23 | echo "eos_sale=$sale" 24 | -------------------------------------------------------------------------------- /docs/async.min.js: -------------------------------------------------------------------------------- 1 | !function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(n.async=n.async||{})}(this,function(n){"use strict";function t(n,t){t|=0;for(var e=Math.max(n.length-t,0),r=Array(e),u=0;u-1&&n%1==0&&n<=Bt}function d(n){return null!=n&&v(n.length)&&!y(n)}function m(){}function g(n){return function(){if(null!==n){var t=n;n=null,t.apply(this,arguments)}}}function b(n,t){for(var e=-1,r=Array(n);++e-1&&n%1==0&&nu?0:u+t),e=e>u?u:e,e<0&&(e+=u),u=t>e?0:e-t>>>0,t>>>=0;for(var o=Array(u);++r=r?n:Z(n,t,e)}function tn(n,t){for(var e=n.length;e--&&J(t,n[e],0)>-1;);return e}function en(n,t){for(var e=-1,r=n.length;++e-1;);return e}function rn(n){return n.split("")}function un(n){return Xe.test(n)}function on(n){return n.match(vr)||[]}function cn(n){return un(n)?on(n):rn(n)}function fn(n){return null==n?"":Y(n)}function an(n,t,e){if(n=fn(n),n&&(e||void 0===t))return n.replace(dr,"");if(!n||!(t=Y(t)))return n;var r=cn(n),u=cn(t),o=en(r,u),i=tn(r,u)+1;return nn(r,o,i).join("")}function ln(n){return n=n.toString().replace(jr,""),n=n.match(mr)[2].replace(" ",""),n=n?n.split(gr):[],n=n.map(function(n){return an(n.replace(br,""))})}function sn(n,t){var e={};N(n,function(n,t){function r(t,e){var r=K(u,function(n){return t[n]});r.push(e),a(n).apply(null,r)}var u,o=f(n),i=!o&&1===n.length||o&&0===n.length;if(qt(n))u=n.slice(0,-1),n=n[n.length-1],e[t]=u.concat(u.length>0?r:n);else if(i)e[t]=n;else{if(u=ln(n),0===n.length&&!o&&0===u.length)throw new Error("autoInject task functions require explicit parameters.");o||u.pop(),e[t]=u.concat(r)}}),Re(e,t)}function pn(){this.head=this.tail=null,this.length=0}function hn(n,t){n.length=1,n.head=n.tail=t}function yn(n,t,e){function r(n,t,e){if(null!=e&&"function"!=typeof e)throw new Error("task callback must be a function");if(l.started=!0,qt(n)||(n=[n]),0===n.length&&l.idle())return st(function(){l.drain()});for(var r=0,u=n.length;r=0&&c.splice(o),u.callback.apply(u,arguments),null!=t&&l.error(t,u.data)}i<=l.concurrency-l.buffer&&l.unsaturated(),l.idle()&&l.drain(),l.process()}}if(null==t)t=1;else if(0===t)throw new Error("Concurrency must not be zero");var o=a(n),i=0,c=[],f=!1,l={_tasks:new pn,concurrency:t,payload:e,saturated:m,unsaturated:m,buffer:t/4,empty:m,drain:m,error:m,started:!1,paused:!1,push:function(n,t){r(n,!1,t)},kill:function(){l.drain=m,l._tasks.empty()},unshift:function(n,t){r(n,!0,t)},remove:function(n){l._tasks.remove(n)},process:function(){if(!f){for(f=!0;!l.paused&&i2&&(o=t(arguments,1)),u[e]=o,r(n)})},function(n){r(n,u)})}function Cn(n,t){Rn(_e,n,t)}function $n(n,t,e){Rn(z(t),n,e)}function Wn(n,t){if(t=g(t||m),!qt(n))return t(new TypeError("First argument to race must be an array of functions"));if(!n.length)return t();for(var e=0,r=n.length;er?1:0}var u=a(t);Me(n,function(n,t){u(n,function(e,r){return e?t(e):void t(null,{value:n,criteria:r})})},function(n,t){return n?e(n):void e(null,K(t.sort(r),_n("value")))})}function Zn(n,t,e){var r=a(n);return ft(function(u,o){function i(){var t=n.name||"anonymous",r=new Error('Callback function "'+t+'" timed out.');r.code="ETIMEDOUT",e&&(r.info=e),f=!0,o(r)}var c,f=!1;u.push(function(){f||(o.apply(null,arguments),clearTimeout(c))}),c=setTimeout(i,t),r.apply(null,u)})}function nt(n,t,e,r){for(var u=-1,o=tu(nu((t-n)/(e||1)),0),i=Array(o);o--;)i[r?o:++u]=n,n+=e;return i}function tt(n,t,e,r){var u=a(e);ze(nt(0,n,1),t,u,r)}function et(n,t,e,r){arguments.length<=3&&(r=e,e=t,t=qt(n)?[]:{}),r=g(r||m);var u=a(e);_e(n,function(n,e,r){u(t,n,e,r)},function(n){r(n,t)})}function rt(n,e){var r,u=null;e=e||m,Fr(n,function(n,e){a(n)(function(n,o){r=arguments.length>2?t(arguments,1):o,u=n,e(!n)})},function(){e(u,r)})}function ut(n){return function(){return(n.unmemoized||n).apply(null,arguments)}}function ot(n,e,r){r=U(r||m);var u=a(e);if(!n())return r(null);var o=function(e){if(e)return r(e);if(n())return u(o);var i=t(arguments,1);r.apply(null,[null].concat(i))};u(o)}function it(n,t,e){ot(function(){return!n.apply(this,arguments)},t,e)}var ct,ft=function(n){return function(){var e=t(arguments),r=e.pop();n.call(this,e,r)}},at="function"==typeof setImmediate&&setImmediate,lt="object"==typeof process&&"function"==typeof process.nextTick;ct=at?setImmediate:lt?process.nextTick:r;var st=u(ct),pt="function"==typeof Symbol,ht="object"==typeof global&&global&&global.Object===Object&&global,yt="object"==typeof self&&self&&self.Object===Object&&self,vt=ht||yt||Function("return this")(),dt=vt.Symbol,mt=Object.prototype,gt=mt.hasOwnProperty,bt=mt.toString,jt=dt?dt.toStringTag:void 0,St=Object.prototype,kt=St.toString,Ot="[object Null]",wt="[object Undefined]",xt=dt?dt.toStringTag:void 0,Lt="[object AsyncFunction]",Et="[object Function]",At="[object GeneratorFunction]",Tt="[object Proxy]",Bt=9007199254740991,Ft={},It="function"==typeof Symbol&&Symbol.iterator,_t=function(n){return It&&n[It]&&n[It]()},Mt="[object Arguments]",Ut=Object.prototype,zt=Ut.hasOwnProperty,Pt=Ut.propertyIsEnumerable,Vt=S(function(){return arguments}())?S:function(n){return j(n)&&zt.call(n,"callee")&&!Pt.call(n,"callee")},qt=Array.isArray,Dt="object"==typeof n&&n&&!n.nodeType&&n,Rt=Dt&&"object"==typeof module&&module&&!module.nodeType&&module,Ct=Rt&&Rt.exports===Dt,$t=Ct?vt.Buffer:void 0,Wt=$t?$t.isBuffer:void 0,Nt=Wt||k,Qt=9007199254740991,Gt=/^(?:0|[1-9]\d*)$/,Ht="[object Arguments]",Jt="[object Array]",Kt="[object Boolean]",Xt="[object Date]",Yt="[object Error]",Zt="[object Function]",ne="[object Map]",te="[object Number]",ee="[object Object]",re="[object RegExp]",ue="[object Set]",oe="[object String]",ie="[object WeakMap]",ce="[object ArrayBuffer]",fe="[object DataView]",ae="[object Float32Array]",le="[object Float64Array]",se="[object Int8Array]",pe="[object Int16Array]",he="[object Int32Array]",ye="[object Uint8Array]",ve="[object Uint8ClampedArray]",de="[object Uint16Array]",me="[object Uint32Array]",ge={};ge[ae]=ge[le]=ge[se]=ge[pe]=ge[he]=ge[ye]=ge[ve]=ge[de]=ge[me]=!0,ge[Ht]=ge[Jt]=ge[ce]=ge[Kt]=ge[fe]=ge[Xt]=ge[Yt]=ge[Zt]=ge[ne]=ge[te]=ge[ee]=ge[re]=ge[ue]=ge[oe]=ge[ie]=!1;var be="object"==typeof n&&n&&!n.nodeType&&n,je=be&&"object"==typeof module&&module&&!module.nodeType&&module,Se=je&&je.exports===be,ke=Se&&ht.process,Oe=function(){try{return ke&&ke.binding("util")}catch(n){}}(),we=Oe&&Oe.isTypedArray,xe=we?x(we):w,Le=Object.prototype,Ee=Le.hasOwnProperty,Ae=Object.prototype,Te=A(Object.keys,Object),Be=Object.prototype,Fe=Be.hasOwnProperty,Ie=V(P,1/0),_e=function(n,t,e){var r=d(n)?q:Ie;r(n,a(t),e)},Me=D(R),Ue=l(Me),ze=C(R),Pe=V(ze,1),Ve=l(Pe),qe=function(n){var e=t(arguments,1);return function(){var r=t(arguments);return n.apply(null,e.concat(r))}},De=W(),Re=function(n,e,r){function u(n,t){j.push(function(){f(n,t)})}function o(){if(0===j.length&&0===v)return r(null,y);for(;j.length&&v2&&(u=t(arguments,1)),e){var o={};N(y,function(n,t){o[t]=n}),o[n]=u,d=!0,b=Object.create(null),r(e,o)}else y[n]=u,c(n)});v++;var o=a(e[e.length-1]);e.length>1?o(y,u):o(u)}}function l(){for(var n,t=0;S.length;)n=S.pop(),t++,$(s(n),function(n){0===--k[n]&&S.push(n)});if(t!==h)throw new Error("async.auto cannot execute tasks due to a recursive dependency")}function s(t){var e=[];return N(n,function(n,r){qt(n)&&J(n,t,0)>=0&&e.push(r)}),e}"function"==typeof e&&(r=e,e=null),r=g(r||m);var p=B(n),h=p.length;if(!h)return r(null);e||(e=h);var y={},v=0,d=!1,b=Object.create(null),j=[],S=[],k={};N(n,function(t,e){if(!qt(t))return u(e,[t]),void S.push(e);var r=t.slice(0,t.length-1),o=r.length;return 0===o?(u(e,t),void S.push(e)):(k[e]=o,void $(r,function(c){if(!n[c])throw new Error("async.auto task `"+e+"` has a non-existent dependency `"+c+"` in "+r.join(", "));i(c,function(){o--,0===o&&u(e,t)})}))}),l(),o()},Ce="[object Symbol]",$e=1/0,We=dt?dt.prototype:void 0,Ne=We?We.toString:void 0,Qe="\\ud800-\\udfff",Ge="\\u0300-\\u036f\\ufe20-\\ufe23",He="\\u20d0-\\u20f0",Je="\\ufe0e\\ufe0f",Ke="\\u200d",Xe=RegExp("["+Ke+Qe+Ge+He+Je+"]"),Ye="\\ud800-\\udfff",Ze="\\u0300-\\u036f\\ufe20-\\ufe23",nr="\\u20d0-\\u20f0",tr="\\ufe0e\\ufe0f",er="["+Ye+"]",rr="["+Ze+nr+"]",ur="\\ud83c[\\udffb-\\udfff]",or="(?:"+rr+"|"+ur+")",ir="[^"+Ye+"]",cr="(?:\\ud83c[\\udde6-\\uddff]){2}",fr="[\\ud800-\\udbff][\\udc00-\\udfff]",ar="\\u200d",lr=or+"?",sr="["+tr+"]?",pr="(?:"+ar+"(?:"+[ir,cr,fr].join("|")+")"+sr+lr+")*",hr=sr+lr+pr,yr="(?:"+[ir+rr+"?",rr,cr,fr,er].join("|")+")",vr=RegExp(ur+"(?="+ur+")|"+yr+hr,"g"),dr=/^\s+|\s+$/g,mr=/^(?:async\s+)?(function)?\s*[^\(]*\(\s*([^\)]*)\)/m,gr=/,/,br=/(=.+)?(\s*)$/,jr=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;pn.prototype.removeLink=function(n){return n.prev?n.prev.next=n.next:this.head=n.next,n.next?n.next.prev=n.prev:this.tail=n.prev,n.prev=n.next=null,this.length-=1,n},pn.prototype.empty=function(){for(;this.head;)this.shift();return this},pn.prototype.insertAfter=function(n,t){t.prev=n,t.next=n.next,n.next?n.next.prev=t:this.tail=t,n.next=t,this.length+=1},pn.prototype.insertBefore=function(n,t){t.prev=n.prev,t.next=n,n.prev?n.prev.next=t:this.head=t,n.prev=t,this.length+=1},pn.prototype.unshift=function(n){this.head?this.insertBefore(this.head,n):hn(this,n)},pn.prototype.push=function(n){this.tail?this.insertAfter(this.tail,n):hn(this,n)},pn.prototype.shift=function(){return this.head&&this.removeLink(this.head)},pn.prototype.pop=function(){return this.tail&&this.removeLink(this.tail)},pn.prototype.toArray=function(){for(var n=Array(this.length),t=this.head,e=0;e=u.priority;)u=u.next;for(var o=0,i=n.length;o * { 37 | width: 1200px; 38 | position: relative; 39 | } 40 | 41 | .pane { 42 | padding: 1.5rem 2rem; 43 | margin: 1.5rem 0; 44 | border-left: none; 45 | border-right: none; 46 | } 47 | .pane + .pane { 48 | border-top: none; margin-top: 0; 49 | padding-top: 0; 50 | } 51 | 52 | .pane .info > table th { 53 | color: #8D8E90; 54 | } 55 | 56 | .account { 57 | background: #1C1D21; 58 | } 59 | 60 | .account .info { 61 | display: inline-block; 62 | } 63 | 64 | .account .buttons { 65 | position: absolute; 66 | right: 0px; 67 | display: inline-block; 68 | width: 420px; 69 | margin-top: 0.5rem; 70 | margin-right: 2rem; 71 | } 72 | 73 | .account .buttons > div.row { 74 | display: inline-block; 75 | } 76 | 77 | .account .buttons > div.row > div.button { 78 | display: inline-block; 79 | width: 200px; 80 | border: 1px solid #ffffff; 81 | text-transform: uppercase; 82 | padding: 5px; 83 | text-align: center; 84 | } 85 | 86 | .account .buttons > div.row > div.button > a { 87 | color: #ffffff; 88 | text-decoration: none; 89 | } 90 | 91 | .sales > table tr > td { 92 | border-bottom: 1px groove #8D8E90; 93 | } 94 | 95 | .sales > table th { 96 | border-bottom: 1px groove #8D8E90; 97 | } 98 | 99 | .active { 100 | background: #1C1D21; 101 | font-weight: bold; 102 | } 103 | 104 | .closed { 105 | color: gray; 106 | } 107 | 108 | button, input, select { 109 | font: inherit; 110 | padding: 0rem .25rem; 111 | } 112 | 113 | .hidden { 114 | display: none; 115 | } 116 | 117 | button { 118 | padding-left: 1rem; 119 | padding-right: 1rem; 120 | } 121 | 122 | h3 { 123 | margin: 0 0 .75rem; 124 | } 125 | 126 | table { 127 | text-align: right; 128 | border-collapse: collapse; 129 | } 130 | 131 | td, th { 132 | padding: .25rem 1rem; 133 | } 134 | 135 | #generate-confirm table > tbody > tr > th { 136 | color: #8D8E90; 137 | } 138 | 139 | #generate-pane table > tbody > tr > th { 140 | color: #8D8E90; 141 | } 142 | 143 | #buy-pane table > tbody > tr > th { 144 | color: #8D8E90; 145 | } 146 | 147 | .account .buttons > div.row > div.button > a.disabled { 148 | color: #8D8E90; 149 | cursor: not-allowed; 150 | } 151 | 152 | .account .buttons > div.row > div.button.disabled { 153 | border: 1px groove #8D8E90; 154 | opacity: 0.8; 155 | } 156 | 157 | #sale-window { 158 | background: #1C1D21; 159 | color: #ffffff; 160 | width: 150px; 161 | height: 35px; 162 | border: none; 163 | } 164 | 165 | input[type='text'] { 166 | background: #1C1D21; 167 | color: #ffffff; 168 | border: none; 169 | } 170 | 171 | button { 172 | background: black; 173 | color: #ffffff; 174 | border: 1px double #ffffff; 175 | } 176 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | EOS Token Distribution 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 |
26 |

EOS Token Distribution

27 |

Loading...please wait. Unlock your MetaMask wallet and/or reload this page if the interface does not load in a few seconds.

28 |
29 |

30 | If problems persist there may be a problem with your connection to the Ethereum network. You can try configuring MetaMask to use one of the following servers: 31 | 32 |

    33 |
  1. http://rpc.makerdao.com:7777
  2. 34 |
  3. http://localhost:8545 (if you are running a full Parity Node)
  4. 35 |
36 | 37 |
38 | 39 | We are in the process of setting up additional RPC severs to handle the requests. 40 | 41 |

42 |
43 |
44 | -------------------------------------------------------------------------------- /docs/index.js: -------------------------------------------------------------------------------- 1 | let EOS_SALE = "0xd0a6e6c54dbc68db5db3a091b171a77407ff7ccf" 2 | let EOS_SALE_UTIL = "0x860fd485f533b0348e413e65151f7ee993f93c02" 3 | let EOS_TOKEN = "0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0" 4 | 5 | let eos_sale, eos_token 6 | 7 | let startTime = 1498914000 8 | let startMoment = moment(startTime * 1000) 9 | let numberOfDays = 350 10 | let createFirstDay = WAD * 20000000000 11 | let createPerDay = WAD * 200000000 12 | 13 | let createOnDay = day => web3.toBigNumber( 14 | day == 0 ? createFirstDay : createPerDay 15 | ) 16 | 17 | let getTime = () => new Date().getTime() / 1000 18 | let dayFor = timestamp => timestamp < startTime ? 0 19 | : Math.floor((timestamp - startTime) / 23 / 60 / 60) + 1; 20 | 21 | let state = { 22 | buyWindow: dayFor(getTime()), 23 | } 24 | 25 | let balanceOf = async (token, address) => web3.toBigNumber(hex(await call({ 26 | to: token, data: calldata(sighash("balanceOf(address)"), address) 27 | }))) 28 | 29 | let getDailyTotals = async () => words32(await call({ 30 | to: EOS_SALE_UTIL, data: sighash("dailyTotals()"), 31 | })).map(web3.toBigNumber) 32 | 33 | let getUserBuys = async address => words32(await call({ 34 | to: EOS_SALE_UTIL, data: calldata(sighash("userBuys()"), address), 35 | })).map(web3.toBigNumber) 36 | 37 | let getUserClaims = async address => words32(await call({ 38 | to: EOS_SALE_UTIL, data: calldata(sighash("userClaims()"), address), 39 | })).map(Number).map(Boolean) 40 | 41 | let getKey = async address => bytes( 42 | words32(await call({ 43 | to: EOS_SALE, data: calldata(sighash("keys(address)")) 44 | })).slice(2).map(unhex).join("").replace(/(00)*$/, "") 45 | ).map(Number).map(String.fromCharCode).join("") 46 | 47 | addEventListener("mousemove", event => eos_ecc.key_utils.addEntropy( 48 | event.pageX, event.pageY, event.screenX, event.screenY 49 | ), { capture: false, passive: true }) 50 | 51 | onload = () => { 52 | if (window.web3) { 53 | eos_sale = web3.eth.contract(EOS_SALE_ABI).at(EOS_SALE) 54 | eos_token = web3.eth.contract(EOS_TOKEN_ABI).at(EOS_TOKEN) 55 | 56 | poll() 57 | } else { 58 | byId("app").innerHTML = ` 59 |
60 |
61 |

Could not connect to Ethereum

62 |

63 | 64 | Consider installing MetaMask, 65 | Mist or another Ethereum client. 66 | 67 | If you’re using MetaMask, you may need to unlock 68 | your account. You can also try disabling and re-enabling 69 | the MetaMask plugin by going to chrome://extensions. 71 | 72 |

73 | 74 |

Please reload this page and try again.

75 |
76 |
77 | ` 78 | } 79 | } 80 | 81 | let refresh = () => new Promise(resolve => async.parallel(Object.assign({ 82 | dailyTotals: toAsync(getDailyTotals()), 83 | }, web3.eth.accounts[0] ? { 84 | eth_balance: $ => web3.eth.getBalance(web3.eth.accounts[0], $), 85 | eos_balance: toAsync(balanceOf(EOS_TOKEN, web3.eth.accounts[0])), 86 | publicKey: toAsync(getKey(web3.eth.accounts[0])), 87 | userBuys: toAsync(getUserBuys(web3.eth.accounts[0])), 88 | userClaims: toAsync(getUserClaims(web3.eth.accounts[0])), 89 | } : {}), hopefully(({ 90 | dailyTotals, eth_balance, eos_balance, publicKey, userBuys, userClaims, 91 | }) => { 92 | let time = getTime() 93 | 94 | if (keyChange(publicKey)) { 95 | if (byId("generate-link")) { 96 | enable("generate-link") 97 | } 98 | if (byId("register-pane")) { 99 | hide("register-pane") 100 | } 101 | } 102 | 103 | let days = iota(Number(numberOfDays) + 1).map(i => { 104 | let day = {} 105 | 106 | day.createOnDay = createOnDay(i).div(WAD) 107 | day.dailyTotal = dailyTotals[i].div(WAD) 108 | 109 | day.price = day.dailyTotal.div(day.createOnDay) 110 | 111 | day.userBuys = userBuys[i] && userBuys[i].div(WAD) 112 | day.received = !day.userBuys || day.dailyTotal.equals(0) 113 | ? web3.toBigNumber(0) 114 | : day.createOnDay.div(day.dailyTotal).times(day.userBuys) 115 | 116 | if (i == 0) { 117 | day.ends = startMoment 118 | } else { 119 | day.begins = startMoment.clone().add(23 * (i - 1), "hours") 120 | day.ends = day.begins.clone().add(23, "hours") 121 | } 122 | 123 | day.claimed = userClaims && userClaims[i] 124 | 125 | return day 126 | }) 127 | 128 | let unclaimed = days.filter((x, i) => { 129 | return i < dayFor(time) && !x.claimed 130 | }).reduce((a, x) => x.received.plus(a), web3.toBigNumber(0)) 131 | 132 | resolve(update({ 133 | time, days, unclaimed, eth_balance, eos_balance, publicKey 134 | })) 135 | }))) 136 | 137 | let render = ({ 138 | time, days, unclaimed, eth_balance, eos_balance, publicKey, buyWindow, 139 | }) =>
140 |

141 | 142 | The EOS Token Distribution will take place over about 341 days. 143 | 1,000,000,000 (one billion) EOS tokens will be created at the 144 | start of the sale, 100,000,000 EOS are allocated to block.one and cannot be 145 | transfered. 146 | 147 | The remaining 900,000,000 EOS will be split into different rolling windows of 148 | availability. The EOS tokens in a given window will be split 149 | proportionally to all ETH contributions made during that window. 150 | 200,000,000 EOS will be sold in the first window, lasting five days. 151 | The remaining 700,000,000 will be divided equally into 350 windows, each 152 | lasting 23 hours and distributing 2,000,000 EOS. Contributions can be made to 153 | any future window, but the EOS cannot be claimed until the window closes. 154 | 155 | Once a window closes, the EOS tokens allocated to that window are 156 | available to be claimed. 157 | 158 | You must generate and register an EOS Public Key or it will not be possible for 159 | anyone to include your EOS tokens in the genesis block of any future blockchain's 160 | based on EOS.IO software. 161 | 162 | By sending ETH to this contract you agree to the Terms & Conditions and Purchase Agreement. 163 |

164 | 165 |

166 | For more details, please review the smart contract source 168 | code. 169 |

170 | 171 | 178 | Last updated {moment(time * 1000).format("LTS")} 179 | 180 | 181 | {web3.eth.accounts[0] ?
182 |
183 |

EOS Token Distribution

184 |
185 | 186 | 187 | 190 | 191 | 192 | 193 | 196 | 197 | 198 | 199 | 210 | 211 | 212 | 213 | 216 | 217 | 218 | 219 | 222 | 223 | 224 | 225 | 228 | 229 |
Contract address 188 | {EOS_SALE} 189 |
Ethereum account 194 | {web3.eth.accounts[0]} 195 |
EOS public key 200 | {publicKey ? 201 | 202 | {publicKey} 203 | 204 | : 205 | 206 | (no EOS key registered) 207 | 208 | } 209 |
Token balances 214 | {formatETH(eth_balance.div(WAD))} ETH 215 |
220 | {formatEOS(unclaimed)} EOS (unclaimed) 221 |
226 | {formatEOS(eos_balance.div(WAD))} EOS 227 |
230 | 274 |
275 |
(event.preventDefault(), generateConfirm())}> 277 | 278 | Generating key... 279 | 280 |
281 |

{publicKey ? "Change" : "Register"} EOS key

282 | 283 | {publicKey ?

This will replace your EOS claim key: 284 | 285 | 286 | 287 | 288 | 291 | 292 | 293 |
Public key 289 | {publicKey} 290 |
294 |

: } 295 | 296 |

Please back up the private key displayed below in multiple 297 | safe locations before continuing. You should make more than 298 | one copy and keep all copies in separate secure locations. 299 | If you use an external storage device such as a USB stick, 300 | make sure to safely eject the device before continuing.

301 | 302 | 303 | 304 | 305 | 306 | 309 | 310 | 311 | 312 | 315 | 316 | 317 | 318 | 321 | 322 | 323 | 324 | 335 | 336 | 337 |
Description 307 | EOS Token Distribution Claim Key 308 |
Public key 313 | 314 |
Private key 319 | 320 |
Confirm private key 325 | 329 |

330 | 331 | Private key does not match 332 | 333 |

334 |
338 | 339 |

340 | 341 | There is no way to recover your private key. You must save 342 | it right now or you will be unable to access your EOS tokens 343 | when the sale ends. 344 | 345 |

346 | 347 | 350 | 353 |
354 |
355 |
356 |

{publicKey ? "Change" : "Register"} EOS public key

357 | 358 | 359 | 360 | 361 | 364 | 365 | 366 |
Public key 362 |   363 |
367 | 368 | 369 | {publicKey ? "Changing" : "Registering"} key... 370 | 371 | 372 |
373 |
(event.preventDefault(), buy())}> 375 |

Get EOS tokens

376 | 377 | 378 | 379 | 387 | 388 | 389 | 390 | 393 | 394 | 395 | 396 | 399 | 400 | 401 | 402 | 405 | 406 | 407 | 408 | 411 | 412 | 413 | 414 | 417 | 418 | 419 | 420 | 433 | 434 |
Distribution period 380 | 386 |
Closing 391 | {days[buyWindow].ends.fromNow()} 392 |
EOS Distributed 397 | {formatEOS(days[buyWindow].createOnDay)} EOS 398 |
Total ETH 403 | {formatETH(days[buyWindow].dailyTotal)} ETH 404 |
Your ETH 409 | {formatETH(days[buyWindow].userBuys)} ETH 410 |
Effective price 415 | {days[buyWindow].price.toFormat(9)} ETH/EOS 416 |
Send ETH 421 | 423 | {" ETH"} 424 | 425 | 428 | 429 | Sending ETH... 430 | 431 | 432 |
435 |
436 |
(event.preventDefault(), transfer())}> 438 |

Transfer EOS tokens to another Ethereum account

439 | 440 | 441 | 442 | 449 | 450 | 451 | 452 | 467 | 468 |
Recipient account 443 | 448 |
Transfer amount 453 | 457 | {" EOS"} 458 | 459 | 462 | 463 | Transferring tokens... 464 | 465 | 466 |
469 |
470 |
471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | {days.map((day, i) => 485 | 486 | 490 | 491 | 492 | 495 | 496 | 497 | 502 | 503 | )} 504 | 505 |
PeriodEOS DistributedTotal ETHEffective priceClosingYour ETHYour EOS
487 | #{i} 488 | {i == dayFor(time) ? "" : ""} 489 | {formatEOS(day.createOnDay)} EOS{formatETH(day.dailyTotal)} ETH{day.dailyTotal == 0 ? "n/a" : ( 493 | `${day.price.toFormat(9)} ETH/EOS` 494 | )}{day.ends.fromNow()}{formatETH(day.userBuys)} ETH 498 | {formatEOS(day.received)} EOS 499 | {i >= dayFor(time) 500 | && *} 501 |
506 |
507 |
:
508 |

Ethereum account not found

509 | 510 | It looks like an Ethereum client is available in your 511 | browser, but I couldn’t find any accounts. 512 | If you’re using MetaMask, you may need to unlock 513 | your account. You can also try disabling and re-enabling 514 | the MetaMask plugin by going to chrome://extensions. 516 | 517 |
} 518 |
519 | 520 | function buy() { 521 | byId("buy-button").classList.add("hidden") 522 | byId("buy-progress").classList.remove("hidden") 523 | let amount = getValue("buy-input").replace(/,/g, "") 524 | eos_sale.buyWithLimit(state.buyWindow, 0, { 525 | value: web3.toWei(amount) 526 | }, hopefully(result => 527 | ping(result).then(() => { 528 | hidePanes() 529 | byId("buy-input").value = "" 530 | byId("buy-button").classList.remove("hidden") 531 | byId("buy-progress").classList.add("hidden") 532 | }) 533 | )) 534 | } 535 | 536 | function claim() { 537 | byId("claim-button").classList.add("hidden") 538 | disable("claim-button") 539 | byId("claim-progress").classList.remove("hidden") 540 | eos_sale.claimAll({ 541 | gas: 2000000, 542 | }, hopefully(result => ping(result).then(() => { 543 | byId("claim-button").classList.remove("hidden") 544 | byId("claim-progress").classList.add("hidden") 545 | }))) 546 | } 547 | 548 | function transfer() { 549 | byId("transfer-button").classList.add("hidden") 550 | byId("transfer-progress").classList.remove("hidden") 551 | let guy = getValue("transfer-address-input") 552 | let wad = web3.toBigNumber( 553 | getValue("transfer-amount-input").replace(/,/g, "") 554 | ).times(WAD) 555 | eos_token.transfer(guy, wad, hopefully(result => ping(result).then(() => { 556 | hidePanes() 557 | byId("transfer-button").classList.remove("hidden") 558 | byId("transfer-progress").classList.add("hidden") 559 | }))) 560 | } 561 | 562 | function generate() { 563 | showPane('generate') 564 | show("generate-progress") 565 | hide("generate-confirm") 566 | setTimeout(() => { 567 | privateKeyPair = genKeyPair() 568 | hide("generate-progress") 569 | byId("generate-pubkey").innerHTML = privateKeyPair.pubkey 570 | byId("generate-privkey").innerHTML = privateKeyPair.privkey 571 | byId("generate-confirm-input").value = "" 572 | show("generate-confirm") 573 | }) 574 | } 575 | 576 | let privateKeyPair = null 577 | 578 | function genKeyPair() { 579 | let {PrivateKey} = eos_ecc 580 | let d = PrivateKey.randomKey() 581 | let privkey = d.toWif() 582 | let pubkey = d.toPublic().toString() 583 | return {pubkey, privkey} 584 | } 585 | 586 | function generateConfirm() { 587 | const confirmPriv = getValue("generate-confirm-input") 588 | if(confirmPriv !== privateKeyPair.privkey) { 589 | show("generate-unmatched") 590 | return 591 | } 592 | hide("generate-unmatched") 593 | hide('generate-pane') 594 | byId("generate-pubkey").innerHTML = null 595 | byId("generate-privkey").innerHTML = null 596 | byId("generate-confirm-input").value = null 597 | show('register-pane') 598 | register() 599 | } 600 | 601 | function generateCancel(e) { 602 | e.preventDefault() 603 | privateKeyPair = null 604 | hide('register-pane') 605 | enable("generate-link") 606 | hide('generate-pane') 607 | hide("generate-unmatched") 608 | byId("generate-pubkey").innerHTML = null 609 | byId("generate-privkey").innerHTML = null 610 | byId("generate-confirm-input").value = null 611 | } 612 | 613 | function register() { 614 | const key = privateKeyPair.pubkey 615 | show("register-progress") 616 | eos_sale.register(key, { 617 | gas: 1000000, 618 | }, hopefully(result => ping(result).then(() => { 619 | hidePanes() 620 | hide("register-progress") 621 | }))) 622 | } 623 | 624 | let lastPublicKey 625 | 626 | function keyChange(pubkey) { 627 | const changed = (lastPublicKey != pubkey) 628 | lastPublicKey = pubkey 629 | return changed 630 | } 631 | 632 | let ping = tx => new Promise((resolve, reject) => { 633 | loop() 634 | function loop() { 635 | web3.eth.getTransactionReceipt(tx, async (error, receipt) => { 636 | if (receipt) { 637 | await refresh() 638 | resolve(receipt) 639 | } else { 640 | setTimeout(loop, 1000) 641 | } 642 | }) 643 | } 644 | }) 645 | 646 | let loaded 647 | 648 | setTimeout(() => loaded || location.reload(), 5000) 649 | 650 | let poll = async () => { 651 | await refresh() 652 | loaded = true 653 | setTimeout(poll, 10000) 654 | } 655 | -------------------------------------------------------------------------------- /docs/lib.js: -------------------------------------------------------------------------------- 1 | let WAD = 1000000000000000000 2 | 3 | let unhex = data => data.replace(/^0x/, "") 4 | let hex = data => `0x${unhex(data)}` 5 | let bytes4 = data => hex(unhex(data).slice(0, 8)) 6 | let sighash = sig => bytes4(web3.sha3(sig)) 7 | let parts = (data, n) => data.match(new RegExp(`.{${n}}`, "g")) || [] 8 | let hexparts = (data, n) => parts(unhex(data), n).map(hex) 9 | let words32 = data => hexparts(data, 64) 10 | let bytes = data => hexparts(data, 2) 11 | let hexcat = (...data) => hex(data.map(unhex).join("")) 12 | let word = data => hex(unhex(data).padStart(64, "0")) 13 | let calldata = (sig, ...words) => hexcat(sig, ...words.map(word)) 14 | let toAsync = promise => $ => promise.then(x => $(null, x), $) 15 | var byId = id => document.getElementById(id) 16 | var formatWad = wad => String(wad).replace(/\..*/, "") 17 | var formatEOS = wad => wad ? wad.toFormat(4) : "0" 18 | var formatETH = wad => wad ? wad.toFormat(2) : "0" 19 | var getValue = id => byId(id).value 20 | var show = id => byId(id).classList.remove("hidden") 21 | var hide = id => byId(id).classList.add("hidden") 22 | var iota = n => repeat("x", n).split("").map((_, i) => i) 23 | var repeat = (x, n) => new Array(n + 1).join("x") 24 | 25 | let toQueryString = params => Object.keys(params).map(name => ([ 26 | encodeURIComponent(name), encodeURIComponent(params[name]), 27 | ])).map(([name, value]) => `${name}=${value}`).join("&") 28 | 29 | let call = params => etherscan( 30 | Object.assign(params, { module: "proxy", action: "eth_call" }) 31 | ) 32 | 33 | let ETHERSCAN_URL = "https://api.etherscan.io/api?" 34 | let etherscan = async params => { 35 | let response = await fetch(ETHERSCAN_URL + toQueryString(params)) 36 | 37 | if (response.ok) { 38 | let json = await response.json() 39 | 40 | if (json.error) { 41 | throw new Error(JSON.stringify(json.error)) 42 | } else { 43 | return json.result 44 | } 45 | } else { 46 | throw new Error(`HTTP ${response.statusCode}`) 47 | } 48 | } 49 | 50 | let update = patch => { 51 | state = Object.assign({}, state, patch) 52 | ReactDOM.render(render(state), byId("app")) 53 | } 54 | 55 | let hopefully = $ => (error, result) => { 56 | if (error) { 57 | lament(error) 58 | } else { 59 | $(result) 60 | } 61 | } 62 | 63 | function lament(error) { 64 | if (error) { 65 | document.querySelector(".before-error").outerHTML += ` 66 |
67 |

${error.message}

68 |
${error.stack}
69 |
70 | ` 71 | } 72 | } 73 | 74 | function showPane(name) { 75 | hidePanes() 76 | show(`${name}-pane`) 77 | disable(`${name}-link`) 78 | } 79 | 80 | function hidePanes() { 81 | for (let x of "generate transfer buy register".split(" ")) { 82 | try { 83 | enable(`${x}-link`) 84 | hide(`${x}-pane`) 85 | } catch (error) {} 86 | } 87 | } 88 | 89 | function enable(id) { 90 | byId(id).classList.remove("disabled"); 91 | byId(id).parentNode.classList.remove("disabled"); 92 | } 93 | 94 | function disable(id) { 95 | byId(id).classList.add("disabled"); 96 | byId(id).parentNode.classList.add("disabled"); 97 | } 98 | -------------------------------------------------------------------------------- /docs/moment.min.js: -------------------------------------------------------------------------------- 1 | //! moment.js 2 | //! version : 2.18.1 3 | //! authors : Tim Wood, Iskren Chernev, Moment.js contributors 4 | //! license : MIT 5 | //! momentjs.com 6 | !function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return sd.apply(null,arguments)}function b(a){sd=a}function c(a){return a instanceof Array||"[object Array]"===Object.prototype.toString.call(a)}function d(a){return null!=a&&"[object Object]"===Object.prototype.toString.call(a)}function e(a){var b;for(b in a)return!1;return!0}function f(a){return void 0===a}function g(a){return"number"==typeof a||"[object Number]"===Object.prototype.toString.call(a)}function h(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function i(a,b){var c,d=[];for(c=0;c0)for(c=0;c0?"future":"past"];return z(c)?c(b):c.replace(/%s/i,b)}function J(a,b){var c=a.toLowerCase();Hd[c]=Hd[c+"s"]=Hd[b]=a}function K(a){return"string"==typeof a?Hd[a]||Hd[a.toLowerCase()]:void 0}function L(a){var b,c,d={};for(c in a)j(a,c)&&(b=K(c),b&&(d[b]=a[c]));return d}function M(a,b){Id[a]=b}function N(a){var b=[];for(var c in a)b.push({unit:c,priority:Id[c]});return b.sort(function(a,b){return a.priority-b.priority}),b}function O(b,c){return function(d){return null!=d?(Q(this,b,d),a.updateOffset(this,c),this):P(this,b)}}function P(a,b){return a.isValid()?a._d["get"+(a._isUTC?"UTC":"")+b]():NaN}function Q(a,b,c){a.isValid()&&a._d["set"+(a._isUTC?"UTC":"")+b](c)}function R(a){return a=K(a),z(this[a])?this[a]():this}function S(a,b){if("object"==typeof a){a=L(a);for(var c=N(a),d=0;d=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}function U(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(Md[a]=e),b&&(Md[b[0]]=function(){return T(e.apply(this,arguments),b[1],b[2])}),c&&(Md[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function V(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function W(a){var b,c,d=a.match(Jd);for(b=0,c=d.length;b=0&&Kd.test(a);)a=a.replace(Kd,c),Kd.lastIndex=0,d-=1;return a}function Z(a,b,c){ce[a]=z(b)?b:function(a,d){return a&&c?c:b}}function $(a,b){return j(ce,a)?ce[a](b._strict,b._locale):new RegExp(_(a))}function _(a){return aa(a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}))}function aa(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function ba(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),g(b)&&(d=function(a,c){c[b]=u(a)}),c=0;c=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function ta(a){var b=new Date(Date.UTC.apply(null,arguments));return a<100&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b}function ua(a,b,c){var d=7+b-c,e=(7+ta(a,0,d).getUTCDay()-b)%7;return-e+d-1}function va(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=ua(a,d,e),j=1+7*(b-1)+h+i;return j<=0?(f=a-1,g=pa(f)+j):j>pa(a)?(f=a+1,g=j-pa(a)):(f=a,g=j),{year:f,dayOfYear:g}}function wa(a,b,c){var d,e,f=ua(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return g<1?(e=a.year()-1,d=g+xa(e,b,c)):g>xa(a.year(),b,c)?(d=g-xa(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function xa(a,b,c){var d=ua(a,b,c),e=ua(a+1,b,c);return(pa(a)-d+e)/7}function ya(a){return wa(a,this._week.dow,this._week.doy).week}function za(){return this._week.dow}function Aa(){return this._week.doy}function Ba(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function Ca(a){var b=wa(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}function Da(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function Ea(a,b){return"string"==typeof a?b.weekdaysParse(a)%7||7:isNaN(a)?null:a}function Fa(a,b){return a?c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?"format":"standalone"][a.day()]:c(this._weekdays)?this._weekdays:this._weekdays.standalone}function Ga(a){return a?this._weekdaysShort[a.day()]:this._weekdaysShort}function Ha(a){return a?this._weekdaysMin[a.day()]:this._weekdaysMin}function Ia(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],d=0;d<7;++d)f=l([2e3,1]).day(d),this._minWeekdaysParse[d]=this.weekdaysMin(f,"").toLocaleLowerCase(),this._shortWeekdaysParse[d]=this.weekdaysShort(f,"").toLocaleLowerCase(),this._weekdaysParse[d]=this.weekdays(f,"").toLocaleLowerCase();return c?"dddd"===b?(e=ne.call(this._weekdaysParse,g),e!==-1?e:null):"ddd"===b?(e=ne.call(this._shortWeekdaysParse,g),e!==-1?e:null):(e=ne.call(this._minWeekdaysParse,g),e!==-1?e:null):"dddd"===b?(e=ne.call(this._weekdaysParse,g),e!==-1?e:(e=ne.call(this._shortWeekdaysParse,g),e!==-1?e:(e=ne.call(this._minWeekdaysParse,g),e!==-1?e:null))):"ddd"===b?(e=ne.call(this._shortWeekdaysParse,g),e!==-1?e:(e=ne.call(this._weekdaysParse,g),e!==-1?e:(e=ne.call(this._minWeekdaysParse,g),e!==-1?e:null))):(e=ne.call(this._minWeekdaysParse,g),e!==-1?e:(e=ne.call(this._weekdaysParse,g),e!==-1?e:(e=ne.call(this._shortWeekdaysParse,g),e!==-1?e:null)))}function Ja(a,b,c){var d,e,f;if(this._weekdaysParseExact)return Ia.call(this,a,b,c);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;d<7;d++){if(e=l([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp("^"+this.weekdays(e,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[d]=new RegExp("^"+this.weekdaysShort(e,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[d]=new RegExp("^"+this.weekdaysMin(e,"").replace(".",".?")+"$","i")),this._weekdaysParse[d]||(f="^"+this.weekdays(e,"")+"|^"+this.weekdaysShort(e,"")+"|^"+this.weekdaysMin(e,""),this._weekdaysParse[d]=new RegExp(f.replace(".",""),"i")),c&&"dddd"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&"ddd"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&"dd"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}}function Ka(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Da(a,this.localeData()),this.add(a-b,"d")):b}function La(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Ma(a){if(!this.isValid())return null!=a?this:NaN;if(null!=a){var b=Ea(a,this.localeData());return this.day(this.day()%7?b:b-7)}return this.day()||7}function Na(a){return this._weekdaysParseExact?(j(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysStrictRegex:this._weekdaysRegex):(j(this,"_weekdaysRegex")||(this._weekdaysRegex=ye),this._weekdaysStrictRegex&&a?this._weekdaysStrictRegex:this._weekdaysRegex)}function Oa(a){return this._weekdaysParseExact?(j(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(j(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=ze),this._weekdaysShortStrictRegex&&a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Pa(a){return this._weekdaysParseExact?(j(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(j(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=Ae),this._weekdaysMinStrictRegex&&a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function Qa(){function a(a,b){return b.length-a.length}var b,c,d,e,f,g=[],h=[],i=[],j=[];for(b=0;b<7;b++)c=l([2e3,1]).day(b),d=this.weekdaysMin(c,""),e=this.weekdaysShort(c,""),f=this.weekdays(c,""),g.push(d),h.push(e),i.push(f),j.push(d),j.push(e),j.push(f);for(g.sort(a),h.sort(a),i.sort(a),j.sort(a),b=0;b<7;b++)h[b]=aa(h[b]),i[b]=aa(i[b]),j[b]=aa(j[b]);this._weekdaysRegex=new RegExp("^("+j.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+i.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+h.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+g.join("|")+")","i")}function Ra(){return this.hours()%12||12}function Sa(){return this.hours()||24}function Ta(a,b){U(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}function Ua(a,b){return b._meridiemParse}function Va(a){return"p"===(a+"").toLowerCase().charAt(0)}function Wa(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Xa(a){return a?a.toLowerCase().replace("_","-"):a}function Ya(a){for(var b,c,d,e,f=0;f0;){if(d=Za(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&v(e,c,!0)>=b-1)break;b--}f++}return null}function Za(a){var b=null;if(!Fe[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=Be._abbr,require("./locale/"+a),$a(b)}catch(a){}return Fe[a]}function $a(a,b){var c;return a&&(c=f(b)?bb(a):_a(a,b),c&&(Be=c)),Be._abbr}function _a(a,b){if(null!==b){var c=Ee;if(b.abbr=a,null!=Fe[a])y("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),c=Fe[a]._config;else if(null!=b.parentLocale){if(null==Fe[b.parentLocale])return Ge[b.parentLocale]||(Ge[b.parentLocale]=[]),Ge[b.parentLocale].push({name:a,config:b}),null;c=Fe[b.parentLocale]._config}return Fe[a]=new C(B(c,b)),Ge[a]&&Ge[a].forEach(function(a){_a(a.name,a.config)}),$a(a),Fe[a]}return delete Fe[a],null}function ab(a,b){if(null!=b){var c,d=Ee;null!=Fe[a]&&(d=Fe[a]._config),b=B(d,b),c=new C(b),c.parentLocale=Fe[a],Fe[a]=c,$a(a)}else null!=Fe[a]&&(null!=Fe[a].parentLocale?Fe[a]=Fe[a].parentLocale:null!=Fe[a]&&delete Fe[a]);return Fe[a]}function bb(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return Be;if(!c(a)){if(b=Za(a))return b;a=[a]}return Ya(a)}function cb(){return Ad(Fe)}function db(a){var b,c=a._a;return c&&n(a).overflow===-2&&(b=c[fe]<0||c[fe]>11?fe:c[ge]<1||c[ge]>ea(c[ee],c[fe])?ge:c[he]<0||c[he]>24||24===c[he]&&(0!==c[ie]||0!==c[je]||0!==c[ke])?he:c[ie]<0||c[ie]>59?ie:c[je]<0||c[je]>59?je:c[ke]<0||c[ke]>999?ke:-1,n(a)._overflowDayOfYear&&(bge)&&(b=ge),n(a)._overflowWeeks&&b===-1&&(b=le),n(a)._overflowWeekday&&b===-1&&(b=me),n(a).overflow=b),a}function eb(a){var b,c,d,e,f,g,h=a._i,i=He.exec(h)||Ie.exec(h);if(i){for(n(a).iso=!0,b=0,c=Ke.length;b10?"YYYY ":"YY "),f="HH:mm"+(c[4]?":ss":""),c[1]){var l=new Date(c[2]),m=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][l.getDay()];if(c[1].substr(0,3)!==m)return n(a).weekdayMismatch=!0,void(a._isValid=!1)}switch(c[5].length){case 2:0===i?h=" +0000":(i=k.indexOf(c[5][1].toUpperCase())-12,h=(i<0?" -":" +")+(""+i).replace(/^-?/,"0").match(/..$/)[0]+"00");break;case 4:h=j[c[5]];break;default:h=j[" GMT"]}c[5]=h,a._i=c.splice(1).join(""),g=" ZZ",a._f=d+e+f+g,lb(a),n(a).rfc2822=!0}else a._isValid=!1}function gb(b){var c=Me.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(eb(b),void(b._isValid===!1&&(delete b._isValid,fb(b),b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b)))))}function hb(a,b,c){return null!=a?a:null!=b?b:c}function ib(b){var c=new Date(a.now());return b._useUTC?[c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate()]:[c.getFullYear(),c.getMonth(),c.getDate()]}function jb(a){var b,c,d,e,f=[];if(!a._d){for(d=ib(a),a._w&&null==a._a[ge]&&null==a._a[fe]&&kb(a),null!=a._dayOfYear&&(e=hb(a._a[ee],d[ee]),(a._dayOfYear>pa(e)||0===a._dayOfYear)&&(n(a)._overflowDayOfYear=!0),c=ta(e,0,a._dayOfYear),a._a[fe]=c.getUTCMonth(),a._a[ge]=c.getUTCDate()),b=0;b<3&&null==a._a[b];++b)a._a[b]=f[b]=d[b];for(;b<7;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];24===a._a[he]&&0===a._a[ie]&&0===a._a[je]&&0===a._a[ke]&&(a._nextDay=!0,a._a[he]=0),a._d=(a._useUTC?ta:sa).apply(null,f),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[he]=24)}}function kb(a){var b,c,d,e,f,g,h,i;if(b=a._w,null!=b.GG||null!=b.W||null!=b.E)f=1,g=4,c=hb(b.GG,a._a[ee],wa(tb(),1,4).year),d=hb(b.W,1),e=hb(b.E,1),(e<1||e>7)&&(i=!0);else{f=a._locale._week.dow,g=a._locale._week.doy;var j=wa(tb(),f,g);c=hb(b.gg,a._a[ee],j.year),d=hb(b.w,j.week),null!=b.d?(e=b.d,(e<0||e>6)&&(i=!0)):null!=b.e?(e=b.e+f,(b.e<0||b.e>6)&&(i=!0)):e=f}d<1||d>xa(c,f,g)?n(a)._overflowWeeks=!0:null!=i?n(a)._overflowWeekday=!0:(h=va(c,d,e,f,g),a._a[ee]=h.year,a._dayOfYear=h.dayOfYear)}function lb(b){if(b._f===a.ISO_8601)return void eb(b);if(b._f===a.RFC_2822)return void fb(b);b._a=[],n(b).empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=Y(b._f,b._locale).match(Jd)||[],c=0;c0&&n(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),Md[f]?(d?n(b).empty=!1:n(b).unusedTokens.push(f),da(f,d,b)):b._strict&&!d&&n(b).unusedTokens.push(f);n(b).charsLeftOver=i-j,h.length>0&&n(b).unusedInput.push(h),b._a[he]<=12&&n(b).bigHour===!0&&b._a[he]>0&&(n(b).bigHour=void 0),n(b).parsedDateParts=b._a.slice(0),n(b).meridiem=b._meridiem,b._a[he]=mb(b._locale,b._a[he],b._meridiem),jb(b),db(b)}function mb(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&b<12&&(b+=12),d||12!==b||(b=0),b):b}function nb(a){var b,c,d,e,f;if(0===a._f.length)return n(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;ethis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ob(){if(!f(this._isDSTShifted))return this._isDSTShifted;var a={};if(q(a,this),a=qb(a),a._a){var b=a._isUTC?l(a._a):tb(a._a);this._isDSTShifted=this.isValid()&&v(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Pb(){return!!this.isValid()&&!this._isUTC}function Qb(){return!!this.isValid()&&this._isUTC}function Rb(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function Sb(a,b){var c,d,e,f=a,h=null;return Bb(a)?f={ms:a._milliseconds,d:a._days,M:a._months}:g(a)?(f={},b?f[b]=a:f.milliseconds=a):(h=Te.exec(a))?(c="-"===h[1]?-1:1,f={y:0,d:u(h[ge])*c,h:u(h[he])*c,m:u(h[ie])*c,s:u(h[je])*c,ms:u(Cb(1e3*h[ke]))*c}):(h=Ue.exec(a))?(c="-"===h[1]?-1:1,f={y:Tb(h[2],c),M:Tb(h[3],c),w:Tb(h[4],c),d:Tb(h[5],c),h:Tb(h[6],c),m:Tb(h[7],c),s:Tb(h[8],c)}):null==f?f={}:"object"==typeof f&&("from"in f||"to"in f)&&(e=Vb(tb(f.from),tb(f.to)),f={},f.ms=e.milliseconds,f.M=e.months),d=new Ab(f),Bb(a)&&j(a,"_locale")&&(d._locale=a._locale),d}function Tb(a,b){var c=a&&parseFloat(a.replace(",","."));return(isNaN(c)?0:c)*b}function Ub(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Vb(a,b){var c;return a.isValid()&&b.isValid()?(b=Fb(b,a),a.isBefore(b)?c=Ub(a,b):(c=Ub(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}}function Wb(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||(y(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Sb(c,d),Xb(this,e,a),this}}function Xb(b,c,d,e){var f=c._milliseconds,g=Cb(c._days),h=Cb(c._months);b.isValid()&&(e=null==e||e,f&&b._d.setTime(b._d.valueOf()+f*d),g&&Q(b,"Date",P(b,"Date")+g*d),h&&ja(b,P(b,"Month")+h*d),e&&a.updateOffset(b,g||h))}function Yb(a,b){var c=a.diff(b,"days",!0);return c<-6?"sameElse":c<-1?"lastWeek":c<0?"lastDay":c<1?"sameDay":c<2?"nextDay":c<7?"nextWeek":"sameElse"}function Zb(b,c){var d=b||tb(),e=Fb(d,this).startOf("day"),f=a.calendarFormat(this,e)||"sameElse",g=c&&(z(c[f])?c[f].call(this,d):c[f]);return this.format(g||this.localeData().calendar(f,this,tb(d)))}function $b(){return new r(this)}function _b(a,b){var c=s(a)?a:tb(a);return!(!this.isValid()||!c.isValid())&&(b=K(f(b)?"millisecond":b),"millisecond"===b?this.valueOf()>c.valueOf():c.valueOf()9999?X(a,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):z(Date.prototype.toISOString)?this.toDate().toISOString():X(a,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}function jc(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var a="moment",b="";this.isLocal()||(a=0===this.utcOffset()?"moment.utc":"moment.parseZone",b="Z");var c="["+a+'("]',d=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",e="-MM-DD[T]HH:mm:ss.SSS",f=b+'[")]';return this.format(c+d+e+f)}function kc(b){b||(b=this.isUtc()?a.defaultFormatUtc:a.defaultFormat);var c=X(this,b);return this.localeData().postformat(c)}function lc(a,b){return this.isValid()&&(s(a)&&a.isValid()||tb(a).isValid())?Sb({to:this,from:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function mc(a){return this.from(tb(),a)}function nc(a,b){return this.isValid()&&(s(a)&&a.isValid()||tb(a).isValid())?Sb({from:this,to:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function oc(a){return this.to(tb(),a)}function pc(a){var b;return void 0===a?this._locale._abbr:(b=bb(a),null!=b&&(this._locale=b),this)}function qc(){return this._locale}function rc(a){switch(a=K(a)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":case"date":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===a&&this.weekday(0),"isoWeek"===a&&this.isoWeekday(1),"quarter"===a&&this.month(3*Math.floor(this.month()/3)),this}function sc(a){return a=K(a),void 0===a||"millisecond"===a?this:("date"===a&&(a="day"),this.startOf(a).add(1,"isoWeek"===a?"week":a).subtract(1,"ms"))}function tc(){return this._d.valueOf()-6e4*(this._offset||0)}function uc(){return Math.floor(this.valueOf()/1e3)}function vc(){return new Date(this.valueOf())}function wc(){var a=this;return[a.year(),a.month(),a.date(),a.hour(),a.minute(),a.second(),a.millisecond()]}function xc(){var a=this;return{years:a.year(),months:a.month(),date:a.date(),hours:a.hours(),minutes:a.minutes(),seconds:a.seconds(),milliseconds:a.milliseconds()}}function yc(){return this.isValid()?this.toISOString():null}function zc(){return o(this)}function Ac(){ 7 | return k({},n(this))}function Bc(){return n(this).overflow}function Cc(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function Dc(a,b){U(0,[a,a.length],0,b)}function Ec(a){return Ic.call(this,a,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function Fc(a){return Ic.call(this,a,this.isoWeek(),this.isoWeekday(),1,4)}function Gc(){return xa(this.year(),1,4)}function Hc(){var a=this.localeData()._week;return xa(this.year(),a.dow,a.doy)}function Ic(a,b,c,d,e){var f;return null==a?wa(this,d,e).year:(f=xa(a,d,e),b>f&&(b=f),Jc.call(this,a,b,c,d,e))}function Jc(a,b,c,d,e){var f=va(a,b,c,d,e),g=ta(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this}function Kc(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}function Lc(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function Mc(a,b){b[ke]=u(1e3*("0."+a))}function Nc(){return this._isUTC?"UTC":""}function Oc(){return this._isUTC?"Coordinated Universal Time":""}function Pc(a){return tb(1e3*a)}function Qc(){return tb.apply(null,arguments).parseZone()}function Rc(a){return a}function Sc(a,b,c,d){var e=bb(),f=l().set(d,b);return e[c](f,a)}function Tc(a,b,c){if(g(a)&&(b=a,a=void 0),a=a||"",null!=b)return Sc(a,b,c,"month");var d,e=[];for(d=0;d<12;d++)e[d]=Sc(a,d,c,"month");return e}function Uc(a,b,c,d){"boolean"==typeof a?(g(b)&&(c=b,b=void 0),b=b||""):(b=a,c=b,a=!1,g(b)&&(c=b,b=void 0),b=b||"");var e=bb(),f=a?e._week.dow:0;if(null!=c)return Sc(b,(c+f)%7,d,"day");var h,i=[];for(h=0;h<7;h++)i[h]=Sc(b,(h+f)%7,d,"day");return i}function Vc(a,b){return Tc(a,b,"months")}function Wc(a,b){return Tc(a,b,"monthsShort")}function Xc(a,b,c){return Uc(a,b,c,"weekdays")}function Yc(a,b,c){return Uc(a,b,c,"weekdaysShort")}function Zc(a,b,c){return Uc(a,b,c,"weekdaysMin")}function $c(){var a=this._data;return this._milliseconds=df(this._milliseconds),this._days=df(this._days),this._months=df(this._months),a.milliseconds=df(a.milliseconds),a.seconds=df(a.seconds),a.minutes=df(a.minutes),a.hours=df(a.hours),a.months=df(a.months),a.years=df(a.years),this}function _c(a,b,c,d){var e=Sb(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}function ad(a,b){return _c(this,a,b,1)}function bd(a,b){return _c(this,a,b,-1)}function cd(a){return a<0?Math.floor(a):Math.ceil(a)}function dd(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;return f>=0&&g>=0&&h>=0||f<=0&&g<=0&&h<=0||(f+=864e5*cd(fd(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=t(f/1e3),i.seconds=a%60,b=t(a/60),i.minutes=b%60,c=t(b/60),i.hours=c%24,g+=t(c/24),e=t(ed(g)),h+=e,g-=cd(fd(e)),d=t(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function ed(a){return 4800*a/146097}function fd(a){return 146097*a/4800}function gd(a){if(!this.isValid())return NaN;var b,c,d=this._milliseconds;if(a=K(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+ed(b),"month"===a?c:c/12;switch(b=this._days+Math.round(fd(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}function hd(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*u(this._months/12):NaN}function id(a){return function(){return this.as(a)}}function jd(a){return a=K(a),this.isValid()?this[a+"s"]():NaN}function kd(a){return function(){return this.isValid()?this._data[a]:NaN}}function ld(){return t(this.days()/7)}function md(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function nd(a,b,c){var d=Sb(a).abs(),e=uf(d.as("s")),f=uf(d.as("m")),g=uf(d.as("h")),h=uf(d.as("d")),i=uf(d.as("M")),j=uf(d.as("y")),k=e<=vf.ss&&["s",e]||e0,k[4]=c,md.apply(null,k)}function od(a){return void 0===a?uf:"function"==typeof a&&(uf=a,!0)}function pd(a,b){return void 0!==vf[a]&&(void 0===b?vf[a]:(vf[a]=b,"s"===a&&(vf.ss=b-1),!0))}function qd(a){if(!this.isValid())return this.localeData().invalidDate();var b=this.localeData(),c=nd(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function rd(){if(!this.isValid())return this.localeData().invalidDate();var a,b,c,d=wf(this._milliseconds)/1e3,e=wf(this._days),f=wf(this._months);a=t(d/60),b=t(a/60),d%=60,a%=60,c=t(f/12),f%=12;var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(m<0?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var sd,td;td=Array.prototype.some?Array.prototype.some:function(a){for(var b=Object(this),c=b.length>>>0,d=0;d68?1900:2e3)};var te=O("FullYear",!0);U("w",["ww",2],"wo","week"),U("W",["WW",2],"Wo","isoWeek"),J("week","w"),J("isoWeek","W"),M("week",5),M("isoWeek",5),Z("w",Sd),Z("ww",Sd,Od),Z("W",Sd),Z("WW",Sd,Od),ca(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=u(a)});var ue={dow:0,doy:6};U("d",0,"do","day"),U("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),U("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),U("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),U("e",0,0,"weekday"),U("E",0,0,"isoWeekday"),J("day","d"),J("weekday","e"),J("isoWeekday","E"),M("day",11),M("weekday",11),M("isoWeekday",11),Z("d",Sd),Z("e",Sd),Z("E",Sd),Z("dd",function(a,b){return b.weekdaysMinRegex(a)}),Z("ddd",function(a,b){return b.weekdaysShortRegex(a)}),Z("dddd",function(a,b){return b.weekdaysRegex(a)}),ca(["dd","ddd","dddd"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict);null!=e?b.d=e:n(c).invalidWeekday=a}),ca(["d","e","E"],function(a,b,c,d){b[d]=u(a)});var ve="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),we="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),xe="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),ye=be,ze=be,Ae=be;U("H",["HH",2],0,"hour"),U("h",["hh",2],0,Ra),U("k",["kk",2],0,Sa),U("hmm",0,0,function(){return""+Ra.apply(this)+T(this.minutes(),2)}),U("hmmss",0,0,function(){return""+Ra.apply(this)+T(this.minutes(),2)+T(this.seconds(),2)}),U("Hmm",0,0,function(){return""+this.hours()+T(this.minutes(),2)}),U("Hmmss",0,0,function(){return""+this.hours()+T(this.minutes(),2)+T(this.seconds(),2)}),Ta("a",!0),Ta("A",!1),J("hour","h"),M("hour",13),Z("a",Ua),Z("A",Ua),Z("H",Sd),Z("h",Sd),Z("k",Sd),Z("HH",Sd,Od),Z("hh",Sd,Od),Z("kk",Sd,Od),Z("hmm",Td),Z("hmmss",Ud),Z("Hmm",Td),Z("Hmmss",Ud),ba(["H","HH"],he),ba(["k","kk"],function(a,b,c){var d=u(a);b[he]=24===d?0:d}),ba(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),ba(["h","hh"],function(a,b,c){b[he]=u(a),n(c).bigHour=!0}),ba("hmm",function(a,b,c){var d=a.length-2;b[he]=u(a.substr(0,d)),b[ie]=u(a.substr(d)),n(c).bigHour=!0}),ba("hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[he]=u(a.substr(0,d)),b[ie]=u(a.substr(d,2)),b[je]=u(a.substr(e)),n(c).bigHour=!0}),ba("Hmm",function(a,b,c){var d=a.length-2;b[he]=u(a.substr(0,d)),b[ie]=u(a.substr(d))}),ba("Hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[he]=u(a.substr(0,d)),b[ie]=u(a.substr(d,2)),b[je]=u(a.substr(e))});var Be,Ce=/[ap]\.?m?\.?/i,De=O("Hours",!0),Ee={calendar:Bd,longDateFormat:Cd,invalidDate:Dd,ordinal:Ed,dayOfMonthOrdinalParse:Fd,relativeTime:Gd,months:pe,monthsShort:qe,week:ue,weekdays:ve,weekdaysMin:xe,weekdaysShort:we,meridiemParse:Ce},Fe={},Ge={},He=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Ie=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Je=/Z|[+-]\d\d(?::?\d\d)?/,Ke=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Le=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Me=/^\/?Date\((\-?\d+)/i,Ne=/^((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d?\d\s(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(?:\d\d)?\d\d\s)(\d\d:\d\d)(\:\d\d)?(\s(?:UT|GMT|[ECMP][SD]T|[A-IK-Za-ik-z]|[+-]\d{4}))$/;a.createFromInputFallback=x("value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),a.ISO_8601=function(){},a.RFC_2822=function(){};var Oe=x("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var a=tb.apply(null,arguments);return this.isValid()&&a.isValid()?athis?this:a:p()}),Qe=function(){return Date.now?Date.now():+new Date},Re=["year","quarter","month","week","day","hour","minute","second","millisecond"];Db("Z",":"),Db("ZZ",""),Z("Z",_d),Z("ZZ",_d),ba(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Eb(_d,a)});var Se=/([\+\-]|\d\d)/gi;a.updateOffset=function(){};var Te=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Ue=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Sb.fn=Ab.prototype,Sb.invalid=zb;var Ve=Wb(1,"add"),We=Wb(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",a.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Xe=x("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});U(0,["gg",2],0,function(){return this.weekYear()%100}),U(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Dc("gggg","weekYear"),Dc("ggggg","weekYear"),Dc("GGGG","isoWeekYear"),Dc("GGGGG","isoWeekYear"),J("weekYear","gg"),J("isoWeekYear","GG"),M("weekYear",1),M("isoWeekYear",1),Z("G",Zd),Z("g",Zd),Z("GG",Sd,Od),Z("gg",Sd,Od),Z("GGGG",Wd,Qd),Z("gggg",Wd,Qd),Z("GGGGG",Xd,Rd),Z("ggggg",Xd,Rd),ca(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=u(a)}),ca(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),U("Q",0,"Qo","quarter"),J("quarter","Q"),M("quarter",7),Z("Q",Nd),ba("Q",function(a,b){b[fe]=3*(u(a)-1)}),U("D",["DD",2],"Do","date"),J("date","D"),M("date",9),Z("D",Sd),Z("DD",Sd,Od),Z("Do",function(a,b){return a?b._dayOfMonthOrdinalParse||b._ordinalParse:b._dayOfMonthOrdinalParseLenient}),ba(["D","DD"],ge),ba("Do",function(a,b){b[ge]=u(a.match(Sd)[0],10)});var Ye=O("Date",!0);U("DDD",["DDDD",3],"DDDo","dayOfYear"),J("dayOfYear","DDD"),M("dayOfYear",4),Z("DDD",Vd),Z("DDDD",Pd),ba(["DDD","DDDD"],function(a,b,c){c._dayOfYear=u(a)}),U("m",["mm",2],0,"minute"),J("minute","m"),M("minute",14),Z("m",Sd),Z("mm",Sd,Od),ba(["m","mm"],ie);var Ze=O("Minutes",!1);U("s",["ss",2],0,"second"),J("second","s"),M("second",15),Z("s",Sd),Z("ss",Sd,Od),ba(["s","ss"],je);var $e=O("Seconds",!1);U("S",0,0,function(){return~~(this.millisecond()/100)}),U(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),U(0,["SSS",3],0,"millisecond"),U(0,["SSSS",4],0,function(){return 10*this.millisecond()}),U(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),U(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),U(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),U(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),U(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),J("millisecond","ms"),M("millisecond",16),Z("S",Vd,Nd),Z("SS",Vd,Od),Z("SSS",Vd,Pd);var _e;for(_e="SSSS";_e.length<=9;_e+="S")Z(_e,Yd);for(_e="S";_e.length<=9;_e+="S")ba(_e,Mc);var af=O("Milliseconds",!1);U("z",0,0,"zoneAbbr"),U("zz",0,0,"zoneName");var bf=r.prototype;bf.add=Ve,bf.calendar=Zb,bf.clone=$b,bf.diff=fc,bf.endOf=sc,bf.format=kc,bf.from=lc,bf.fromNow=mc,bf.to=nc,bf.toNow=oc,bf.get=R,bf.invalidAt=Bc,bf.isAfter=_b,bf.isBefore=ac,bf.isBetween=bc,bf.isSame=cc,bf.isSameOrAfter=dc,bf.isSameOrBefore=ec,bf.isValid=zc,bf.lang=Xe,bf.locale=pc,bf.localeData=qc,bf.max=Pe,bf.min=Oe,bf.parsingFlags=Ac,bf.set=S,bf.startOf=rc,bf.subtract=We,bf.toArray=wc,bf.toObject=xc,bf.toDate=vc,bf.toISOString=ic,bf.inspect=jc,bf.toJSON=yc,bf.toString=hc,bf.unix=uc,bf.valueOf=tc,bf.creationData=Cc,bf.year=te,bf.isLeapYear=ra,bf.weekYear=Ec,bf.isoWeekYear=Fc,bf.quarter=bf.quarters=Kc,bf.month=ka,bf.daysInMonth=la,bf.week=bf.weeks=Ba,bf.isoWeek=bf.isoWeeks=Ca,bf.weeksInYear=Hc,bf.isoWeeksInYear=Gc,bf.date=Ye,bf.day=bf.days=Ka,bf.weekday=La,bf.isoWeekday=Ma,bf.dayOfYear=Lc,bf.hour=bf.hours=De,bf.minute=bf.minutes=Ze,bf.second=bf.seconds=$e,bf.millisecond=bf.milliseconds=af,bf.utcOffset=Hb,bf.utc=Jb,bf.local=Kb,bf.parseZone=Lb,bf.hasAlignedHourOffset=Mb,bf.isDST=Nb,bf.isLocal=Pb,bf.isUtcOffset=Qb,bf.isUtc=Rb,bf.isUTC=Rb,bf.zoneAbbr=Nc,bf.zoneName=Oc,bf.dates=x("dates accessor is deprecated. Use date instead.",Ye),bf.months=x("months accessor is deprecated. Use month instead",ka),bf.years=x("years accessor is deprecated. Use year instead",te),bf.zone=x("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Ib),bf.isDSTShifted=x("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Ob);var cf=C.prototype;cf.calendar=D,cf.longDateFormat=E,cf.invalidDate=F,cf.ordinal=G,cf.preparse=Rc,cf.postformat=Rc,cf.relativeTime=H,cf.pastFuture=I,cf.set=A,cf.months=fa,cf.monthsShort=ga,cf.monthsParse=ia,cf.monthsRegex=na,cf.monthsShortRegex=ma,cf.week=ya,cf.firstDayOfYear=Aa,cf.firstDayOfWeek=za,cf.weekdays=Fa,cf.weekdaysMin=Ha,cf.weekdaysShort=Ga,cf.weekdaysParse=Ja,cf.weekdaysRegex=Na,cf.weekdaysShortRegex=Oa,cf.weekdaysMinRegex=Pa,cf.isPM=Va,cf.meridiem=Wa,$a("en",{dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===u(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),a.lang=x("moment.lang is deprecated. Use moment.locale instead.",$a),a.langData=x("moment.langData is deprecated. Use moment.localeData instead.",bb);var df=Math.abs,ef=id("ms"),ff=id("s"),gf=id("m"),hf=id("h"),jf=id("d"),kf=id("w"),lf=id("M"),mf=id("y"),nf=kd("milliseconds"),of=kd("seconds"),pf=kd("minutes"),qf=kd("hours"),rf=kd("days"),sf=kd("months"),tf=kd("years"),uf=Math.round,vf={ss:44,s:45,m:45,h:22,d:26,M:11},wf=Math.abs,xf=Ab.prototype;return xf.isValid=yb,xf.abs=$c,xf.add=ad,xf.subtract=bd,xf.as=gd,xf.asMilliseconds=ef,xf.asSeconds=ff,xf.asMinutes=gf,xf.asHours=hf,xf.asDays=jf,xf.asWeeks=kf,xf.asMonths=lf,xf.asYears=mf,xf.valueOf=hd,xf._bubble=dd,xf.get=jd,xf.milliseconds=nf,xf.seconds=of,xf.minutes=pf,xf.hours=qf,xf.days=rf,xf.weeks=ld,xf.months=sf,xf.years=tf,xf.humanize=qd,xf.toISOString=rd,xf.toString=rd,xf.toJSON=rd,xf.locale=pc,xf.localeData=qc,xf.toIsoString=x("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",rd),xf.lang=Xe,U("X",0,0,"unix"),U("x",0,0,"valueOf"),Z("x",Zd),Z("X",ae),ba("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),ba("x",function(a,b,c){c._d=new Date(u(a))}),a.version="2.18.1",b(tb),a.fn=bf,a.min=vb,a.max=wb,a.now=Qe,a.utc=l,a.unix=Pc,a.months=Vc,a.isDate=h,a.locale=$a,a.invalid=p,a.duration=Sb,a.isMoment=s,a.weekdays=Xc,a.parseZone=Qc,a.localeData=bb,a.isDuration=Bb,a.monthsShort=Wc,a.weekdaysMin=Zc,a.defineLocale=_a,a.updateLocale=ab,a.locales=cb,a.weekdaysShort=Yc,a.normalizeUnits=K,a.relativeTimeRounding=od,a.relativeTimeThreshold=pd,a.calendarFormat=Yb,a.prototype=bf,a}); -------------------------------------------------------------------------------- /docs/react.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * React v15.6.1 3 | * 4 | * Copyright 2013-present, Facebook, Inc. 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. An additional grant 9 | * of patent rights can be found in the PATENTS file in the same directory. 10 | * 11 | */ 12 | !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.React=t()}}(function(){return function t(e,n,r){function o(a,u){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!u&&s)return s(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n||t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;a1){for(var y=Array(d),h=0;h1){for(var v=Array(m),b=0;b uint) public dailyTotals; 25 | mapping (uint => mapping (address => uint)) public userBuys; 26 | mapping (uint => mapping (address => bool)) public claimed; 27 | mapping (address => string) public keys; 28 | 29 | event LogBuy (uint window, address user, uint amount); 30 | event LogClaim (uint window, address user, uint amount); 31 | event LogRegister (address user, string key); 32 | event LogCollect (uint amount); 33 | event LogFreeze (); 34 | 35 | function EOSSale( 36 | uint _numberOfDays, 37 | uint128 _totalSupply, 38 | uint _openTime, 39 | uint _startTime, 40 | uint128 _foundersAllocation, 41 | string _foundersKey 42 | ) { 43 | numberOfDays = _numberOfDays; 44 | totalSupply = _totalSupply; 45 | openTime = _openTime; 46 | startTime = _startTime; 47 | foundersAllocation = _foundersAllocation; 48 | foundersKey = _foundersKey; 49 | 50 | createFirstDay = wmul(totalSupply, 0.2 ether); 51 | createPerDay = div( 52 | sub(sub(totalSupply, foundersAllocation), createFirstDay), 53 | numberOfDays 54 | ); 55 | 56 | assert(numberOfDays > 0); 57 | assert(totalSupply > foundersAllocation); 58 | assert(openTime < startTime); 59 | } 60 | 61 | function initialize(DSToken eos) auth { 62 | assert(address(EOS) == address(0)); 63 | assert(eos.owner() == address(this)); 64 | assert(eos.authority() == DSAuthority(0)); 65 | assert(eos.totalSupply() == 0); 66 | 67 | EOS = eos; 68 | EOS.mint(totalSupply); 69 | 70 | // Address 0xb1 is provably non-transferrable 71 | EOS.push(0xb1, foundersAllocation); 72 | keys[0xb1] = foundersKey; 73 | LogRegister(0xb1, foundersKey); 74 | } 75 | 76 | function time() constant returns (uint) { 77 | return block.timestamp; 78 | } 79 | 80 | function today() constant returns (uint) { 81 | return dayFor(time()); 82 | } 83 | 84 | // Each window is 23 hours long so that end-of-window rotates 85 | // around the clock for all timezones. 86 | function dayFor(uint timestamp) constant returns (uint) { 87 | return timestamp < startTime 88 | ? 0 89 | : sub(timestamp, startTime) / 23 hours + 1; 90 | } 91 | 92 | function createOnDay(uint day) constant returns (uint) { 93 | return day == 0 ? createFirstDay : createPerDay; 94 | } 95 | 96 | // This method provides the buyer some protections regarding which 97 | // day the buy order is submitted and the maximum price prior to 98 | // applying this payment that will be allowed. 99 | function buyWithLimit(uint day, uint limit) payable { 100 | assert(time() >= openTime && today() <= numberOfDays); 101 | assert(msg.value >= 0.01 ether); 102 | 103 | assert(day >= today()); 104 | assert(day <= numberOfDays); 105 | 106 | userBuys[day][msg.sender] += msg.value; 107 | dailyTotals[day] += msg.value; 108 | 109 | if (limit != 0) { 110 | assert(dailyTotals[day] <= limit); 111 | } 112 | 113 | LogBuy(day, msg.sender, msg.value); 114 | } 115 | 116 | function buy() payable { 117 | buyWithLimit(today(), 0); 118 | } 119 | 120 | function () payable { 121 | buy(); 122 | } 123 | 124 | function claim(uint day) { 125 | assert(today() > day); 126 | 127 | if (claimed[day][msg.sender] || dailyTotals[day] == 0) { 128 | return; 129 | } 130 | 131 | // This will have small rounding errors, but the token is 132 | // going to be truncated to 8 decimal places or less anyway 133 | // when launched on its own chain. 134 | 135 | var dailyTotal = cast(dailyTotals[day]); 136 | var userTotal = cast(userBuys[day][msg.sender]); 137 | var price = wdiv(cast(createOnDay(day)), dailyTotal); 138 | var reward = wmul(price, userTotal); 139 | 140 | claimed[day][msg.sender] = true; 141 | EOS.push(msg.sender, reward); 142 | 143 | LogClaim(day, msg.sender, reward); 144 | } 145 | 146 | function claimAll() { 147 | for (uint i = 0; i < today(); i++) { 148 | claim(i); 149 | } 150 | } 151 | 152 | // Value should be a public key. Read full key import policy. 153 | // Manually registering requires a base58 154 | // encoded using the STEEM, BTS, or EOS public key format. 155 | function register(string key) { 156 | assert(today() <= numberOfDays + 1); 157 | assert(bytes(key).length <= 64); 158 | 159 | keys[msg.sender] = key; 160 | 161 | LogRegister(msg.sender, key); 162 | } 163 | 164 | // Crowdsale owners can collect ETH any number of times 165 | function collect() auth { 166 | assert(today() > 0); // Prevent recycling during window 0 167 | exec(msg.sender, this.balance); 168 | LogCollect(this.balance); 169 | } 170 | 171 | // Anyone can freeze the token 1 day after the sale ends 172 | function freeze() { 173 | assert(today() > numberOfDays + 1); 174 | EOS.stop(); 175 | LogFreeze(); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/eos_sale.t.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import "ds-exec/exec.sol"; 4 | import "ds-test/test.sol"; 5 | 6 | import "ds-guard/guard.sol"; 7 | 8 | import "gnosis-multisig/MultiSigWallet.sol"; 9 | 10 | import "./eos_sale.sol"; 11 | 12 | contract TestUser is DSExec { 13 | TestableEOSSale sale; 14 | 15 | function TestUser(TestableEOSSale sale_) { 16 | sale = sale_; 17 | } 18 | 19 | function() payable {} 20 | 21 | function doBuy(uint wad) { 22 | sale.buy.value(wad)(); 23 | } 24 | 25 | function doBuyWithLimit(uint wad, uint window, uint limit) { 26 | sale.buyWithLimit.value(wad)(window, limit); 27 | } 28 | 29 | function doClaim(uint window) { 30 | sale.claim(window); 31 | } 32 | 33 | function doFreeze() { 34 | sale.freeze(); 35 | } 36 | 37 | function doExec(uint wad) { 38 | exec(sale, wad); 39 | } 40 | } 41 | 42 | contract TestOwner { 43 | TestableEOSSale sale; 44 | 45 | function TestOwner(TestableEOSSale sale_) { 46 | sale = sale_; 47 | } 48 | 49 | function() payable {} 50 | 51 | function doCollect() { 52 | sale.collect(); 53 | } 54 | } 55 | 56 | contract TestableEOSSale is EOSSale { 57 | function TestableEOSSale( 58 | uint n, uint128 t, uint o, uint s, uint128 a, string k 59 | ) EOSSale(n, t, o, s, a, k) {} 60 | 61 | uint public localTime; 62 | 63 | function time() constant returns (uint) { 64 | return localTime; 65 | } 66 | 67 | function addTime(uint extra) { 68 | localTime += extra; 69 | } 70 | } 71 | 72 | contract EOSSaleTest is DSTest, DSExec { 73 | TestableEOSSale sale; 74 | DSToken EOS; 75 | DSGuard guard; 76 | TestUser user1; 77 | TestUser user2; 78 | TestOwner owner; 79 | uint window; 80 | 81 | function setUp() { 82 | string memory x = new string(1); 83 | 84 | EOS = new DSToken("EOS"); 85 | window = 0; 86 | 87 | sale = new TestableEOSSale( 88 | 5, 156.25 ether, now, block.timestamp + 1 days, 10 ether, x 89 | ); 90 | 91 | EOS.setOwner(sale); 92 | sale.initialize(EOS); 93 | 94 | sale.addTime(now + 1); 95 | 96 | user1 = new TestUser(sale); 97 | user2 = new TestUser(sale); 98 | owner = new TestOwner(sale); 99 | 100 | user1.transfer(100 ether); 101 | user2.transfer(100 ether); 102 | 103 | guard = new DSGuard(); 104 | guard.okay(owner, sale); 105 | 106 | sale.setAuthority(guard); 107 | } 108 | 109 | function addTime() { 110 | sale.addTime(1 days); 111 | } 112 | 113 | function nextRound(uint wad, uint wad1, uint wad2) { 114 | if (wad != 0) sale.buy.value(wad)(); 115 | if (wad1 != 0) user1.doBuy(wad1); 116 | if (wad2 != 0) user2.doBuy(wad2); 117 | 118 | addTime(); 119 | 120 | sale.claim(window); 121 | user1.doClaim(window); 122 | user2.doClaim(window); 123 | 124 | window++; 125 | } 126 | 127 | function testFailBuyBeforeOpen() { 128 | string memory x = new string(1); 129 | sale = new TestableEOSSale( 130 | 5, 156.25 ether, now + 1, block.timestamp + 1 days, 10 ether, x 131 | ); 132 | sale.addTime(now); 133 | sale.buy.value(1 ether)(); 134 | } 135 | 136 | function testBuy() { 137 | sale.buy.value(1 ether)(); 138 | } 139 | 140 | function testBuyWithLimit() { 141 | sale.buyWithLimit.value(1 ether)(0, 2 ether); 142 | assertEq(sale.userBuys(0, address(this)), 1 ether); 143 | } 144 | 145 | function testFailBuyOverLimit() { 146 | user1.doBuy(1 ether); 147 | sale.buyWithLimit.value(1 ether)(0, 1.5 ether); 148 | } 149 | 150 | function testBuyOverLimitLaterWindow() { 151 | user1.doBuy(1 ether); 152 | sale.buyWithLimit.value(1 ether)(3, 1.5 ether); 153 | } 154 | 155 | function testBuyLaterWindow() { 156 | sale.buyWithLimit.value(1 ether)(3, 2 ether); 157 | assertEq(sale.userBuys(0, address(this)), 0); 158 | assertEq(sale.userBuys(2, address(this)), 0); 159 | assertEq(sale.userBuys(3, address(this)), 1 ether); 160 | assertEq(sale.userBuys(4, address(this)), 0); 161 | } 162 | 163 | function testFailBuyTooLate() { 164 | addTime(); 165 | sale.buyWithLimit.value(1 ether)(0, 0); 166 | } 167 | 168 | function testBuyFirstDay() { 169 | sale.buy.value(1 ether)(); 170 | sale.addTime(1 days); 171 | sale.claim(0); 172 | assertEq(EOS.balanceOf(this), 31.25 ether); 173 | } 174 | 175 | function testBuyFirstAndSecondDay() { 176 | sale.buy.value(1 ether)(); 177 | sale.addTime(1 days); 178 | sale.claim(0); 179 | assertEq(EOS.balanceOf(this), 31.25 ether); 180 | 181 | sale.buy.value(1 ether)(); 182 | sale.addTime(1 days); 183 | sale.claim(1); 184 | // 23 tokens issued per day after first day 185 | assertEq(EOS.balanceOf(this), 54.25 ether); 186 | } 187 | 188 | function testFailSaleOver() { 189 | sale.addTime(6 days); 190 | sale.buy.value(1 ether)(); 191 | } 192 | 193 | function testFailSmallBuy() { 194 | nextRound(1 finney, 0, 0); 195 | } 196 | 197 | function testLargeBuy() { 198 | nextRound(1001 ether, 0, 0); 199 | } 200 | 201 | function testAllDistributed() { 202 | nextRound(1 ether, 0, 0); 203 | nextRound(1 ether, 0, 0); 204 | nextRound(1 ether, 0, 0); 205 | nextRound(1 ether, 0, 0); 206 | nextRound(1 ether, 0, 0); 207 | nextRound(1 ether, 0, 0); 208 | 209 | assertEq(EOS.balanceOf(this), 146.25 ether); 210 | } 211 | 212 | function testClaim() { 213 | nextRound(1 ether, 0, 0); 214 | assertEq(EOS.balanceOf(this), 31.25 ether); 215 | } 216 | 217 | function testClaimZeroContribution() { 218 | nextRound(0, 0, 0); 219 | } 220 | 221 | function testFailEarlyClaim() { 222 | sale.claim(2); 223 | } 224 | 225 | function testFailEarlyFreeze() { 226 | nextRound(1 ether, 0, 0); 227 | nextRound(1 ether, 0, 0); 228 | 229 | // try release at the start of the third round 230 | user1.doFreeze(); 231 | } 232 | 233 | function testMultiUser() { 234 | nextRound(1 ether, 1 ether, 0); 235 | assertEq(EOS.balanceOf(this), 15.625 ether); 236 | assertEq(EOS.balanceOf(user1), 15.625 ether); 237 | } 238 | 239 | function testMultiUserAsymmetricBid() { 240 | nextRound(1 ether, 9 ether, 0); 241 | assertEq(EOS.balanceOf(this), 3.125 ether); 242 | assertEq(EOS.balanceOf(user1), 28.125 ether); 243 | } 244 | 245 | // is this an issue? 246 | function testRepeatingDecimalRoundUp() { 247 | nextRound(1 ether, 1 ether, 1 ether); 248 | assertEq(EOS.balanceOf(this), 10416666666666666667); 249 | assertEq(EOS.balanceOf(user1), 10416666666666666667); 250 | assertEq(EOS.balanceOf(user2), 10416666666666666667); 251 | } 252 | 253 | function testRepeatingDecimalRoundDown() { 254 | addTime(); 255 | window++; 256 | 257 | nextRound(5 ether, 1 ether, 0); 258 | assertEq(EOS.balanceOf(this), 19166666666666666665); 259 | assertEq(EOS.balanceOf(user1), 3833333333333333333); 260 | } 261 | 262 | function testFreeze() { 263 | nextRound(1 ether, 0, 0); 264 | nextRound(1 ether, 0, 0); 265 | nextRound(1 ether, 0, 0); 266 | nextRound(1 ether, 0, 0); 267 | nextRound(1 ether, 0, 0); 268 | nextRound(1 ether, 0, 0); 269 | assertEq(EOS.balanceOf(this), 146.25 ether); 270 | 271 | // one extra day to trade 272 | addTime(); 273 | 274 | user1.doFreeze(); 275 | } 276 | 277 | function testCollect() { 278 | nextRound(1 ether, 0, 0); 279 | nextRound(1 ether, 0, 0); 280 | nextRound(1 ether, 0, 0); 281 | nextRound(1 ether, 0, 0); 282 | nextRound(1 ether, 0, 0); 283 | nextRound(1 ether, 0, 0); 284 | assertEq(EOS.balanceOf(this), 146.25 ether); 285 | 286 | owner.doCollect(); 287 | assertEq(owner.balance, 6 ether); 288 | } 289 | 290 | function testMultiUserFinalize() { 291 | nextRound(1 ether, 1 ether, 0); 292 | nextRound(1 ether, 1 ether, 0); 293 | nextRound(1 ether, 1 ether, 0); 294 | nextRound(1 ether, 1 ether, 0); 295 | nextRound(1 ether, 1 ether, 0); 296 | nextRound(1 ether, 1 ether, 0); 297 | assertEq(EOS.balanceOf(this), 73.125 ether); 298 | assertEq(EOS.balanceOf(user1), 73.125 ether); 299 | addTime(); 300 | 301 | owner.doCollect(); 302 | assertEq(owner.balance, 12 ether); 303 | 304 | user1.doFreeze(); 305 | } 306 | 307 | function testMultiUserAsymmetricBidFinalize() { 308 | nextRound(9 ether, 1 ether, 0); 309 | nextRound(4 ether, 1 ether, 0); 310 | nextRound(1 ether, 9 ether, 10 ether); 311 | nextRound(1 ether, 12 ether, 12 ether); 312 | nextRound(12 ether, 1 ether, 12 ether); 313 | nextRound(12 ether, 12 ether, 1 ether); 314 | assertEq(EOS.balanceOf(this), 70.675 ether); 315 | assertEq(EOS.balanceOf(user1), 41.075 ether); 316 | assertEq(EOS.balanceOf(user2), 34.5 ether); 317 | addTime(); 318 | 319 | owner.doCollect(); 320 | assertEq(owner.balance, 110 ether); 321 | 322 | user1.doFreeze(); 323 | } 324 | 325 | function testClaimAfterFinalize() { 326 | sale.buy.value(1 ether)(); 327 | addTime(); 328 | addTime(); 329 | addTime(); 330 | addTime(); 331 | addTime(); 332 | 333 | owner.doCollect(); 334 | 335 | assertEq(EOS.balanceOf(this), 0); 336 | 337 | sale.claim(0); 338 | 339 | assertEq(EOS.balanceOf(this), 31.25 ether); 340 | } 341 | 342 | function testClaimAll() { 343 | sale.buy.value(1 ether)(); 344 | addTime(); 345 | sale.buy.value(1 ether)(); 346 | addTime(); 347 | sale.buy.value(1 ether)(); 348 | addTime(); 349 | 350 | assertEq(EOS.balanceOf(this), 0); 351 | 352 | sale.claimAll(); 353 | assertEq(EOS.balanceOf(this), 77.25 ether); 354 | } 355 | 356 | function testClaimAllZeroContribution() { 357 | sale.buy.value(1 ether)(); 358 | addTime(); 359 | addTime(); // skip a day 360 | sale.buy.value(1 ether)(); 361 | addTime(); 362 | sale.buy.value(1 ether)(); 363 | addTime(); 364 | 365 | assertEq(EOS.balanceOf(this), 0); 366 | 367 | sale.claimAll(); 368 | assertEq(EOS.balanceOf(this), 77.25 ether); 369 | } 370 | 371 | function testRegister() { 372 | string memory x = new string(56); 373 | string memory y = new string(56); 374 | 375 | sale.register(x); 376 | sale.register(y); 377 | } 378 | 379 | function testFailRegister() { 380 | string memory x = new string(100); 381 | sale.register(x); 382 | } 383 | } 384 | 385 | contract EOSSalePreInitTests is DSTest { 386 | TestableEOSSale sale; 387 | TestUser user1; 388 | 389 | function setUp() { 390 | string memory x = new string(1); 391 | 392 | sale = new TestableEOSSale( 393 | 5, 156.25 ether, now, block.timestamp + 1 days, 10 ether, x 394 | ); 395 | 396 | user1 = new TestUser(sale); 397 | user1.transfer(100 ether); 398 | sale.addTime(now + 1); 399 | } 400 | 401 | // Ensure that initialize fails if the token has other authorized callers 402 | function testFailTokenAuthority() { 403 | DSToken EOS = new DSToken("EOS"); 404 | EOS.setAuthority(new DSGuard()); 405 | EOS.setOwner(sale); 406 | sale.initialize(EOS); 407 | } 408 | } 409 | 410 | contract MultisigUser { 411 | 412 | MultiSigWallet multisig; 413 | 414 | function addMultisig(MultiSigWallet multisig_) { 415 | multisig = multisig_; 416 | } 417 | 418 | function doConfirm(uint id) { 419 | multisig.confirmTransaction(id); 420 | } 421 | } 422 | 423 | contract MultisigTests is DSTest { 424 | TestableEOSSale sale; 425 | MultisigUser user1; 426 | MultisigUser user2; 427 | MultiSigWallet multisig; 428 | 429 | function setUp() { 430 | string memory x = new string(1); 431 | 432 | sale = new TestableEOSSale( 433 | 5, 156.25 ether, now, block.timestamp + 1 days, 10 ether, x 434 | ); 435 | 436 | 437 | sale.addTime(now + 1); 438 | 439 | user1 = new MultisigUser(); 440 | user2 = new MultisigUser(); 441 | 442 | address[] memory members = new address[](3); 443 | members[0] = user1; 444 | members[1] = user2; 445 | members[2] = this; 446 | 447 | multisig = new MultiSigWallet(members, 2); 448 | 449 | user1.addMultisig(multisig); 450 | 451 | } 452 | 453 | // Ensure that initialize fails if the token has other authorized callers 454 | function testRegister() { 455 | bytes memory calldata = new bytes(4 + 32); 456 | bytes4 sig = bytes4(sha3("register(string)")); 457 | calldata[0] = sig[0]; 458 | calldata[1] = sig[1]; 459 | calldata[2] = sig[2]; 460 | calldata[3] = sig[3]; 461 | calldata[4 + 29] = byte("a"); 462 | calldata[4 + 30] = byte("b"); 463 | calldata[4 + 31] = byte("c"); 464 | 465 | uint id = multisig.submitTransaction(sale, 0, calldata); // submit and confirm 466 | user1.doConfirm(id); // confirm and execute 467 | } 468 | } 469 | -------------------------------------------------------------------------------- /src/eos_sale_util.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import "./eos_sale.sol"; 4 | 5 | contract EOSSaleUtil { 6 | EOSSale public sale; 7 | 8 | function EOSSaleUtil(EOSSale _sale) { 9 | sale = _sale; 10 | } 11 | 12 | function dailyTotals() constant returns (uint[351] result) { 13 | for (uint i = 0; i < 351; i++) { 14 | result[i] = sale.dailyTotals(i); 15 | } 16 | } 17 | 18 | function userBuys(address user) constant returns (uint[351] result) { 19 | for (uint i = 0; i < 351; i++) { 20 | result[i] = sale.userBuys(i, user); 21 | } 22 | } 23 | 24 | function userClaims(address user) constant returns (bool[351] result) { 25 | for (uint i = 0; i < 351; i++) { 26 | result[i] = sale.claimed(i, user); 27 | } 28 | } 29 | } 30 | --------------------------------------------------------------------------------