diff --git a/css/main.css b/css/main.css index 4dd8934..f477d7b 100644 --- a/css/main.css +++ b/css/main.css @@ -561,7 +561,6 @@ ul { margin-top: 1rem; --border-radius: 0.5rem; border-radius: 0.5rem; - --padding: 1rem 1.2rem; --background: rgba(var(--foreground-color), 1); box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.1); border: solid thin rgba(var(--text-color), 0.2); diff --git a/css/main.min.css b/css/main.min.css index 85eaf9a..de6fa4a 100644 --- a/css/main.min.css +++ b/css/main.min.css @@ -1 +1 @@ -*{padding:0;margin:0;box-sizing:border-box;font-family:"Roboto",sans-serif}:root{font-size:clamp(1rem,1.2vmax,1.2rem)}html,body{height:100%}body{--accent-color: #3d5afe;--secondary-color: #ffac2e;--text-color: 34, 34, 34;--foreground-color: 252, 253, 255;--background-color: 241, 243, 248;--danger-color: rgb(255, 75, 75);--green: #1cad59;--yellow: rgb(220, 165, 0);display:flex;flex-direction:column;color:rgba(var(--text-color), 1);background-color:rgba(var(--background-color), 1)}body[data-theme=dark]{--accent-color: #92a2ff;--secondary-color: #d60739;--text-color: 200, 200, 200;--foreground-color: 27, 28, 29;--background-color: 21, 22, 22;--danger-color: rgb(255, 106, 106);--green: #00e676;--yellow: rgb(255, 213, 5)}p,strong{line-height:1.7;color:rgba(var(--text-color), 0.9);max-width:70ch}img{-o-object-fit:cover;object-fit:cover}a:where([class]){color:inherit;text-decoration:none}a:where([class]):focus-visible{box-shadow:0 0 0 .1rem rgba(var(--text-color), 1) inset}a{color:var(--accent-color)}a:-webkit-any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a:-moz-any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a:any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}button,.button{-webkit-user-select:none;-moz-user-select:none;user-select:none;position:relative;display:inline-flex;border:none;background-color:rgba(0,0,0,0);overflow:hidden;color:inherit;-webkit-tap-highlight-color:rgba(0,0,0,0);align-items:center;font-size:inherit;font-weight:500;white-space:nowrap;padding:.8rem;border-radius:.3rem;justify-content:center;flex-shrink:0}button:focus-visible,.button:focus-visible{outline:var(--accent-color) solid medium}button:not(:disabled),.button:not(:disabled){cursor:pointer}.button{background-color:rgba(var(--text-color), 0.02);border:solid thin rgba(var(--text-color), 0.06)}.button--primary{color:rgba(var(--background-color), 1);background-color:var(--accent-color)}.button--primary .icon{fill:rgba(var(--background-color), 1)}.button--colored{color:var(--accent-color)}.button--colored .icon{fill:var(--accent-color)}.button--danger{background-color:rgba(255,115,115,.062745098);color:var(--danger-color)}.button--danger .icon{fill:var(--danger-color)}.button--small{padding:.4rem .6rem}.button--outlined{border:solid rgba(var(--text-color), 0.3) .1rem;background-color:rgba(var(--foreground-color), 1)}.button--transparent{background-color:rgba(0,0,0,0)}button:disabled{opacity:.4;cursor:not-allowed;filter:saturate(0)}.cta{text-transform:uppercase;font-size:.8rem;font-weight:700;letter-spacing:.05em;padding:.8rem 1rem}.icon{width:1.2rem;height:1.2rem;fill:rgba(var(--text-color), 0.8);flex-shrink:0}.icon-only{padding:.5rem;border-radius:.3rem;aspect-ratio:1/1}a:-webkit-any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a:-moz-any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a:any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}sm-input{--border-radius: 0.5rem;--background-color: rgba(var(--foreground-color), 1)}sm-input button .icon{fill:var(--accent-color)}sm-spinner{--size: 1.5rem;--stroke-width: 0.1rem}sm-copy{font-size:.9rem;font-weight:500}ul{list-style:none}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.wrap-around{overflow-wrap:break-word;word-wrap:break-word;word-break:break-word;-webkit-hyphens:auto;hyphens:auto}.full-bleed{grid-column:1/-1}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.sticky{position:-webkit-sticky;position:sticky}.top-0{top:0}.flex{display:flex}.flex-wrap{flex-wrap:wrap}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.grid{display:grid}.flow-column{grid-auto-flow:column}.gap-0-3{gap:.3rem}.gap-0-5{gap:.5rem}.gap-1{gap:1rem}.gap-1-5{gap:1.5rem}.gap-2{gap:2rem}.gap-3{gap:3rem}.text-align-right{text-align:right}.text-align-left{text-align:left}.align-items-start{align-items:flex-start}.align-items-center{align-items:center}.align-content-start{align-content:flex-start}.align-end{align-items:flex-end}.text-center{text-align:center}.justify-start{justify-items:start}.justify-content-start{justify-content:start}.justify-content-center{justify-content:center}.justify-right{margin-left:auto}.align-self-center{align-self:center}.align-self-end{align-self:end}.justify-self-center{justify-self:center}.justify-self-start{justify-self:start}.justify-self-end{justify-self:end}.flex-direction-column{flex-direction:column}.space-between{justify-content:space-between}.space-evenly{justify-content:space-evenly}.w-100{width:100%}.h-100{height:100%}.padding-block-1{padding-block:1rem}.margin-right-0-3{margin-right:.3rem}.margin-right-0-5{margin-right:.5rem}.margin-right-1{margin-right:1rem}.margin-left-0-5{margin-left:.5rem}.margin-left-auto{margin-left:auto}.margin-right-auto{margin-right:auto}.margin-top-1{margin-top:1rem}.margin-bottom-0-5{margin-bottom:.5rem}.margin-bottom-1{margin-bottom:1rem}.margin-bottom-2{margin-bottom:2rem}.margin-block-0-5{margin-block:.5rem}.margin-block-1{margin-block:1rem}.margin-block-1-5{margin-block:1.5rem}.margin-inline-1{margin-inline:1rem}.margin-inline-1-5{margin-inline:1.5rem}.hidden{display:none !important}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.4rem}.h4{font-size:1rem}.h5{font-size:.8rem}.grid-3{grid-template-columns:1fr auto auto}.flow-column{grid-auto-flow:column}.w-100{width:100%}.color-0-8{color:rgba(var(--text-color), 0.8)}.weight-400{font-weight:400}.weight-500{font-weight:500}.ws-pre-line{white-space:pre-line}.card{background-color:rgba(var(--foreground-color), 1);border-radius:.5rem;padding:max(1rem,3vw)}.ripple{height:8rem;width:8rem;position:absolute;border-radius:50%;transform:scale(0);background:radial-gradient(circle, rgba(var(--text-color), 0.3) 0%, rgba(0, 0, 0, 0) 50%);pointer-events:none}.interact{position:relative;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:rgba(0,0,0,0)}.observe-empty-state:empty{display:none}.observe-empty-state:not(:empty)~.empty-state{display:none}.button__icon{height:1.2rem;width:1.2rem}.button__icon--left{margin-right:.5rem}.button__icon--right{margin-left:.5rem}#loader{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:1rem}#main_header{display:flex;gap:1rem;align-items:center;background:rgba(var(--foreground-color), 1);justify-content:space-between;padding:1.5rem 1rem}#main_logo{height:1.5rem;width:1.5rem;fill:rgba(var(--text-color), 1)}#search_payments{position:-webkit-sticky;position:sticky;top:1rem;width:min(24rem,100% - 2rem);margin:0 auto;margin-top:1rem;--border-radius: 0.5rem;border-radius:.5rem;--padding: 1rem 1.2rem;--background: rgba(var(--foreground-color), 1);box-shadow:0 .5rem 1.5rem rgba(0,0,0,.1);border:solid thin rgba(var(--text-color), 0.2);z-index:2}#intern_payment_list{display:flex;flex-wrap:wrap;gap:1rem;padding:1rem;padding-bottom:4rem;margin-top:1rem;margin:0 auto}.intern-card{display:flex;flex-direction:column;gap:.8rem;padding:max(1rem,3vw);border-radius:.5rem;background-color:rgba(var(--foreground-color), 1);width:100%}.intern-card h3{font-size:1.2rem}.intern-card .button{padding-right:.2rem}#intern{display:flex;flex-direction:column;gap:1.5rem;padding:1rem;width:min(56rem,100%);margin:0 auto}#intern__details{background-color:rgba(var(--foreground-color), 1);padding:max(1rem,3vw);border-radius:.5rem}.back-button{position:-webkit-sticky;position:sticky;top:1rem;z-index:1;background-color:rgba(var(--background-color), 1);border-radius:2rem;padding:.5rem .6rem}.back-button .icon{height:1em;width:1em;margin-right:.1em;margin-left:-0.2rem}h1{font-size:2rem}#payment_history{display:flex;flex-direction:column;gap:1rem}.payment-card{display:flex;flex-direction:column;gap:.5rem;border-radius:.5rem;padding:max(1rem,2vw);background-color:rgba(var(--foreground-color), 1)}.payment-card time{font-size:.85rem;color:rgba(var(--text-color), 0.8)}.payment-card .amount{font-weight:700}@media screen and (max-width: 768px){#intern__details{margin:0 -1rem;margin-top:-5rem;padding-top:5rem;border-radius:0;box-shadow:0 1rem 1rem rgba(0,0,0,.06)}}@media screen and (min-width: 768px){#intern_payment_list{display:grid;grid-template-columns:repeat(auto-fill, minmax(24rem, 1fr))}}@media(any-hover: hover){::-webkit-scrollbar{width:.5rem;height:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color), 0.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color), 0.5)}.interact{transition:background-color .2s}.interact:hover{background-color:rgba(var(--text-color), 0.04)}} \ No newline at end of file +*{padding:0;margin:0;box-sizing:border-box;font-family:"Roboto",sans-serif}:root{font-size:clamp(1rem,1.2vmax,1.2rem)}html,body{height:100%}body{--accent-color: #3d5afe;--secondary-color: #ffac2e;--text-color: 34, 34, 34;--foreground-color: 252, 253, 255;--background-color: 241, 243, 248;--danger-color: rgb(255, 75, 75);--green: #1cad59;--yellow: rgb(220, 165, 0);display:flex;flex-direction:column;color:rgba(var(--text-color), 1);background-color:rgba(var(--background-color), 1)}body[data-theme=dark]{--accent-color: #92a2ff;--secondary-color: #d60739;--text-color: 200, 200, 200;--foreground-color: 27, 28, 29;--background-color: 21, 22, 22;--danger-color: rgb(255, 106, 106);--green: #00e676;--yellow: rgb(255, 213, 5)}p,strong{line-height:1.7;color:rgba(var(--text-color), 0.9);max-width:70ch}img{-o-object-fit:cover;object-fit:cover}a:where([class]){color:inherit;text-decoration:none}a:where([class]):focus-visible{box-shadow:0 0 0 .1rem rgba(var(--text-color), 1) inset}a{color:var(--accent-color)}a:-webkit-any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a:-moz-any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a:any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}button,.button{-webkit-user-select:none;-moz-user-select:none;user-select:none;position:relative;display:inline-flex;border:none;background-color:rgba(0,0,0,0);overflow:hidden;color:inherit;-webkit-tap-highlight-color:rgba(0,0,0,0);align-items:center;font-size:inherit;font-weight:500;white-space:nowrap;padding:.8rem;border-radius:.3rem;justify-content:center;flex-shrink:0}button:focus-visible,.button:focus-visible{outline:var(--accent-color) solid medium}button:not(:disabled),.button:not(:disabled){cursor:pointer}.button{background-color:rgba(var(--text-color), 0.02);border:solid thin rgba(var(--text-color), 0.06)}.button--primary{color:rgba(var(--background-color), 1);background-color:var(--accent-color)}.button--primary .icon{fill:rgba(var(--background-color), 1)}.button--colored{color:var(--accent-color)}.button--colored .icon{fill:var(--accent-color)}.button--danger{background-color:rgba(255,115,115,.062745098);color:var(--danger-color)}.button--danger .icon{fill:var(--danger-color)}.button--small{padding:.4rem .6rem}.button--outlined{border:solid rgba(var(--text-color), 0.3) .1rem;background-color:rgba(var(--foreground-color), 1)}.button--transparent{background-color:rgba(0,0,0,0)}button:disabled{opacity:.4;cursor:not-allowed;filter:saturate(0)}.cta{text-transform:uppercase;font-size:.8rem;font-weight:700;letter-spacing:.05em;padding:.8rem 1rem}.icon{width:1.2rem;height:1.2rem;fill:rgba(var(--text-color), 0.8);flex-shrink:0}.icon-only{padding:.5rem;border-radius:.3rem;aspect-ratio:1/1}a:-webkit-any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a:-moz-any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a:any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}sm-input{--border-radius: 0.5rem;--background-color: rgba(var(--foreground-color), 1)}sm-input button .icon{fill:var(--accent-color)}sm-spinner{--size: 1.5rem;--stroke-width: 0.1rem}sm-copy{font-size:.9rem;font-weight:500}ul{list-style:none}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.wrap-around{overflow-wrap:break-word;word-wrap:break-word;word-break:break-word;-webkit-hyphens:auto;hyphens:auto}.full-bleed{grid-column:1/-1}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.sticky{position:-webkit-sticky;position:sticky}.top-0{top:0}.flex{display:flex}.flex-wrap{flex-wrap:wrap}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.grid{display:grid}.flow-column{grid-auto-flow:column}.gap-0-3{gap:.3rem}.gap-0-5{gap:.5rem}.gap-1{gap:1rem}.gap-1-5{gap:1.5rem}.gap-2{gap:2rem}.gap-3{gap:3rem}.text-align-right{text-align:right}.text-align-left{text-align:left}.align-items-start{align-items:flex-start}.align-items-center{align-items:center}.align-content-start{align-content:flex-start}.align-end{align-items:flex-end}.text-center{text-align:center}.justify-start{justify-items:start}.justify-content-start{justify-content:start}.justify-content-center{justify-content:center}.justify-right{margin-left:auto}.align-self-center{align-self:center}.align-self-end{align-self:end}.justify-self-center{justify-self:center}.justify-self-start{justify-self:start}.justify-self-end{justify-self:end}.flex-direction-column{flex-direction:column}.space-between{justify-content:space-between}.space-evenly{justify-content:space-evenly}.w-100{width:100%}.h-100{height:100%}.padding-block-1{padding-block:1rem}.margin-right-0-3{margin-right:.3rem}.margin-right-0-5{margin-right:.5rem}.margin-right-1{margin-right:1rem}.margin-left-0-5{margin-left:.5rem}.margin-left-auto{margin-left:auto}.margin-right-auto{margin-right:auto}.margin-top-1{margin-top:1rem}.margin-bottom-0-5{margin-bottom:.5rem}.margin-bottom-1{margin-bottom:1rem}.margin-bottom-2{margin-bottom:2rem}.margin-block-0-5{margin-block:.5rem}.margin-block-1{margin-block:1rem}.margin-block-1-5{margin-block:1.5rem}.margin-inline-1{margin-inline:1rem}.margin-inline-1-5{margin-inline:1.5rem}.hidden{display:none !important}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.4rem}.h4{font-size:1rem}.h5{font-size:.8rem}.grid-3{grid-template-columns:1fr auto auto}.flow-column{grid-auto-flow:column}.w-100{width:100%}.color-0-8{color:rgba(var(--text-color), 0.8)}.weight-400{font-weight:400}.weight-500{font-weight:500}.ws-pre-line{white-space:pre-line}.card{background-color:rgba(var(--foreground-color), 1);border-radius:.5rem;padding:max(1rem,3vw)}.ripple{height:8rem;width:8rem;position:absolute;border-radius:50%;transform:scale(0);background:radial-gradient(circle, rgba(var(--text-color), 0.3) 0%, rgba(0, 0, 0, 0) 50%);pointer-events:none}.interact{position:relative;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:rgba(0,0,0,0)}.observe-empty-state:empty{display:none}.observe-empty-state:not(:empty)~.empty-state{display:none}.button__icon{height:1.2rem;width:1.2rem}.button__icon--left{margin-right:.5rem}.button__icon--right{margin-left:.5rem}#loader{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:1rem}#main_header{display:flex;gap:1rem;align-items:center;background:rgba(var(--foreground-color), 1);justify-content:space-between;padding:1.5rem 1rem}#main_logo{height:1.5rem;width:1.5rem;fill:rgba(var(--text-color), 1)}#search_payments{position:-webkit-sticky;position:sticky;top:1rem;width:min(24rem,100% - 2rem);margin:0 auto;margin-top:1rem;--border-radius: 0.5rem;border-radius:.5rem;--background: rgba(var(--foreground-color), 1);box-shadow:0 .5rem 1.5rem rgba(0,0,0,.1);border:solid thin rgba(var(--text-color), 0.2);z-index:2}#intern_payment_list{display:flex;flex-wrap:wrap;gap:1rem;padding:1rem;padding-bottom:4rem;margin-top:1rem;margin:0 auto}.intern-card{display:flex;flex-direction:column;gap:.8rem;padding:max(1rem,3vw);border-radius:.5rem;background-color:rgba(var(--foreground-color), 1);width:100%}.intern-card h3{font-size:1.2rem}.intern-card .button{padding-right:.2rem}#intern{display:flex;flex-direction:column;gap:1.5rem;padding:1rem;width:min(56rem,100%);margin:0 auto}#intern__details{background-color:rgba(var(--foreground-color), 1);padding:max(1rem,3vw);border-radius:.5rem}.back-button{position:-webkit-sticky;position:sticky;top:1rem;z-index:1;background-color:rgba(var(--background-color), 1);border-radius:2rem;padding:.5rem .6rem}.back-button .icon{height:1em;width:1em;margin-right:.1em;margin-left:-0.2rem}h1{font-size:2rem}#payment_history{display:flex;flex-direction:column;gap:1rem}.payment-card{display:flex;flex-direction:column;gap:.5rem;border-radius:.5rem;padding:max(1rem,2vw);background-color:rgba(var(--foreground-color), 1)}.payment-card time{font-size:.85rem;color:rgba(var(--text-color), 0.8)}.payment-card .amount{font-weight:700}@media screen and (max-width: 768px){#intern__details{margin:0 -1rem;margin-top:-5rem;padding-top:5rem;border-radius:0;box-shadow:0 1rem 1rem rgba(0,0,0,.06)}}@media screen and (min-width: 768px){#intern_payment_list{display:grid;grid-template-columns:repeat(auto-fill, minmax(24rem, 1fr))}}@media(any-hover: hover){::-webkit-scrollbar{width:.5rem;height:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color), 0.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color), 0.5)}.interact{transition:background-color .2s}.interact:hover{background-color:rgba(var(--text-color), 0.04)}} \ No newline at end of file diff --git a/css/main.scss b/css/main.scss index 5e90558..0d70fb8 100644 --- a/css/main.scss +++ b/css/main.scss @@ -39,6 +39,7 @@ body[data-theme="dark"] { --green: #00e676; --yellow: rgb(255, 213, 5); } + p, strong { line-height: 1.7; @@ -58,6 +59,7 @@ a:where([class]) { box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; } } + a { color: var(--accent-color); } @@ -84,6 +86,7 @@ button, border-radius: 0.3rem; justify-content: center; flex-shrink: 0; + &:focus-visible { outline: var(--accent-color) solid medium; } @@ -96,6 +99,7 @@ button, .button { background-color: rgba(var(--text-color), 0.02); border: solid thin rgba(var(--text-color), 0.06); + &--primary { color: rgba(var(--background-color), 1); background-color: var(--accent-color); @@ -104,15 +108,19 @@ button, fill: rgba(var(--background-color), 1); } } + &--colored { color: var(--accent-color); + .icon { fill: var(--accent-color); } } + &--danger { background-color: #ff737310; color: var(--danger-color); + .icon { fill: var(--danger-color); } @@ -126,10 +134,12 @@ button, border: solid rgba(var(--text-color), 0.3) 0.1rem; background-color: rgba(var(--foreground-color), 1); } + &--transparent { background-color: transparent; } } + button:disabled { opacity: 0.4; cursor: not-allowed; @@ -171,10 +181,12 @@ sm-input { } } } + sm-spinner { --size: 1.5rem; --stroke-width: 0.1rem; } + sm-copy { font-size: 0.9rem; font-weight: 500; @@ -229,6 +241,7 @@ ul { .flex-1 { flex: 1; } + .flex-shrink-0 { flex-shrink: 0; } @@ -268,6 +281,7 @@ ul { .text-align-right { text-align: right; } + .text-align-left { text-align: left; } @@ -275,9 +289,11 @@ ul { .align-items-start { align-items: flex-start; } + .align-items-center { align-items: center; } + .align-content-start { align-content: flex-start; } @@ -293,6 +309,7 @@ ul { .justify-start { justify-items: start; } + .justify-content-start { justify-content: start; } @@ -332,6 +349,7 @@ ul { .space-between { justify-content: space-between; } + .space-evenly { justify-content: space-evenly; } @@ -351,9 +369,11 @@ ul { .margin-right-0-3 { margin-right: 0.3rem; } + .margin-right-0-5 { margin-right: 0.5rem; } + .margin-right-1 { margin-right: 1rem; } @@ -365,18 +385,23 @@ ul { .margin-left-auto { margin-left: auto; } + .margin-right-auto { margin-right: auto; } + .margin-top-1 { margin-top: 1rem; } + .margin-bottom-0-5 { margin-bottom: 0.5rem; } + .margin-bottom-1 { margin-bottom: 1rem; } + .margin-bottom-2 { margin-bottom: 2rem; } @@ -384,6 +409,7 @@ ul { .margin-block-0-5 { margin-block: 0.5rem; } + .margin-block-1 { margin-block: 1rem; } @@ -431,6 +457,7 @@ ul { .flow-column { grid-auto-flow: column; } + .w-100 { width: 100%; } @@ -446,6 +473,7 @@ ul { .weight-500 { font-weight: 500; } + .ws-pre-line { white-space: pre-line; } @@ -462,13 +490,12 @@ ul { position: absolute; border-radius: 50%; transform: scale(0); - background: radial-gradient( - circle, - rgba(var(--text-color), 0.3) 0%, - rgba(0, 0, 0, 0) 50% - ); + background: radial-gradient(circle, + rgba(var(--text-color), 0.3) 0%, + rgba(0, 0, 0, 0) 50%); pointer-events: none; } + .interact { position: relative; overflow: hidden; @@ -480,7 +507,7 @@ ul { display: none; } -.observe-empty-state:not(:empty) ~ .empty-state { +.observe-empty-state:not(:empty)~.empty-state { display: none; } @@ -496,6 +523,7 @@ ul { margin-left: 0.5rem; } } + #loader { display: flex; flex-direction: column; @@ -504,6 +532,7 @@ ul { height: 100%; gap: 1rem; } + #main_header { display: flex; gap: 1rem; @@ -512,11 +541,13 @@ ul { justify-content: space-between; padding: 1.5rem 1rem; } + #main_logo { height: 1.5rem; width: 1.5rem; fill: rgba(var(--text-color), 1); } + #search_payments { position: sticky; top: 1rem; @@ -525,12 +556,12 @@ ul { margin-top: 1rem; --border-radius: 0.5rem; border-radius: 0.5rem; - --padding: 1rem 1.2rem; --background: rgba(var(--foreground-color), 1); box-shadow: 0 0.5rem 1.5rem rgba(0 0 0 /0.1); border: solid thin rgba(var(--text-color), 0.2); z-index: 2; } + #intern_payment_list { display: flex; flex-wrap: wrap; @@ -540,6 +571,7 @@ ul { margin-top: 1rem; margin: 0 auto; } + .intern-card { display: flex; flex-direction: column; @@ -548,13 +580,16 @@ ul { border-radius: 0.5rem; background-color: rgba(var(--foreground-color), 1); width: 100%; + h3 { font-size: 1.2rem; } + .button { padding-right: 0.2rem; } } + #intern { display: flex; flex-direction: column; @@ -563,11 +598,13 @@ ul { width: min(56rem, 100%); margin: 0 auto; } + #intern__details { background-color: rgba(var(--foreground-color), 1); padding: max(1rem, 3vw); border-radius: 0.5rem; } + .back-button { position: sticky; top: 1rem; @@ -575,6 +612,7 @@ ul { background-color: rgba(var(--background-color), 1); border-radius: 2rem; padding: 0.5rem 0.6rem; + .icon { height: 1em; width: 1em; @@ -582,14 +620,17 @@ ul { margin-left: -0.2rem; } } + h1 { font-size: 2rem; } + #payment_history { display: flex; flex-direction: column; gap: 1rem; } + .payment-card { display: flex; flex-direction: column; @@ -597,14 +638,17 @@ h1 { border-radius: 0.5rem; padding: max(1rem, 2vw); background-color: rgba(var(--foreground-color), 1); + time { font-size: 0.85rem; color: rgba(var(--text-color), 0.8); } + .amount { font-weight: 700; } } + @media screen and (max-width: 768px) { #intern__details { margin: 0 -1rem; @@ -614,12 +658,14 @@ h1 { box-shadow: 0 1rem 1rem rgba(0 0 0 /0.06); } } + @media screen and (min-width: 768px) { #intern_payment_list { display: grid; grid-template-columns: repeat(auto-fill, minmax(24rem, 1fr)); } } + @media (any-hover: hover) { ::-webkit-scrollbar { width: 0.5rem; @@ -634,10 +680,12 @@ h1 { background: rgba(var(--text-color), 0.5); } } + .interact { transition: background-color 0.2s; + &:hover { background-color: rgba(var(--text-color), 0.04); } } -} +} \ No newline at end of file diff --git a/index.html b/index.html index 003a472..b9e8970 100644 --- a/index.html +++ b/index.html @@ -20,14 +20,13 @@ } - - - - - - - - + + + + + + + diff --git a/js/btcOperator.min.js b/js/btcOperator.min.js new file mode 100644 index 0000000..65f4421 --- /dev/null +++ b/js/btcOperator.min.js @@ -0,0 +1 @@ +!function(EXPORTS){const btcOperator="object"===typeof module?module.exports:window.btcOperator={},URL="https://blockchain.info/",fetch_api=btcOperator.fetch=function(api,json_res=!0){return new Promise(((resolve,reject)=>{console.debug(URL+api),fetch(URL+api).then((response=>{response.ok?(json_res?response.json():response.text()).then((result=>resolve(result))).catch((error=>reject(error))):response.json().then((result=>reject(result))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},util=btcOperator.util={};util.Sat_to_BTC=value=>parseFloat((value/1e8).toFixed(8)),util.BTC_to_Sat=value=>parseInt(1e8*value);const broadcastTx=btcOperator.broadcastTx=rawTxHex=>new Promise(((resolve,reject)=>{fetch("https://coinb.in/api/?uid=1&key=12345678901234567890123456789012&setmodule=bitcoin&request=sendrawtransaction",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:"rawtx="+rawTxHex}).then((response=>{response.text().then((resultText=>{let r=resultText.match(/.*<\/result>/);if(r)if(r=r.pop().replace("","").replace("",""),"1"==r){let txid=resultText.match(/.*<\/txid>/).pop().replace("","").replace("","");resolve(txid)}else if("0"==r){let error=resultText.match(/.*<\/response>/).pop().replace("","").replace("","");reject(decodeURIComponent(error.replace(/\+/g," ")))}else reject(resultText);else reject(resultText)})).catch((error=>reject(error)))})).catch((error=>reject(error)))}));Object.defineProperties(btcOperator,{newKeys:{get:()=>{let r=coinjs.newKeys();return r.segwitAddress=coinjs.segwitAddress(r.pubkey).address,r.bech32Address=coinjs.bech32Address(r.pubkey).address,r}},pubkey:{value:key=>key.length>=66?key:64==key.length?coinjs.newPubkey(key):coinjs.wif2pubkey(key).pubkey},address:{value:(key,prefix=void 0)=>coinjs.pubkey2address(btcOperator.pubkey(key),prefix)},segwitAddress:{value:key=>coinjs.segwitAddress(btcOperator.pubkey(key)).address},bech32Address:{value:key=>coinjs.bech32Address(btcOperator.pubkey(key)).address}}),coinjs.compressed=!0;const verifyKey=btcOperator.verifyKey=function(addr,key){if(addr&&key)switch(coinjs.addressDecode(addr).type){case"standard":return btcOperator.address(key)===addr;case"multisig":return btcOperator.segwitAddress(key)===addr;case"bech32":return btcOperator.bech32Address(key)===addr;default:return null}},validateAddress=btcOperator.validateAddress=function(addr){if(!addr)return;let type=coinjs.addressDecode(addr).type;return!!["standard","multisig","bech32","multisigBech32"].includes(type)&&type};btcOperator.multiSigAddress=function(pubKeys,minRequired,bech32=!0){if(!Array.isArray(pubKeys))throw"pubKeys must be an array of public keys";if(pubKeys.lengthnew Promise(((resolve,reject)=>{fetch_api(`q/addressbalance/${addr}`).then((result=>resolve(util.Sat_to_BTC(result)))).catch((error=>reject(error)))}));const BASE_TX_SIZE=12,BASE_INPUT_SIZE=41,LEGACY_INPUT_SIZE=107,BECH32_INPUT_SIZE=27,BECH32_MULTISIG_INPUT_SIZE=35,SEGWIT_INPUT_SIZE=59,MULTISIG_INPUT_SIZE_ES=351,BASE_OUTPUT_SIZE=9,LEGACY_OUTPUT_SIZE=25,BECH32_OUTPUT_SIZE=23,BECH32_MULTISIG_OUTPUT_SIZE=34,SEGWIT_OUTPUT_SIZE=23;function _redeemScript(addr,key){let decode=coinjs.addressDecode(addr);switch(decode.type){case"standard":return!1;case"multisig":return key?coinjs.segwitAddress(btcOperator.pubkey(key)).redeemscript:null;case"bech32":return decode.redeemscript;default:return null}}function _sizePerOutput(addr){switch(coinjs.addressDecode(addr).type){case"standard":return BASE_OUTPUT_SIZE+LEGACY_OUTPUT_SIZE;case"bech32":return BASE_OUTPUT_SIZE+BECH32_OUTPUT_SIZE;case"multisigBech32":return BASE_OUTPUT_SIZE+BECH32_MULTISIG_OUTPUT_SIZE;case"multisig":return BASE_OUTPUT_SIZE+SEGWIT_OUTPUT_SIZE;default:return null}}function validateTxParameters(parameters){let invalids=[];if(parameters.senders&&(Array.isArray(parameters.senders)||(parameters.senders=[parameters.senders]),parameters.senders.forEach((id=>validateAddress(id)?null:invalids.push(id))),invalids.length))throw"Invalid senders:"+invalids;if(parameters.privkeys){if(Array.isArray(parameters.privkeys)||(parameters.privkeys=[parameters.privkeys]),parameters.senders.length!=parameters.privkeys.length)throw"Array length for senders and privkeys should be equal";if(parameters.senders.forEach(((id,i)=>{let key=parameters.privkeys[i];verifyKey(id,key)||invalids.push(id),64===key.length&&(parameters.privkeys[i]=coinjs.privkey2wif(key))})),invalids.length)throw"Invalid private key for address:"+invalids}if(Array.isArray(parameters.receivers)||(parameters.receivers=[parameters.receivers]),parameters.receivers.forEach((id=>validateAddress(id)?null:invalids.push(id))),invalids.length)throw"Invalid receivers:"+invalids;if(parameters.change_address&&!validateAddress(parameters.change_address))throw"Invalid change_address:"+parameters.change_address;if(("number"!=typeof parameters.fee||parameters.fee<=0)&&null!==parameters.fee)throw"Invalid fee:"+parameters.fee;if(Array.isArray(parameters.amounts)||(parameters.amounts=[parameters.amounts]),parameters.receivers.length!=parameters.amounts.length)throw"Array length for receivers and amounts should be equal";if(parameters.amounts.forEach((a=>"number"!=typeof a||a<=0?invalids.push(a):null)),invalids.length)throw"Invalid amounts:"+invalids;return parameters}function createTransaction(senders,redeemScripts,receivers,amounts,fee,change_address,fee_from_receiver){return new Promise(((resolve,reject)=>{let total_amount=parseFloat(amounts.reduce(((t,a)=>t+a),0).toFixed(8));const tx=coinjs.transaction();let output_size=function(tx,receivers,amounts,change_address){let size=0;for(let i in receivers)tx.addoutput(receivers[i],amounts[i]),size+=_sizePerOutput(receivers[i]);return tx.addoutput(change_address,0),size+=_sizePerOutput(change_address),size}(tx,receivers,amounts,change_address);(function(tx,senders,redeemScripts,total_amount,fee,output_size,fee_from_receiver){return new Promise(((resolve,reject)=>{null!==fee?addUTXOs(tx,senders,redeemScripts,fee_from_receiver?total_amount:total_amount+fee,!1).then((result=>{result.fee=fee,resolve(result)})).catch((error=>reject(error))):new Promise(((resolve,reject)=>{fetch("https://api.blockchain.info/mempool/fees").then((response=>{response.ok?response.json().then((result=>resolve(util.Sat_to_BTC(result.regular)))).catch((error=>reject(error))):reject(response)})).catch((error=>reject(error)))})).then((fee_rate=>{let net_fee=BASE_TX_SIZE*fee_rate;net_fee+=output_size*fee_rate,(fee_from_receiver?addUTXOs(tx,senders,redeemScripts,total_amount,!1):addUTXOs(tx,senders,redeemScripts,total_amount+net_fee,fee_rate)).then((result=>{result.fee=parseFloat((net_fee+result.input_size*fee_rate).toFixed(8)),result.fee_rate=fee_rate,resolve(result)})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))})(tx,senders,redeemScripts,total_amount,fee,output_size,fee_from_receiver).then((result=>{if(result.change_amount>0&&result.change_amount>result.fee&&(tx.outs[tx.outs.length-1].value=util.BTC_to_Sat(result.change_amount)),fee_from_receiver){let fee_remaining=util.BTC_to_Sat(result.fee);for(let i=0;i0;i++)fee_remaining0)return reject("Send amount is less than fee")}let filtered_outputs=[],dust_value=0;tx.outs.forEach((o=>o.value>=546?filtered_outputs.push(o):dust_value+=o.value)),tx.outs=filtered_outputs,result.fee+=util.Sat_to_BTC(dust_value),result.output_size=output_size,result.output_amount=total_amount-(fee_from_receiver?result.fee:0),result.total_size=BASE_TX_SIZE+output_size+result.input_size,result.transaction=tx,resolve(result)})).catch((error=>reject(error)))}))}function addUTXOs(tx,senders,redeemScripts,required_amount,fee_rate,rec_args={}){return new Promise(((resolve,reject)=>{if(required_amount=parseFloat(required_amount.toFixed(8)),void 0===rec_args.n&&(rec_args.n=0,rec_args.input_size=0,rec_args.input_amount=0),required_amount<=0)return resolve({input_size:rec_args.input_size,input_amount:rec_args.input_amount,change_amount:-1*required_amount});if(rec_args.n>=senders.length)return reject("Insufficient Balance");let addr=senders[rec_args.n],rs=redeemScripts[rec_args.n],addr_type=coinjs.addressDecode(addr).type,size_per_input=function(addr,rs){switch(coinjs.addressDecode(addr).type){case"standard":return BASE_INPUT_SIZE+LEGACY_INPUT_SIZE;case"bech32":return BASE_INPUT_SIZE+BECH32_INPUT_SIZE;case"multisigBech32":return BASE_INPUT_SIZE+BECH32_MULTISIG_INPUT_SIZE;case"multisig":switch(coinjs.script().decodeRedeemScript(rs).type){case"segwit__":return BASE_INPUT_SIZE+SEGWIT_INPUT_SIZE;case"multisig__":return BASE_INPUT_SIZE+MULTISIG_INPUT_SIZE_ES;default:return null}default:return null}}(addr,rs);fetch_api(`unspent?active=${addr}`).then((result=>{let utxos=result.unspent_outputs;for(let i=0;i0;i++)if(utxos[i].confirmations){var script;if(rs&&rs.length)if(rs.match(/^00/)&&44==rs.length||40==rs.length&&rs.match(/^[a-f0-9]+$/gi)||"multisigBech32"===addr_type){let s=coinjs.script();s.writeBytes(Crypto.util.hexToBytes(rs)),s.writeOp(0),s.writeBytes(coinjs.numToBytes(utxos[i].value.toFixed(0),8)),script=Crypto.util.bytesToHex(s.buffer)}else script=rs;else script=utxos[i].script;tx.addinput(utxos[i].tx_hash_big_endian,utxos[i].tx_output_n,script,4294967293),rec_args.input_size+=size_per_input,rec_args.input_amount+=util.Sat_to_BTC(utxos[i].value),required_amount-=util.Sat_to_BTC(utxos[i].value),fee_rate&&(required_amount+=size_per_input*fee_rate)}rec_args.n+=1,addUTXOs(tx,senders,redeemScripts,required_amount,fee_rate,rec_args).then((result=>resolve(result))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))}btcOperator.editFee=function(tx_hex,new_fee,private_keys,change_only=!0){return new Promise(((resolve,reject)=>{var tx;Array.isArray(private_keys)||(private_keys=[private_keys]),(tx=tx_hex,new Promise(((resolve,reject)=>{"string"==typeof tx&&/^[0-9a-f]{64}$/i.test(tx)?getTx.hex(tx).then((txhex=>resolve(deserializeTx(txhex)))).catch((error=>reject(error))):resolve(deserializeTx(tx))}))).then((tx=>{parseTransaction(tx).then((tx_parsed=>{if(tx_parsed.fee>=new_fee)return reject("Fees can only be increased");var edit_output_address=new Set;!0===change_only?tx_parsed.inputs.forEach((inp=>edit_output_address.add(inp.address))):!1===change_only?tx_parsed.outputs.forEach((out=>edit_output_address.add(out.address))):"string"==typeof change_only?edit_output_address.add(change_only):Array.isArray(change_only)&&change_only.forEach((id=>edit_output_address.add(id)));let inc_fee=util.BTC_to_Sat(new_fee-tx_parsed.fee);if(inc_fee<219)return reject("Insufficient additional fee. Minimum increment: 219");for(let i=tx.outs.length-1;i>=0&&inc_fee>0;i--)if(edit_output_address.has(tx_parsed.outputs[i].address)){let current_value=tx.outs[i].value;current_value instanceof BigInteger&&(current_value=current_value.intValue()),current_value>inc_fee?(tx.outs[i].value=current_value-inc_fee,inc_fee=0):(inc_fee-=current_value,tx.outs[i].value=0)}if(inc_fee>0){let max_possible_fee=util.BTC_to_Sat(new_fee)-inc_fee;return reject(`Insufficient output values to increase fee. Maximum fee possible: ${util.Sat_to_BTC(max_possible_fee)}`)}tx.outs=tx.outs.filter((o=>o.value>=546));let wif_keys=[];for(let i in tx.ins){var addr=tx_parsed.inputs[i].address,value=util.BTC_to_Sat(tx_parsed.inputs[i].value);let addr_decode=coinjs.addressDecode(addr);var privKey=private_keys.find((pk=>verifyKey(addr,pk)));if(!privKey)return reject(`Private key missing for ${addr}`);const rs=_redeemScript(addr,privKey);var script;if(!1===rs?wif_keys.unshift(privKey):wif_keys.push(privKey),rs&&rs.length)if(rs.match(/^00/)&&44==rs.length||40==rs.length&&rs.match(/^[a-f0-9]+$/gi)||"multisigBech32"===addr_decode.type){let s=coinjs.script();s.writeBytes(Crypto.util.hexToBytes(rs)),s.writeOp(0),s.writeBytes(coinjs.numToBytes(value.toFixed(0),8)),script=Crypto.util.bytesToHex(s.buffer)}else script=rs;else{let s=coinjs.script();s.writeOp(118),s.writeOp(169),s.writeBytes(addr_decode.bytes),s.writeOp(136),s.writeOp(172),script=Crypto.util.bytesToHex(s.buffer)}tx.ins[i].script=coinjs.script(script)}tx.witness=!1,console.debug("Unsigned:",tx.serialize()),new Set(wif_keys).forEach((key=>tx.sign(key,1))),resolve(tx.serialize())})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},btcOperator.sendTx=function(senders,privkeys,receivers,amounts,fee=null,options={}){return new Promise(((resolve,reject)=>{createSignedTx(senders,privkeys,receivers,amounts,fee,options).then((result=>{broadcastTx(result.transaction.serialize()).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))};const createSignedTx=btcOperator.createSignedTx=function(senders,privkeys,receivers,amounts,fee=null,options={}){return new Promise(((resolve,reject)=>{try{({senders:senders,privkeys:privkeys,receivers:receivers,amounts:amounts}=validateTxParameters({senders:senders,privkeys:privkeys,receivers:receivers,amounts:amounts,fee:fee,change_address:options.change_address}))}catch(e){return reject(e)}let redeemScripts=[],wif_keys=[];for(let i in senders){let rs=_redeemScript(senders[i],privkeys[i]);redeemScripts.push(rs),!1===rs?wif_keys.unshift(privkeys[i]):wif_keys.push(privkeys[i])}if(redeemScripts.includes(null))return reject("Unable to get redeem-script");createTransaction(senders,redeemScripts,receivers,amounts,fee,options.change_address||senders[0],options.fee_from_receiver).then((result=>{let tx=result.transaction;console.debug("Unsigned:",tx.serialize()),new Set(wif_keys).forEach((key=>tx.sign(key,1))),console.debug("Signed:",tx.serialize()),resolve(result)})).catch((error=>reject(error)))}))};function deserializeTx(tx){if("string"==typeof tx||Array.isArray(tx))try{tx=coinjs.transaction().deserialize(tx)}catch{throw"Invalid transaction hex"}else if("object"!=typeof tx||"function"!=typeof tx.sign)throw"Invalid transaction object";return tx}btcOperator.createTx=function(senders,receivers,amounts,fee=null,options={}){return new Promise(((resolve,reject)=>{try{({senders:senders,receivers:receivers,amounts:amounts}=validateTxParameters({senders:senders,receivers:receivers,amounts:amounts,fee:fee,change_address:options.change_address}))}catch(e){return reject(e)}let redeemScripts=senders.map((id=>_redeemScript(id)));if(redeemScripts.includes(null))return reject("Unable to get redeem-script");createTransaction(senders,redeemScripts,receivers,amounts,fee,options.change_address||senders[0],options.fee_from_receiver).then((result=>{result.tx_hex=result.transaction.serialize(),delete result.transaction,resolve(result)})).catch((error=>reject(error)))}))},btcOperator.createMultiSigTx=function(sender,redeemScript,receivers,amounts,fee=null,options={}){return new Promise(((resolve,reject)=>{let addr_type=validateAddress(sender);if(!["multisig","multisigBech32"].includes(addr_type))return reject("Invalid sender (multisig):"+sender);{let script=coinjs.script(),decode="multisig"==addr_type?script.decodeRedeemScript(redeemScript):script.decodeRedeemScriptBech32(redeemScript);if(!decode||decode.address!==sender)return reject("Invalid redeem-script")}try{({receivers:receivers,amounts:amounts}=validateTxParameters({receivers:receivers,amounts:amounts,fee:fee,change_address:options.change_address}))}catch(e){return reject(e)}createTransaction([sender],[redeemScript],receivers,amounts,fee,options.change_address||sender,options.fee_from_receiver).then((result=>{result.tx_hex=result.transaction.serialize(),delete result.transaction,resolve(result)})).catch((error=>reject(error)))}))},btcOperator.signTx=function(tx,privkeys,sighashtype=1){tx=deserializeTx(tx),Array.isArray(privkeys)||(privkeys=[privkeys]);for(let i in privkeys)64===privkeys[i].length&&(privkeys[i]=coinjs.privkey2wif(privkeys[i]));return new Set(privkeys).forEach((key=>tx.sign(key,sighashtype))),tx.serialize()};const checkSigned=btcOperator.checkSigned=function(tx,bool=!0){tx=deserializeTx(tx);let n=[];for(let i in tx.ins){var s=tx.extractScriptKey(i);if("multisig"!==s.type&&"multisig_bech32"!==s.type)n.push("true"==s.signed||tx.witness[i]&&2==tx.witness[i].length);else{var rs=coinjs.script().decodeRedeemScript(s.script);let x={s:s.signatures,r:rs.signaturesRequired,t:rs.pubkeys.length};if(x.r>x.t)throw"signaturesRequired is more than publicKeys";x.s!0!==x)).length:n};btcOperator.checkIfSameTx=function(tx1,tx2){if(tx1=deserializeTx(tx1),tx2=deserializeTx(tx2),tx1.ins.length!==tx2.ins.length||tx1.outs.length!==tx2.outs.length)return!1;for(let i=0;inew Promise(((resolve,reject)=>{fetch_api(`rawtx/${txid}`).then((result=>resolve(result.out[i]))).catch((error=>reject(error)))})),parseTransaction=btcOperator.parseTransaction=function(tx){return new Promise(((resolve,reject)=>{tx=deserializeTx(tx);let result={},promises=[];for(let i=0;i{result.inputs=inputs.map((inp=>Object({address:inp.addr,value:util.Sat_to_BTC(inp.value)})));let signed=checkSigned(tx,!1);result.inputs.forEach(((inp,i)=>inp.signed=signed[i])),result.outputs=tx.outs.map((out=>{var address;switch(out.script.chunks[0]){case 0:address=util.encodeBech32(Crypto.util.bytesToHex(out.script.chunks[1]),coinjs.bech32.version,coinjs.bech32.hrp);break;case 169:address=util.encodeLegacy(Crypto.util.bytesToHex(out.script.chunks[1]),coinjs.multisig);break;case 118:address=util.encodeLegacy(Crypto.util.bytesToHex(out.script.chunks[2]),coinjs.pub)}return{address:address,value:util.Sat_to_BTC(out.value)}})),result.total_input=parseFloat(result.inputs.reduce(((a,inp)=>a+inp.value),0).toFixed(8)),result.total_output=parseFloat(result.outputs.reduce(((a,out)=>a+out.value),0).toFixed(8)),result.fee=parseFloat((result.total_input-result.total_output).toFixed(8)),resolve(result)})).catch((error=>reject(error)))}))};btcOperator.transactionID=function(tx){tx=deserializeTx(tx);let clone=coinjs.clone(tx);clone.witness=null;let raw_bytes=Crypto.util.hexToBytes(clone.serialize()),txid=Crypto.SHA256(Crypto.SHA256(raw_bytes,{asBytes:!0}),{asBytes:!0}).reverse();return Crypto.util.bytesToHex(txid)};const getLatestBlock=btcOperator.getLatestBlock=()=>new Promise(((resolve,reject)=>{fetch_api("q/getblockcount").then((result=>resolve(result))).catch((error=>reject(error)))})),getTx=btcOperator.getTx=txid=>new Promise(((resolve,reject)=>{fetch_api(`rawtx/${txid}`).then((result=>{getLatestBlock().then((latest_block=>resolve({block:result.block_height,txid:result.hash,time:1e3*result.time,confirmations:null===result.block_height?0:latest_block-result.block_height,size:result.size,fee:util.Sat_to_BTC(result.fee),inputs:result.inputs.map((i=>Object({address:i.prev_out.addr,value:util.Sat_to_BTC(i.prev_out.value)}))),total_input_value:util.Sat_to_BTC(result.inputs.reduce(((a,i)=>a+i.prev_out.value),0)),outputs:result.out.map((o=>Object({address:o.addr,value:util.Sat_to_BTC(o.value)}))),total_output_value:util.Sat_to_BTC(result.out.reduce(((a,o)=>a+o.value),0))})))})).catch((error=>reject(error)))}));getTx.hex=txid=>new Promise(((resolve,reject)=>{fetch_api(`rawtx/${txid}?format=hex`,!1).then((result=>resolve(result))).catch((error=>reject(error)))})),btcOperator.getAddressData=address=>new Promise(((resolve,reject)=>{fetch_api(`rawaddr/${address}`).then((data=>{let details={};details.balance=util.Sat_to_BTC(data.final_balance),details.address=data.address,details.txs=data.txs.map((tx=>{let d={txid:tx.hash,time:1e3*tx.time,block:tx.block_height,tx_senders:{}};tx.inputs.forEach((i=>{i.prev_out.addr in d.tx_senders?d.tx_senders[i.prev_out.addr]+=i.prev_out.value:d.tx_senders[i.prev_out.addr]=i.prev_out.value})),d.tx_input_value=0;for(let s in d.tx_senders){let val=d.tx_senders[s];d.tx_senders[s]=util.Sat_to_BTC(val),d.tx_input_value+=val}d.tx_input_value=util.Sat_to_BTC(d.tx_input_value),d.tx_receivers={},tx.out.forEach((o=>{o.addr in d.tx_receivers?d.tx_receivers[o.addr]+=o.value:d.tx_receivers[o.addr]=o.value})),d.tx_output_value=0;for(let r in d.tx_receivers){let val=d.tx_receivers[r];d.tx_receivers[r]=util.Sat_to_BTC(val),d.tx_output_value+=val}return d.tx_output_value=util.Sat_to_BTC(d.tx_output_value),d.tx_fee=util.Sat_to_BTC(tx.fee),tx.result>0?(d.type="in",d.amount=util.Sat_to_BTC(tx.result),d.sender=Object.keys(d.tx_senders).filter((s=>s!==address))):Object.keys(d.tx_receivers).some((r=>r!==address))?(d.type="out",d.amount=util.Sat_to_BTC(-1*tx.result),d.receiver=Object.keys(d.tx_receivers).filter((r=>r!==address)),d.fee=d.tx_fee):(d.type="self",d.amount=d.tx_receivers[address],d.address=address),d})),resolve(details)})).catch((error=>reject(error)))})),btcOperator.getBlock=block=>new Promise(((resolve,reject)=>{fetch_api(`rawblock/${block}`).then((result=>resolve({height:result.height,hash:result.hash,merkle_root:result.mrkl_root,prev_block:result.prev_block,next_block:result.next_block[0],size:result.size,time:1e3*result.time,txs:result.tx.map((t=>Object({fee:t.fee,size:t.size,inputs:t.inputs.map((i=>Object({address:i.prev_out.addr,value:util.Sat_to_BTC(i.prev_out.value)}))),total_input_value:util.Sat_to_BTC(t.inputs.reduce(((a,i)=>a+i.prev_out.value),0)),outputs:t.out.map((o=>Object({address:o.addr,value:util.Sat_to_BTC(o.value)}))),total_output_value:util.Sat_to_BTC(t.out.reduce(((a,o)=>a+o.value),0))})))}))).catch((error=>reject(error)))}))}(); \ No newline at end of file diff --git a/js/compactIDB.min.js b/js/compactIDB.min.js new file mode 100644 index 0000000..db21c75 --- /dev/null +++ b/js/compactIDB.min.js @@ -0,0 +1 @@ +!function(EXPORTS){"use strict";const compactIDB=window.compactIDB={};var defaultDB;const indexedDB=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB,IDBKeyRange=(window.IDBTransaction||window.webkitIDBTransaction||window.msIDBTransaction,window.IDBKeyRange||window.webkitIDBKeyRange||window.msIDBKeyRange);if(!indexedDB)return void console.error("Your browser doesn't support a stable version of IndexedDB.");function upgradeDB(dbName,createList=null,deleteList=null){return new Promise(((resolve,reject)=>{(function(dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{resolve(db.version),db.close()})).catch((error=>reject(error)))}))})(dbName).then((version=>{var idb=indexedDB.open(dbName,version+1);idb.onerror=event=>reject("Error in opening IndexedDB"),idb.onupgradeneeded=event=>{let db=event.target.result;if(createList instanceof Object){if(Array.isArray(createList)){let tmp={};createList.forEach((o=>tmp[o]={})),createList=tmp}for(let o in createList){let obs=db.createObjectStore(o,createList[o].options||{});if(createList[o].indexes instanceof Object)for(let i in createList[o].indexes)obs.createIndex(i,i,createList[o].indexes||{})}}Array.isArray(deleteList)&&deleteList.forEach((o=>db.deleteObjectStore(o))),resolve("Database upgraded")},idb.onsuccess=event=>event.target.result.close()})).catch((error=>reject(error)))}))}compactIDB.setDefaultDB=dbName=>defaultDB=dbName,Object.defineProperty(compactIDB,"default",{get:()=>defaultDB,set:dbName=>defaultDB=dbName}),compactIDB.initDB=function(dbName,objectStores={}){return new Promise(((resolve,reject)=>{if(!(objectStores instanceof Object))return reject("ObjectStores must be an object or array");defaultDB=defaultDB||dbName;var idb=indexedDB.open(dbName);idb.onerror=event=>reject("Error in opening IndexedDB"),idb.onsuccess=event=>{var db=event.target.result;let cList=Object.values(db.objectStoreNames);var obs={},a_obs={},d_obs=[];if(Array.isArray(objectStores))objectStores.forEach((o=>obs[o]={}));else obs=objectStores;let nList=Object.keys(obs);for(let o of nList)cList.includes(o)||(a_obs[o]=obs[o]);for(let o of cList)nList.includes(o)||d_obs.push(o);Object.keys(a_obs).length||d_obs.length?upgradeDB(dbName,a_obs,d_obs).then((result=>resolve(result))).catch((error=>reject(error))):resolve("Initiated IndexedDB"),db.close()}}))};const openDB=compactIDB.openDB=function(dbName=defaultDB){return new Promise(((resolve,reject)=>{var idb=indexedDB.open(dbName);idb.onerror=event=>reject("Error in opening IndexedDB"),idb.onupgradeneeded=event=>{event.target.result.close(),deleteDB(dbName).then((_=>null)).catch((_=>null)).finally((_=>reject("Datebase not found")))},idb.onsuccess=event=>resolve(event.target.result)}))},deleteDB=compactIDB.deleteDB=function(dbName=defaultDB){return new Promise(((resolve,reject)=>{var deleteReq=indexedDB.deleteDatabase(dbName);deleteReq.onerror=event=>reject("Error deleting database!"),deleteReq.onsuccess=event=>resolve("Database deleted successfully")}))};compactIDB.writeData=function(obsName,data,key=!1,dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{var obs=db.transaction(obsName,"readwrite").objectStore(obsName);let writeReq=key?obs.put(data,key):obs.put(data);writeReq.onsuccess=evt=>resolve("Write data Successful"),writeReq.onerror=evt=>reject(`Write data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`),db.close()})).catch((error=>reject(error)))}))},compactIDB.addData=function(obsName,data,key=!1,dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{var obs=db.transaction(obsName,"readwrite").objectStore(obsName);let addReq=key?obs.add(data,key):obs.add(data);addReq.onsuccess=evt=>resolve("Add data successful"),addReq.onerror=evt=>reject(`Add data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`),db.close()})).catch((error=>reject(error)))}))},compactIDB.removeData=function(obsName,key,dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{let delReq=db.transaction(obsName,"readwrite").objectStore(obsName).delete(key);delReq.onsuccess=evt=>resolve(`Removed Data ${key}`),delReq.onerror=evt=>reject(`Remove data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`),db.close()})).catch((error=>reject(error)))}))},compactIDB.clearData=function(obsName,dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{let clearReq=db.transaction(obsName,"readwrite").objectStore(obsName).clear();clearReq.onsuccess=evt=>resolve("Clear data Successful"),clearReq.onerror=evt=>reject("Clear data Unsuccessful"),db.close()})).catch((error=>reject(error)))}))},compactIDB.readData=function(obsName,key,dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{let getReq=db.transaction(obsName,"readonly").objectStore(obsName).get(key);getReq.onsuccess=evt=>resolve(evt.target.result),getReq.onerror=evt=>reject(`Read data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`),db.close()})).catch((error=>reject(error)))}))},compactIDB.readAllData=function(obsName,dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{var obs=db.transaction(obsName,"readonly").objectStore(obsName),tmpResult={};let curReq=obs.openCursor();curReq.onsuccess=evt=>{var cursor=evt.target.result;cursor?(tmpResult[cursor.primaryKey]=cursor.value,cursor.continue()):resolve(tmpResult)},curReq.onerror=evt=>reject(`Read-All data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`),db.close()})).catch((error=>reject(error)))}))},compactIDB.searchData=function(obsName,options={},dbName=defaultDB){return options.lowerKey=options.atKey||options.lowerKey||0,options.upperKey=options.atKey||options.upperKey||!1,options.patternEval=options.patternEval||((k,v)=>!0),options.limit=options.limit||!1,options.reverse=options.reverse||!1,options.lastOnly=options.lastOnly||!1,new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{var obs=db.transaction(obsName,"readonly").objectStore(obsName),filteredResult={};let curReq=obs.openCursor(options.upperKey?IDBKeyRange.bound(options.lowerKey,options.upperKey):IDBKeyRange.lowerBound(options.lowerKey),options.lastOnly||options.reverse?"prev":"next");curReq.onsuccess=evt=>{var cursor=evt.target.result;if(!cursor||options.limit&&options.limit<=Object.keys(filteredResult).length)return resolve(filteredResult);options.patternEval(cursor.primaryKey,cursor.value)?(filteredResult[cursor.primaryKey]=cursor.value,options.lastOnly?resolve(filteredResult):cursor.continue()):cursor.continue()},curReq.onerror=evt=>reject(`Search unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`),db.close()})).catch((error=>reject(error)))}))}}(); \ No newline at end of file diff --git a/js/components.min.js b/js/components.min.js index 90e7ec1..768e628 100644 --- a/js/components.min.js +++ b/js/components.min.js @@ -1,5 +1,6 @@ -const smCopy = document.createElement("template"); smCopy.innerHTML = '\n\n
\n

\n \n
\n', customElements.define("sm-copy", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smCopy.content.cloneNode(!0)), this.copyContent = this.shadowRoot.querySelector(".copy-content"), this.copyButton = this.shadowRoot.querySelector(".copy-button"), this.copy = this.copy.bind(this) } static get observedAttributes() { return ["value"] } set value(n) { this.setAttribute("value", n) } get value() { return this.getAttribute("value") } fireEvent() { this.dispatchEvent(new CustomEvent("copy", { composed: !0, bubbles: !0, cancelable: !0 })) } copy() { navigator.clipboard.writeText(this.copyContent.textContent).then(n => this.fireEvent()).catch(n => console.error(n)) } connectedCallback() { this.copyButton.addEventListener("click", this.copy) } attributeChangedCallback(n, t, o) { "value" === n && (this.copyContent.textContent = o) } disconnectedCallback() { this.copyButton.removeEventListener("click", this.copy) } }); -const smInput = document.createElement("template"); smInput.innerHTML = '\n \n
\n \n \n \n
\n ', customElements.define("sm-input", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smInput.content.cloneNode(!0)), this.inputParent = this.shadowRoot.querySelector(".input"), this.input = this.shadowRoot.querySelector("input"), this.clearBtn = this.shadowRoot.querySelector(".clear"), this.label = this.shadowRoot.querySelector(".label"), this.feedbackText = this.shadowRoot.querySelector(".feedback-text"), this.outerContainer = this.shadowRoot.querySelector(".outer-container"), this.optionList = this.shadowRoot.querySelector(".datalist"), this._helperText = "", this._errorText = "", this.isRequired = !1, this.datalist = [], this.validationFunction = void 0, this.reflectedAttributes = ["value", "required", "disabled", "type", "inputmode", "readonly", "min", "max", "pattern", "minlength", "maxlength", "step", "list", "autocomplete"], this.reset = this.reset.bind(this), this.clear = this.clear.bind(this), this.focusIn = this.focusIn.bind(this), this.focusOut = this.focusOut.bind(this), this.fireEvent = this.fireEvent.bind(this), this.checkInput = this.checkInput.bind(this), this.allowOnlyNum = this.allowOnlyNum.bind(this), this.handleOptionClick = this.handleOptionClick.bind(this), this.handleInputNavigation = this.handleInputNavigation.bind(this), this.handleDatalistNavigation = this.handleDatalistNavigation.bind(this), this.handleFocus = this.handleFocus.bind(this), this.handleBlur = this.handleBlur.bind(this) } static get observedAttributes() { return ["value", "placeholder", "required", "disabled", "type", "inputmode", "readonly", "min", "max", "pattern", "minlength", "maxlength", "step", "helper-text", "error-text", "list"] } get value() { return this.input.value } set value(t) { t !== this.input.value && (this.input.value = t, this.checkInput()) } get placeholder() { return this.getAttribute("placeholder") } set placeholder(t) { this.setAttribute("placeholder", t) } get type() { return this.getAttribute("type") } set type(t) { this.setAttribute("type", t) } get validity() { return this.input.validity } get disabled() { return this.hasAttribute("disabled") } set disabled(t) { t ? this.inputParent.classList.add("disabled") : this.inputParent.classList.remove("disabled") } get readOnly() { return this.hasAttribute("readonly") } set readOnly(t) { t ? this.setAttribute("readonly", "") : this.removeAttribute("readonly") } set customValidation(t) { this.validationFunction = t } set errorText(t) { this._errorText = t } set helperText(t) { this._helperText = t } get isValid() { if ("" !== this.input.value) { const t = this.input.checkValidity(); let e = !0; return this.validationFunction && (e = Boolean(this.validationFunction(this.input.value))), t && e ? (this.feedbackText.classList.remove("error"), this.feedbackText.classList.add("success"), this.feedbackText.textContent = "") : this._errorText && (this.feedbackText.classList.add("error"), this.feedbackText.classList.remove("success"), this.feedbackText.innerHTML = `\n \n ${this._errorText}`), t && e } } reset() { this.value = "" } clear() { this.value = "", this.input.focus(), this.fireEvent() } focusIn() { this.input.focus() } focusOut() { this.input.blur() } fireEvent() { let t = new Event("input", { bubbles: !0, cancelable: !0, composed: !0 }); this.dispatchEvent(t) } searchDatalist(t) { const e = this.datalist.filter(e => e.toLowerCase().includes(t.toLowerCase())); if (e.sort((e, n) => { const i = e.toLowerCase().indexOf(t.toLowerCase()), s = n.toLowerCase().indexOf(t.toLowerCase()); return i - s }), e.length) { if (this.optionList.children.length > e.length) { const t = this.optionList.children.length - e.length; for (let e = 0; e < t; e++)this.optionList.removeChild(this.optionList.lastChild) } e.forEach((t, e) => { if (this.optionList.children[e]) this.optionList.children[e].textContent = t; else { const e = document.createElement("li"); e.textContent = t, e.classList.add("datalist-item"), e.setAttribute("tabindex", "0"), this.optionList.appendChild(e) } }), this.optionList.classList.remove("hidden") } else this.optionList.classList.add("hidden") } checkInput(t) { this.hasAttribute("readonly") || ("" !== this.input.value ? this.clearBtn.classList.remove("hidden") : this.clearBtn.classList.add("hidden")), this.hasAttribute("placeholder") && "" !== this.getAttribute("placeholder").trim() && ("" !== this.input.value ? (this.animate ? this.inputParent.classList.add("animate-placeholder") : this.label.classList.add("hidden"), this.datalist.length && (this.searchTimeout && clearTimeout(this.searchTimeout), this.searchTimeout = setTimeout(() => { this.searchDatalist(this.input.value.trim()) }, 100))) : (this.animate ? this.inputParent.classList.remove("animate-placeholder") : this.label.classList.remove("hidden"), this.feedbackText.textContent = "", this.datalist.length && (this.optionList.innerHTML = "", this.optionList.classList.add("hidden")))) } allowOnlyNum(t) { 1 === t.key.length && (("." !== t.key || !t.target.value.includes(".") && 0 !== t.target.value.length) && ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."].includes(t.key) || t.preventDefault()) } handleOptionClick(t) { this.input.value = t.target.textContent, this.optionList.classList.add("hidden"), this.input.focus() } handleInputNavigation(t) { "ArrowDown" === t.key ? (t.preventDefault(), this.optionList.children.length && this.optionList.children[0].focus()) : "ArrowUp" === t.key && (t.preventDefault(), this.optionList.children.length && this.optionList.children[this.optionList.children.length - 1].focus()) } handleDatalistNavigation(t) { "ArrowUp" === t.key ? (t.preventDefault(), this.shadowRoot.activeElement.previousElementSibling ? this.shadowRoot.activeElement.previousElementSibling.focus() : this.input.focus()) : "ArrowDown" === t.key ? (t.preventDefault(), this.shadowRoot.activeElement.nextElementSibling ? this.shadowRoot.activeElement.nextElementSibling.focus() : this.input.focus()) : "Enter" !== t.key && " " !== t.key || (t.preventDefault(), this.input.value = t.target.textContent, this.optionList.classList.add("hidden"), this.input.focus()) } handleFocus(t) { this.datalist.length && this.searchDatalist(this.input.value.trim()) } handleBlur(t) { this.datalist.length && this.optionList.classList.add("hidden") } connectedCallback() { this.animate = this.hasAttribute("animate"), this.setAttribute("role", "textbox"), this.input.addEventListener("input", this.checkInput), this.clearBtn.addEventListener("click", this.clear), this.datalist.length && (this.optionList.addEventListener("click", this.handleOptionClick), this.input.addEventListener("keydown", this.handleInputNavigation), this.optionList.addEventListener("keydown", this.handleDatalistNavigation)), this.input.addEventListener("focusin", this.handleFocus), this.addEventListener("focusout", this.handleBlur) } attributeChangedCallback(t, e, n) { e !== n && (this.reflectedAttributes.includes(t) && (this.hasAttribute(t) ? this.input.setAttribute(t, this.getAttribute(t) ? this.getAttribute(t) : "") : this.input.removeAttribute(t)), "placeholder" === t ? (this.label.textContent = n, this.setAttribute("aria-label", n)) : this.hasAttribute("value") ? this.checkInput() : "type" === t ? this.hasAttribute("type") && "number" === this.getAttribute("type") ? (this.input.setAttribute("inputmode", "decimal"), this.input.addEventListener("keydown", this.allowOnlyNum)) : this.input.removeEventListener("keydown", this.allowOnlyNum) : "helper-text" === t ? this._helperText = this.getAttribute("helper-text") : "error-text" === t ? this._errorText = this.getAttribute("error-text") : "required" === t ? (this.isRequired = this.hasAttribute("required"), this.isRequired ? this.setAttribute("aria-required", "true") : this.setAttribute("aria-required", "false")) : "readonly" === t ? this.hasAttribute("readonly") ? this.inputParent.classList.add("readonly") : this.inputParent.classList.remove("readonly") : "disabled" === t ? this.hasAttribute("disabled") ? this.inputParent.classList.add("disabled") : this.inputParent.classList.remove("disabled") : "list" === t && this.hasAttribute("list") && "" !== this.getAttribute("list").trim() && (this.datalist = this.getAttribute("list").split(","))) } disconnectedCallback() { this.input.removeEventListener("input", this.checkInput), this.clearBtn.removeEventListener("click", this.clear), this.input.removeEventListener("keydown", this.allowOnlyNum), this.optionList.removeEventListener("click", this.handleOptionClick), this.input.removeEventListener("keydown", this.handleInputNavigation), this.optionList.removeEventListener("keydown", this.handleDatalistNavigation), this.input.removeEventListener("focusin", this.handleFocus), this.removeEventListener("focusout", this.handleBlur) } }); -const smNotifications = document.createElement("template"); smNotifications.innerHTML = '\n \n
\n ', customElements.define("sm-notifications", class extends HTMLElement { constructor() { super(), this.shadow = this.attachShadow({ mode: "open" }).append(smNotifications.content.cloneNode(!0)), this.notificationPanel = this.shadowRoot.querySelector(".notification-panel"), this.animationOptions = { duration: 300, fill: "forwards", easing: "cubic-bezier(0.175, 0.885, 0.32, 1.275)" }, this.push = this.push.bind(this), this.createNotification = this.createNotification.bind(this), this.removeNotification = this.removeNotification.bind(this), this.clearAll = this.clearAll.bind(this), this.remove = this.remove.bind(this), this.handlePointerMove = this.handlePointerMove.bind(this), this.startX = 0, this.currentX = 0, this.endX = 0, this.swipeDistance = 0, this.swipeDirection = "", this.swipeThreshold = 0, this.startTime = 0, this.swipeTime = 0, this.swipeTimeThreshold = 200, this.currentTarget = null, this.mediaQuery = window.matchMedia("(min-width: 640px)"), this.handleOrientationChange = this.handleOrientationChange.bind(this), this.isLandscape = !1 } randString(n) { let t = ""; const i = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; for (let e = 0; e < n; e++)t += i.charAt(Math.floor(Math.random() * i.length)); return t } createNotification(n, t = {}) { const { pinned: i = !1, icon: e = "", action: o } = t, r = document.createElement("div"); r.id = this.randString(8), r.classList.add("notification"); let a = ""; return a += `\n
${e}
\n ${n}\n `, o && (a += `\n \n `), i && (r.classList.add("pinned"), a += '\n \n '), r.innerHTML = a, r } push(n, t = {}) { const i = this.createNotification(n, t); return this.isLandscape ? this.notificationPanel.append(i) : this.notificationPanel.prepend(i), this.notificationPanel.animate([{ transform: `translateY(${this.isLandscape ? "" : "-"}${i.clientHeight}px)` }, { transform: "none" }], this.animationOptions), i.animate([{ transform: "translateY(-1rem)", opacity: "0" }, { transform: "none", opacity: "1" }], this.animationOptions).onfinish = (n => { n.target.commitStyles(), n.target.cancel() }), i.querySelector(".action") && i.querySelector(".action").addEventListener("click", t.action.callback), i.id } removeNotification(n, t = "left") { if (!n) return; const i = "left" === t ? "-" : "+"; n.animate([{ transform: this.currentX ? `translateX(${this.currentX}px)` : "none", opacity: "1" }, { transform: `translateX(calc(${i}${Math.abs(this.currentX)}px ${i} 1rem))`, opacity: "0" }], this.animationOptions).onfinish = (() => { n.remove() }) } remove(n) { const t = this.notificationPanel.querySelector(`#${n}`); t && this.removeNotification(t) } clearAll() { Array.from(this.notificationPanel.children).forEach(n => { this.removeNotification(n) }) } handlePointerMove(n) { this.currentX = n.clientX - this.startX, this.currentTarget.style.transform = `translateX(${this.currentX}px)` } handleOrientationChange(n) { this.isLandscape = n.matches, n.matches } connectedCallback() { this.handleOrientationChange(this.mediaQuery), this.mediaQuery.addEventListener("change", this.handleOrientationChange), this.notificationPanel.addEventListener("pointerdown", n => { n.target.closest(".close") ? this.removeNotification(n.target.closest(".notification")) : n.target.closest(".notification") && (this.swipeThreshold = n.target.closest(".notification").getBoundingClientRect().width / 2, this.currentTarget = n.target.closest(".notification"), this.currentTarget.setPointerCapture(n.pointerId), this.startTime = Date.now(), this.startX = n.clientX, this.startY = n.clientY, this.notificationPanel.addEventListener("pointermove", this.handlePointerMove)) }), this.notificationPanel.addEventListener("pointerup", n => { this.endX = n.clientX, this.endY = n.clientY, this.swipeDistance = Math.abs(this.endX - this.startX), this.swipeTime = Date.now() - this.startTime, this.endX > this.startX ? this.swipeDirection = "right" : this.swipeDirection = "left", this.swipeTime < this.swipeTimeThreshold ? this.swipeDistance > 50 && this.removeNotification(this.currentTarget, this.swipeDirection) : this.swipeDistance > this.swipeThreshold ? this.removeNotification(this.currentTarget, this.swipeDirection) : this.currentTarget.animate([{ transform: `translateX(${this.currentX}px)` }, { transform: "none" }], this.animationOptions).onfinish = (n => { n.target.commitStyles(), n.target.cancel() }), this.notificationPanel.removeEventListener("pointermove", this.handlePointerMove), this.notificationPanel.releasePointerCapture(n.pointerId), this.currentX = 0 }); const n = new MutationObserver(n => { n.forEach(n => { "childList" === n.type && n.addedNodes.length && !n.addedNodes[0].classList.contains("pinned") && setTimeout(() => { this.removeNotification(n.addedNodes[0]) }, 5e3) }) }); n.observe(this.notificationPanel, { childList: !0 }) } disconnectedCallback() { mediaQueryList.removeEventListener("change", handleOrientationChange) } }); -const spinner = document.createElement("template"); spinner.innerHTML = '\n\n\n\n'; class SpinnerLoader extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(spinner.content.cloneNode(!0)) } } window.customElements.define("sm-spinner", SpinnerLoader); -const themeToggle = document.createElement("template"); themeToggle.innerHTML = '\n \n \n'; class ThemeToggle extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(themeToggle.content.cloneNode(!0)), this.isChecked = !1, this.hasTheme = "light", this.toggleState = this.toggleState.bind(this), this.fireEvent = this.fireEvent.bind(this), this.handleThemeChange = this.handleThemeChange.bind(this) } static get observedAttributes() { return ["checked"] } daylight() { this.hasTheme = "light", document.body.dataset.theme = "light", this.setAttribute("aria-checked", "false") } nightlight() { this.hasTheme = "dark", document.body.dataset.theme = "dark", this.setAttribute("aria-checked", "true") } toggleState() { this.toggleAttribute("checked"), this.fireEvent() } handleKeyDown(e) { " " === e.key && this.toggleState() } handleThemeChange(e) { e.detail.theme !== this.hasTheme && ("dark" === e.detail.theme ? this.setAttribute("checked", "") : this.removeAttribute("checked")) } fireEvent() { this.dispatchEvent(new CustomEvent("themechange", { bubbles: !0, composed: !0, detail: { theme: this.hasTheme } })) } connectedCallback() { this.setAttribute("role", "switch"), this.setAttribute("aria-label", "theme toggle"), "dark" === localStorage.getItem(`${window.location.hostname}-theme`) ? (this.nightlight(), this.setAttribute("checked", "")) : "light" === localStorage.getItem(`${window.location.hostname}-theme`) ? (this.daylight(), this.removeAttribute("checked")) : window.matchMedia("(prefers-color-scheme: dark)").matches ? (this.nightlight(), this.setAttribute("checked", "")) : (this.daylight(), this.removeAttribute("checked")), this.addEventListener("click", this.toggleState), this.addEventListener("keydown", this.handleKeyDown), document.addEventListener("themechange", this.handleThemeChange) } disconnectedCallback() { this.removeEventListener("click", this.toggleState), this.removeEventListener("keydown", this.handleKeyDown), document.removeEventListener("themechange", this.handleThemeChange) } attributeChangedCallback(e, t, n) { "checked" === e && (this.hasAttribute("checked") ? (this.nightlight(), localStorage.setItem(`${window.location.hostname}-theme`, "dark")) : (this.daylight(), localStorage.setItem(`${window.location.hostname}-theme`, "light"))) } } window.customElements.define("theme-toggle", ThemeToggle); \ No newline at end of file +// Components downloaded: copy,input,notifications,spinner,theme-toggle +const smCopy = document.createElement("template"); smCopy.innerHTML = '

', customElements.define("sm-copy", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smCopy.content.cloneNode(!0)), this.copyContent = this.shadowRoot.querySelector(".copy-content"), this.copyButton = this.shadowRoot.querySelector(".copy-button"), this.copy = this.copy.bind(this) } static get observedAttributes() { return ["value"] } set value(val) { this.setAttribute("value", val) } get value() { return this.getAttribute("value") } fireEvent() { this.dispatchEvent(new CustomEvent("copy", { composed: !0, bubbles: !0, cancelable: !0 })) } copy() { navigator.clipboard.writeText(this.getAttribute("value")).then((res => this.fireEvent())).catch((err => console.error(err))) } connectedCallback() { this.copyButton.addEventListener("click", this.copy) } attributeChangedCallback(name, oldValue, newValue) { if ("value" === name) { const slot = this.copyContent.querySelector("slot"); if (!slot) return; const assignedNodes = slot.assignedNodes(); assignedNodes && assignedNodes.length || (slot.textContent = newValue) } } disconnectedCallback() { this.copyButton.removeEventListener("click", this.copy) } }); +const smInput = document.createElement("template"); smInput.innerHTML = '
', customElements.define("sm-input", class SmInput extends HTMLElement { static hasAppendedStyles = !1; #validationState = { validatedFor: void 0, isValid: !1, errorMessage: "Please fill out this field." }; constructor() { super(), this.attachShadow({ mode: "open" }).append(smInput.content.cloneNode(!0)), this.inputParent = this.shadowRoot.querySelector(".input"), this.input = this.shadowRoot.querySelector("input"), this.clearBtn = this.shadowRoot.querySelector(".clear"), this.placeholderElement = this.shadowRoot.querySelector(".placeholder"), this.outerContainer = this.shadowRoot.querySelector(".outer-container"), this.optionList = this.shadowRoot.querySelector(".datalist"), this._helperText = "", this.isRequired = !1, this.datalist = [], this.validationFunction = void 0, this.reflectedAttributes = ["value", "required", "disabled", "type", "inputmode", "readonly", "min", "max", "pattern", "minlength", "maxlength", "step", "list", "autocomplete"] } static get observedAttributes() { return ["value", "placeholder", "required", "disabled", "type", "inputmode", "readonly", "min", "max", "pattern", "minlength", "maxlength", "step", "helper-text", "error-text", "list"] } get value() { return this.input.value } set value(val) { val !== this.input.value && (this.input.value = val, this._value = val, this.checkInput()) } get placeholder() { return this.getAttribute("placeholder") } set placeholder(val) { this.setAttribute("placeholder", val) } get type() { return this.getAttribute("type") } set type(val) { this.setAttribute("type", val) } get validity() { return this.input.validity } get disabled() { return this.hasAttribute("disabled") } set disabled(value) { value ? (this.inputParent.classList.add("disabled"), this.setAttribute("disabled", "")) : (this.inputParent.classList.remove("disabled"), this.removeAttribute("disabled")) } get readOnly() { return this.hasAttribute("readonly") } set readOnly(value) { value ? this.setAttribute("readonly", "") : this.removeAttribute("readonly") } set customValidation(val) { val && (this.validationFunction = val) } set errorText(val) { this.#validationState.errorText = val } showError = (errorText = this.#validationState.errorText) => { const appendedNew = this.appendFeedbackElement(); this.feedbackPopover.innerHTML = ` ${errorText} `, this.feedbackPopover.dataset.state = "error", appendedNew && this.feedbackPopover.animate([{ transform: "scale(0.95)", opacity: 0 }, { transform: "scale(1)", opacity: 1 }], { duration: 200, easing: "ease", fill: "forwards" }) }; set helperText(val) { this._helperText = val } get isValid() { if (this.#validationState.validatedFor === this.input.value) return this.#validationState.isValid; const _isValid = this.input.checkValidity(); let _validity = { isValid: !0, errorText: "" }; return this.validationFunction && (_validity = this.validationFunction(this.input.value, this)), _isValid && _validity.isValid ? (this.setAttribute("valid", ""), this.removeAttribute("invalid"), this.hideFeedback()) : (this.removeAttribute("valid"), this.setAttribute("invalid", ""), "" !== this.value.trim() && (_validity.errorText || this.#validationState.errorText) && this.showError(_validity.errorText || this.#validationState.errorText)), this.#validationState.validatedFor = this.input.value, this.#validationState.isValid = _isValid && _validity.isValid, this.#validationState.errorText = _validity.errorText || this.#validationState.errorText, this.#validationState.isValid } reset = () => { this.value = "" }; clear = () => { this.value = "", this.input.focus(), this.fireEvent(), this.hideFeedback() }; focusIn = () => { this.input.focus() }; focusOut = () => { this.input.blur() }; fireEvent = () => { let event = new Event("input", { bubbles: !0, cancelable: !0, composed: !0 }); this.dispatchEvent(event) }; searchDatalist = searchKey => { const filteredData = this.datalist.filter((item => item.toLowerCase().includes(searchKey.toLowerCase()))); if (filteredData.sort(((a, b) => a.toLowerCase().indexOf(searchKey.toLowerCase()) - b.toLowerCase().indexOf(searchKey.toLowerCase()))), filteredData.length) { if (this.optionList.children.length > filteredData.length) { const optionsToRemove = this.optionList.children.length - filteredData.length; for (let i = 0; i < optionsToRemove; i++)this.optionList.removeChild(this.optionList.lastChild) } filteredData.forEach(((item, index) => { if (this.optionList.children[index]) this.optionList.children[index].textContent = item; else { const option = document.createElement("li"); option.textContent = item, option.classList.add("datalist-item"), option.setAttribute("tabindex", "0"), this.optionList.appendChild(option) } })), this.optionList.classList.remove("hidden") } else this.optionList.classList.add("hidden") }; checkInput = e => { this.hasAttribute("readonly") || ("" !== this.input.value ? this.clearBtn.classList.remove("hidden") : this.clearBtn.classList.add("hidden")), this.hasAttribute("placeholder") && "" !== this.getAttribute("placeholder").trim() && ("" !== this.input.value ? (this.shouldAnimatePlaceholder && this.inputParent.classList.add("animate-placeholder"), this.placeholderElement.classList.toggle("hidden", !this.shouldAnimatePlaceholder), this.datalist.length && (this.searchTimeout && clearTimeout(this.searchTimeout), this.searchTimeout = setTimeout((() => { this.searchDatalist(this.input.value.trim()) }), 100))) : (this.shouldAnimatePlaceholder && this.inputParent.classList.remove("animate-placeholder"), this.placeholderElement.classList.remove("hidden"), this.hideFeedback(), this.datalist.length && (this.optionList.innerHTML = "", this.optionList.classList.add("hidden")))) }; allowOnlyNum = e => { e.ctrlKey || 1 === e.key.length && (("." !== e.key || !e.target.value.includes(".") && 0 !== e.target.value.length) && ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."].includes(e.key) || e.preventDefault()) }; handleOptionClick = e => { this.input.value = e.target.textContent, this.optionList.classList.add("hidden"), this.input.focus() }; handleInputNavigation = e => { "ArrowDown" === e.key ? (e.preventDefault(), this.optionList.children.length && this.optionList.children[0].focus()) : "ArrowUp" === e.key && (e.preventDefault(), this.optionList.children.length && this.optionList.children[this.optionList.children.length - 1].focus()) }; handleDatalistNavigation = e => { "ArrowUp" === e.key ? (e.preventDefault(), this.shadowRoot.activeElement.previousElementSibling ? this.shadowRoot.activeElement.previousElementSibling.focus() : this.input.focus()) : "ArrowDown" === e.key ? (e.preventDefault(), this.shadowRoot.activeElement.nextElementSibling ? this.shadowRoot.activeElement.nextElementSibling.focus() : this.input.focus()) : "Enter" !== e.key && " " !== e.key || (e.preventDefault(), this.input.value = e.target.textContent, this.optionList.classList.add("hidden"), this.input.focus()) }; handleFocus = e => { this.datalist.length && this.searchDatalist(this.input.value.trim()) }; handleBlur = e => { "" === this.input.value.trim() && this.hideFeedback(), this.datalist.length && this.optionList.classList.add("hidden") }; applyGlobalCustomValidation = () => { if (void 0 !== window.smCompConfig && window.smCompConfig["sm-input"]) { const config = window.smCompConfig["sm-input"].find((config => this.matches(config.selector))); this.customValidation = config?.customValidation } }; updatePosition = () => { requestAnimationFrame((() => { if (this.dimensions = this.getBoundingClientRect(), this.scrollingParentDimensions = this.scrollingParent.getBoundingClientRect(), 0 === this.dimensions.width || 0 === this.dimensions.height) return; let topOffset = this.dimensions.top - this.scrollingParentDimensions.top + this.dimensions.height, leftOffset = this.dimensions.left - this.scrollingParentDimensions.left; const maxWidth = this.dimensions.width; this.feedbackPopover.style = `top: ${topOffset}px; left: ${leftOffset}px; max-width: ${maxWidth}px;` })) }; appendFeedbackElement = () => { if (this.feedbackPopover) return !1; this.feedbackPopover = document.createElement("div"), this.feedbackPopover.className = "feedback-popover", this.feedbackPopover.setAttribute("aria-live", "polite"), this.containment = this.closest("[data-sm-containment]"), this.scrollingParent = this.getNearestScrollingParent(this); return (this.containment || this.scrollingParent).appendChild(this.feedbackPopover), "" === this.scrollingParent.style.position && (this.scrollingParent.style.position = "relative"), this.containment || (this.observerHidFeedback = !1, this.intersectionObserver = new IntersectionObserver((entries => { if (this.feedbackPopover) if (entries[0].isIntersecting) { if (!this.observerHidFeedback) return; this.feedbackPopover.classList.remove("hidden"), this.observerHidFeedback = !1 } else this.feedbackPopover.classList.add("hidden"), this.observerHidFeedback = !0 })).observe(this)), this.updatePosition(), window.addEventListener("resize", this.updatePosition, { passive: !0 }), !0 }; getNearestScrollingParent = element => { let parent = element.parentNode; for (; parent;) { if (parent.scrollHeight > parent.clientHeight || parent.scrollWidth > parent.clientWidth || parent.tagName.includes("SM-") || parent.hasAttribute("data-scrollable")) return parent; parent = parent.parentNode } return document.body }; hideFeedback = () => { this.feedbackPopover && (this.feedbackPopover.animate([{ transform: "none", opacity: 1 }, { transform: "scale(0.95)", opacity: 0 }], { duration: 100, easing: "ease-in-out", fill: "forwards" }).onfinish = () => { this.intersectionObserver?.disconnect(), this.feedbackPopover && (this.feedbackPopover.remove(), this.feedbackPopover = null), window.removeEventListener("resize", this.updatePosition, { passive: !0 }) }) }; connectedCallback() { SmInput.hasAppendedStyles || (document.head.insertAdjacentHTML("beforeend", ""), SmInput.hasAppendedStyles = !0), this.shouldAnimatePlaceholder = this.hasAttribute("animate"), this.shouldAnimatePlaceholder && "" !== this.placeholderElement && this.value && (this.inputParent.classList.add("animate-placeholder"), this.placeholderElement.classList.remove("hidden")), this.setAttribute("role", "textbox"), "loading" === document.readyState ? window.addEventListener("load", this.applyGlobalCustomValidation, { once: !0 }) : this.applyGlobalCustomValidation(), this.input.addEventListener("input", this.checkInput), this.clearBtn.addEventListener("click", this.clear), this.datalist.length && (this.optionList.addEventListener("click", this.handleOptionClick), this.input.addEventListener("keydown", this.handleInputNavigation), this.optionList.addEventListener("keydown", this.handleDatalistNavigation)), this.input.addEventListener("focusin", this.handleFocus), this.addEventListener("focusout", this.handleBlur) } attributeChangedCallback(name, oldValue, newValue) { if (oldValue !== newValue) switch (this.reflectedAttributes.includes(name) && (this.hasAttribute(name) ? this.input.setAttribute(name, this.getAttribute(name) ? this.getAttribute(name) : "") : this.input.removeAttribute(name)), name) { case "placeholder": this.placeholderElement.textContent = newValue, this.setAttribute("aria-label", newValue); break; case "value": this.checkInput(); break; case "type": this.hasAttribute("type") && "number" === this.getAttribute("type") ? (this.input.setAttribute("inputmode", "decimal"), this.input.addEventListener("keydown", this.allowOnlyNum)) : this.input.removeEventListener("keydown", this.allowOnlyNum); break; case "helper-text": this._helperText = newValue; break; case "error-text": this.#validationState.errorText = newValue; break; case "required": this.isRequired = this.hasAttribute("required"), this.isRequired ? this.setAttribute("aria-required", "true") : this.setAttribute("aria-required", "false"); break; case "readonly": this.hasAttribute("readonly") ? this.inputParent.classList.add("readonly") : this.inputParent.classList.remove("readonly"); break; case "disabled": this.hasAttribute("disabled") ? this.inputParent.classList.add("disabled") : this.inputParent.classList.remove("disabled"); break; case "list": this.hasAttribute("list") && "" !== this.getAttribute("list").trim() && (this.datalist = this.getAttribute("list").split(",")) } } disconnectedCallback() { this.input.removeEventListener("input", this.checkInput), this.clearBtn.removeEventListener("click", this.clear), this.input.removeEventListener("keydown", this.allowOnlyNum), this.optionList.removeEventListener("click", this.handleOptionClick), this.input.removeEventListener("keydown", this.handleInputNavigation), this.optionList.removeEventListener("keydown", this.handleDatalistNavigation), this.input.removeEventListener("focusin", this.handleFocus), this.removeEventListener("focusout", this.handleBlur), window.removeEventListener("resize", this.updatePosition, { passive: !0 }), this.feedbackPopover && this.feedbackPopover.remove(), this.intersectionObserver && this.intersectionObserver.disconnect() } }); +const smNotifications = document.createElement("template"); smNotifications.innerHTML = "
", customElements.define("sm-notifications", class extends HTMLElement { constructor() { super(), this.shadow = this.attachShadow({ mode: "open" }).append(smNotifications.content.cloneNode(!0)), this.notificationPanel = this.shadowRoot.querySelector(".notification-panel"), this.animationOptions = { duration: 300, fill: "forwards", easing: "cubic-bezier(0.175, 0.885, 0.32, 1.275)" }, this.push = this.push.bind(this), this.createNotification = this.createNotification.bind(this), this.removeNotification = this.removeNotification.bind(this), this.clearAll = this.clearAll.bind(this), this.remove = this.remove.bind(this), this.handleTouchMove = this.handleTouchMove.bind(this), this.startX = 0, this.currentX = 0, this.endX = 0, this.swipeDistance = 0, this.swipeDirection = "", this.swipeThreshold = 0, this.startTime = 0, this.swipeTime = 0, this.swipeTimeThreshold = 200, this.currentTarget = null, this.notificationTimeout = 5e3, this.mediaQuery = window.matchMedia("(min-width: 640px)"), this.handleOrientationChange = this.handleOrientationChange.bind(this), this.isBigViewport = !1 } set timeout(value) { isNaN(value) || (this.notificationTimeout = value) } randString(length) { let result = ""; const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; for (let i = 0; i < length; i++)result += characters.charAt(Math.floor(52 * Math.random())); return result } createNotification(message, options = {}) { const { pinned: pinned = !1, icon: icon, action: action, timeout: timeout = this.notificationTimeout } = options, notification = document.createElement("div"); return notification.id = this.randString(8), notification.className = "notification " + (pinned ? "pinned" : ""), notification.style.setProperty("--timeout", `${timeout}ms`), notification.innerHTML = ` ${icon ? `
${icon}
` : ""} ${message} ${action ? `` : ""} `, action && notification.querySelector(".action").addEventListener("click", action.callback), notification.querySelector(".close").addEventListener("click", (() => { this.removeNotification(notification) })), pinned || setTimeout((() => { this.removeNotification(notification, this.isBigViewport ? "left" : "top") }), timeout), notification } push(message, options = {}) { const notification = this.createNotification(message, options); return this.isBigViewport ? this.notificationPanel.append(notification) : this.notificationPanel.prepend(notification), notification.scrollIntoView({ behavior: "smooth" }), this.notificationPanel.animate([{ transform: `translateY(${this.isBigViewport ? "" : "-"}${notification.clientHeight}px)` }, { transform: "none" }], this.animationOptions), notification.animate([{ transform: "translateY(-1rem)", opacity: "0" }, { transform: "none", opacity: "1" }], this.animationOptions).onfinish = e => { e.target.commitStyles(), e.target.cancel() }, notification.id } removeNotification(notification, direction = "left") { if (!notification) return; const sign = "left" === direction || "top" === direction ? "-" : "+"; this.isBigViewport || "top" !== direction ? notification.animate([{ transform: this.currentX ? `translateX(${this.currentX}px)` : "none", opacity: "1" }, { transform: `translateX(calc(${sign}${Math.abs(this.currentX)}px ${sign} 1rem))`, opacity: "0" }], this.animationOptions).onfinish = () => { notification.remove() } : notification.animate([{ transform: this.currentX ? `translateY(${this.currentX}px)` : "none", opacity: "1" }, { transform: `translateY(calc(${sign}${Math.abs(this.currentX)}px ${sign} 1rem))`, opacity: "0" }], this.animationOptions).onfinish = () => { notification.remove() } } remove(id) { const notification = this.notificationPanel.querySelector(`#${id}`); notification && this.removeNotification(notification) } clearAll() { Array.from(this.notificationPanel.children).forEach((child => { this.removeNotification(child) })) } handleTouchMove(e) { this.currentX = e.touches[0].clientX - this.startX, this.currentTarget.style.transform = `translateX(${this.currentX}px)` } handleOrientationChange(e) { this.isBigViewport = e.matches, e.matches } connectedCallback() { this.handleOrientationChange(this.mediaQuery), this.mediaQuery.addEventListener("change", this.handleOrientationChange), this.notificationPanel.addEventListener("touchstart", (e => { e.target.closest(".close") ? this.removeNotification(e.target.closest(".notification")) : e.target.closest(".notification") && (this.swipeThreshold = e.target.closest(".notification").getBoundingClientRect().width / 2, this.currentTarget = e.target.closest(".notification"), this.startTime = Date.now(), this.startX = e.touches[0].clientX, this.startY = e.touches[0].clientY, this.notificationPanel.addEventListener("touchmove", this.handleTouchMove, { passive: !0 })) }), { passive: !0 }), this.notificationPanel.addEventListener("touchend", (e => { this.endX = e.changedTouches[0].clientX, this.endY = e.changedTouches[0].clientY, this.swipeDistance = Math.abs(this.endX - this.startX), this.swipeTime = Date.now() - this.startTime, this.endX > this.startX ? this.swipeDirection = "right" : this.swipeDirection = "left", this.swipeTime < this.swipeTimeThreshold ? this.swipeDistance > 50 && this.removeNotification(this.currentTarget, this.swipeDirection) : this.swipeDistance > this.swipeThreshold ? this.removeNotification(this.currentTarget, this.swipeDirection) : this.currentTarget.animate([{ transform: `translateX(${this.currentX}px)` }, { transform: "none" }], this.animationOptions).onfinish = e => { e.target.commitStyles(), e.target.cancel() }, this.notificationPanel.removeEventListener("touchmove", this.handleTouchMove), this.currentX = 0 })) } disconnectedCallback() { mediaQueryList.removeEventListener("change", handleOrientationChange) } }); +const spinner = document.createElement("template"); spinner.innerHTML = ''; class SpinnerLoader extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(spinner.content.cloneNode(!0)) } } window.customElements.define("sm-spinner", SpinnerLoader); +const themeToggle = document.createElement("template"); themeToggle.innerHTML = ' '; class ThemeToggle extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(themeToggle.content.cloneNode(!0)), this.isChecked = !1, this.hasTheme = "light", this.toggleState = this.toggleState.bind(this), this.fireEvent = this.fireEvent.bind(this), this.handleThemeChange = this.handleThemeChange.bind(this) } static get observedAttributes() { return ["checked"] } daylight() { this.hasTheme = "light", document.body.dataset.theme = "light", this.setAttribute("aria-checked", "false") } nightlight() { this.hasTheme = "dark", document.body.dataset.theme = "dark", this.setAttribute("aria-checked", "true") } toggleState() { if (!document.startViewTransition) return this.toggleAttribute("checked"), void this.fireEvent(); document.startViewTransition(() => { this.toggleAttribute("checked"), this.fireEvent() }) } handleKeyDown(e) { " " === e.key && this.toggleState() } handleThemeChange(e) { e.detail.theme !== this.hasTheme && ("dark" === e.detail.theme ? this.setAttribute("checked", "") : this.removeAttribute("checked")) } fireEvent() { this.dispatchEvent(new CustomEvent("themechange", { bubbles: !0, composed: !0, detail: { theme: this.hasTheme } })) } connectedCallback() { this.setAttribute("role", "switch"), this.setAttribute("aria-label", "theme toggle"), "dark" === localStorage.getItem(`${window.location.hostname}-theme`) ? (this.nightlight(), this.setAttribute("checked", "")) : "light" === localStorage.getItem(`${window.location.hostname}-theme`) ? (this.daylight(), this.removeAttribute("checked")) : window.matchMedia("(prefers-color-scheme: dark)").matches ? (this.nightlight(), this.setAttribute("checked", "")) : (this.daylight(), this.removeAttribute("checked")), this.addEventListener("click", this.toggleState), this.addEventListener("keydown", this.handleKeyDown), document.addEventListener("themechange", this.handleThemeChange) } disconnectedCallback() { this.removeEventListener("click", this.toggleState), this.removeEventListener("keydown", this.handleKeyDown), document.removeEventListener("themechange", this.handleThemeChange) } attributeChangedCallback(e, t, n) { "checked" === e && (this.hasAttribute("checked") ? (this.nightlight(), localStorage.setItem(`${window.location.hostname}-theme`, "dark")) : (this.daylight(), localStorage.setItem(`${window.location.hostname}-theme`, "light"))) } } window.customElements.define("theme-toggle", ThemeToggle); \ No newline at end of file diff --git a/js/floBlockchainAPI.js b/js/floBlockchainAPI.js index 4cc37ac..4731fd4 100644 --- a/js/floBlockchainAPI.js +++ b/js/floBlockchainAPI.js @@ -1,4 +1,4 @@ -(function (EXPORTS) { //floBlockchainAPI v3.1.3 +(function (EXPORTS) { //floBlockchainAPI v3.1.4 /* FLO Blockchain Operator to send/receive data from blockchain using API calls via FLO Blockbook*/ 'use strict'; const floBlockchainAPI = EXPORTS; @@ -18,11 +18,11 @@ const SATOSHI_IN_BTC = 1e8; const isUndefined = val => typeof val === 'undefined'; - const torExitNodes = new Set(["185.241.208.232", "194.26.192.64", "171.25.193.25", "80.67.167.81", "192.42.116.187", "198.98.51.189", "89.58.26.216", "109.70.100.4", "149.56.22.133", "5.45.102.93", "178.17.174.14", "192.42.116.196", "185.220.101.4", "45.141.215.62", "94.102.51.15", "192.42.116.213", "107.189.28.166", "185.241.208.243", "45.141.215.80", "193.26.115.61", "192.42.116.175", "149.56.44.47", "107.189.13.91", "87.118.116.103", "178.17.171.102", "185.243.218.110", "192.42.116.208", "89.58.41.156", "2.58.56.43", "104.192.1.138", "45.95.169.184", "107.189.8.56", "176.58.121.177", "185.220.101.31", "45.141.215.200", "109.70.100.1", "185.244.192.175", "185.129.61.2", "144.172.118.41", "192.42.116.184", "45.151.167.10", "185.220.101.27", "91.203.144.194", "45.141.215.88", "179.43.182.232", "185.220.101.5", "109.70.100.2", "107.189.14.4", "94.16.116.81", "185.220.101.8", "185.220.101.12", "88.80.20.86", "23.154.177.15", "45.141.215.56", "5.42.66.6", "23.129.64.225", "104.244.75.74", "45.95.169.228", "37.187.5.192", "45.141.215.169", "109.70.100.66", "45.79.144.222", "185.227.68.78", "179.43.159.199", "2.57.122.246", "192.42.116.201", "185.220.102.248", "195.176.3.23", "45.138.16.42", "216.73.159.75", "185.165.169.239", "23.129.64.213", "109.70.100.6", "45.80.158.27", "45.138.16.240", "178.20.55.16", "192.42.116.173", "51.15.249.160", "192.42.116.200", "185.220.102.254", "45.141.215.63", "193.218.118.151", "192.42.116.211", "185.100.85.24", "185.195.71.12", "107.189.8.181", "193.189.100.199", "109.70.100.69", "185.100.87.250", "31.220.93.201", "89.236.112.100", "45.141.215.90", "185.35.202.222", "109.70.100.65", "95.142.161.63", "192.42.116.181", "192.42.116.23", "194.26.192.77", "193.189.100.198", "180.150.226.99", "23.129.64.227", "107.189.4.23", "45.141.215.235", "185.220.102.252", "109.70.100.67", "185.220.100.255", "185.220.101.21", "185.100.85.22", "128.31.0.13", "46.182.21.248", "192.42.116.174", "185.241.208.115", "185.220.101.1", "192.42.116.202", "45.141.215.97", "185.243.218.204", "78.142.18.219", "192.42.116.192", "190.120.229.98", "192.42.116.177", "45.138.16.113", "192.42.116.212", "185.220.101.3", "45.138.16.222", "5.42.80.232", "87.118.122.51", "107.189.11.166", "185.220.102.245", "185.220.102.251", "46.182.21.250", "5.255.103.235", "185.243.218.89", "185.193.52.180", "185.220.101.24", "2.57.122.215", "45.15.157.177", "185.220.100.253", "37.48.120.64", "204.8.156.142", "192.42.116.179", "185.220.100.240", "185.241.208.236", "185.195.71.244", "193.105.134.155", "51.15.59.15", "185.100.85.23", "45.151.167.11", "82.197.182.161", "192.42.116.191", "27.255.75.198", "171.25.193.79", "45.95.169.255", "45.138.16.230", "107.189.29.103", "163.172.213.212", "95.143.193.125", "23.154.177.7", "185.220.101.23", "195.176.3.24", "107.189.1.9", "192.42.116.182", "23.137.249.240", "192.42.116.189", "23.129.64.146", "45.138.16.107", "107.189.5.121", "107.189.30.236", "94.16.121.91", "109.70.100.70", "185.254.196.141", "194.15.112.133", "192.42.116.180", "173.249.57.253", "185.220.102.250", "185.100.85.25", "185.220.101.13", "185.220.101.25", "192.42.116.199", "23.154.177.2", "107.189.31.232", "45.141.215.81", "192.42.116.220", "185.67.82.114", "45.141.215.114", "185.243.218.61", "107.189.13.184", "107.189.10.141", "104.244.79.61", "185.106.94.195", "176.126.253.190", "23.154.177.22", "192.42.116.210", "185.220.102.249", "23.184.48.127", "192.42.116.218", "91.208.75.4", "192.42.116.178", "178.175.148.209", "208.109.36.224", "23.137.251.61", "94.142.241.194", "162.251.5.152", "23.154.177.4", "45.138.16.76", "45.9.150.103", "213.252.140.118", "185.243.218.95", "45.134.225.36", "109.70.100.5", "185.243.218.202", "185.220.101.19", "192.42.116.176", "109.70.100.71", "45.151.167.13", "185.220.102.4", "185.220.102.7", "104.244.79.50", "178.17.174.198", "199.195.249.214", "66.146.193.33", "107.189.8.238", "139.99.8.57", "45.141.215.95", "192.42.116.219", "114.199.75.111", "185.220.100.242", "5.42.80.234", "173.237.206.68", "139.99.172.11", "23.129.64.143", "80.241.60.207", "192.42.116.194", "45.95.169.226", "185.220.102.8", "109.70.100.3", "179.43.159.200", "192.42.116.217", "185.220.101.6", "198.98.50.199", "185.100.87.192", "193.189.100.202", "163.172.45.102", "185.220.101.0", "107.189.8.133", "185.129.61.6", "104.244.78.233", "192.42.116.15", "192.42.116.195", "45.141.215.110", "193.189.100.203", "77.48.28.237", "104.244.79.232", "193.26.115.43", "199.195.250.165", "190.211.254.97", "45.141.215.61", "185.220.101.17", "192.42.116.203", "185.220.102.247", "91.132.144.59", "185.141.147.129", "23.129.64.149", "185.183.157.214", "95.211.244.28", "192.42.116.188", "188.214.104.21", "192.42.116.186", "192.42.116.197", "107.189.13.247", "212.73.134.204", "185.235.146.29", "188.68.49.235", "92.205.237.227", "23.154.177.12", "199.195.253.180", "171.25.193.234", "185.241.208.71", "96.66.15.152", "94.16.121.226", "204.85.191.9", "91.210.59.57", "5.255.115.42", "185.220.103.113", "216.239.90.19", "77.91.87.79", "192.42.116.216", "23.154.177.23", "192.42.116.198", "173.255.255.215", "144.217.80.80", "107.189.10.175", "45.95.169.227", "103.251.167.20", "185.220.101.30", "5.255.125.196", "198.98.48.192", "185.220.102.242", "23.154.177.18", "185.86.148.90", "185.142.239.49", "185.220.101.2", "5.255.100.219", "107.189.5.7", "199.195.251.119", "185.220.101.10", "92.246.84.133", "66.220.242.222", "184.105.48.40", "23.129.64.133", "185.130.44.108", "192.42.116.20", "185.181.61.115", "192.42.116.19", "149.202.79.129", "146.59.35.38", "23.154.177.20", "185.191.204.254", "23.154.177.3", "185.233.100.23", "23.154.177.19", "45.92.1.74", "107.189.31.225", "89.58.18.10", "138.59.18.110", "185.246.188.73", "192.42.116.221", "104.244.77.192", "192.42.116.214", "178.170.37.11", "188.68.41.191", "192.42.116.183", "185.220.103.115", "178.175.135.7", "209.141.51.30", "141.98.11.62", "171.25.193.235", "23.137.249.143", "179.43.159.197", "192.99.168.180", "185.220.101.11", "185.243.218.41", "89.234.157.254", "47.243.74.136", "107.189.28.199", "185.129.61.9", "185.220.101.28", "185.220.101.29", "5.255.99.5", "179.43.182.58", "185.129.61.3", "23.129.64.135", "107.189.30.69", "51.15.227.109", "185.207.107.216", "185.129.61.129", "185.100.87.41", "23.129.64.145", "179.43.159.201", "23.129.64.224", "192.42.116.28", "93.99.104.194", "185.244.192.184", "45.95.169.223", "104.244.73.43", "185.56.83.83", "87.120.254.48", "185.185.170.27", "195.88.74.206", "107.174.138.172", "109.70.100.68", "23.129.64.139", "94.230.208.147", "77.91.85.147", "77.81.247.72", "2.58.56.220", "185.220.103.7", "149.202.79.101", "5.255.104.202", "178.175.148.195", "83.96.213.63", "185.100.87.174", "79.137.195.103", "185.220.101.20", "107.189.3.11", "185.220.101.22", "185.220.101.7", "217.12.221.131", "179.43.159.196", "45.95.169.230", "107.189.1.160", "208.109.215.188", "171.25.193.78", "204.194.29.4", "104.244.77.80", "162.247.72.199", "89.58.52.25", "192.42.116.209", "217.146.2.41", "185.220.103.117", "23.154.177.10", "91.208.75.3", "94.230.208.148", "95.128.43.164", "171.25.193.20", "102.130.113.9", "91.92.109.43", "107.189.7.144", "185.220.102.240", "5.255.124.150", "198.98.60.158", "185.227.134.106", "193.233.233.221", "71.19.144.106", "185.84.31.254", "23.129.64.132", "62.171.137.169", "193.189.100.196", "185.220.101.18", "107.189.12.3", "91.208.75.178", "193.35.18.49", "185.246.188.74", "45.132.246.245", "209.141.55.26", "198.98.48.20", "185.129.61.1", "108.61.189.136", "185.220.102.243", "107.189.1.96", "185.100.87.136", "213.95.149.22", "23.129.64.217", "192.42.116.185", "5.45.104.176", "192.42.116.193", "23.154.177.16", "198.98.49.203", "171.25.193.77", "91.208.75.153", "162.247.74.216", "179.43.159.194", "54.36.108.162", "198.98.48.33", "188.68.52.231", "185.220.100.252", "205.185.124.193", "104.244.73.190", "185.100.87.139", "23.154.177.25", "77.105.146.42", "79.137.202.92", "51.38.81.135", "87.118.116.90", "23.129.64.134", "185.246.188.67", "185.129.62.62", "185.220.100.241", "82.221.131.71", "209.141.59.116", "194.195.120.132", "185.207.107.130", "178.218.144.99", "172.104.243.155", "93.99.104.128", "87.118.122.30", "185.100.87.253", "51.195.91.124", "104.192.3.74", "185.252.232.218", "23.129.64.141", "5.196.95.34", "185.220.102.6", "23.184.48.128", "193.239.232.102", "185.220.101.16", "91.203.145.116", "185.129.61.4", "23.129.64.147", "37.228.129.63", "45.151.167.12", "93.95.228.205", "185.220.102.244", "209.141.54.203", "93.95.230.165", "94.142.244.16", "162.247.72.192", "185.146.232.234", "81.16.33.42", "107.189.30.86", "51.81.222.62", "23.154.177.5", "77.220.196.253", "72.167.47.69", "185.220.101.26", "104.219.236.100", "192.42.116.204", "185.246.128.161", "200.122.181.2", "199.195.253.247", "109.201.133.100", "142.44.234.69", "89.147.110.202", "89.185.85.140", "104.244.79.44", "5.2.79.179", "23.129.64.130", "104.244.78.187", "23.154.177.13", "5.255.97.221", "92.205.129.119", "80.82.78.14", "23.154.177.8", "51.38.113.118", "45.61.184.205", "107.189.31.134", "185.220.103.114", "179.48.251.188", "135.125.205.25", "198.98.54.49", "193.189.100.205", "185.220.102.253", "45.79.50.161", "202.69.76.36", "79.137.198.213", "46.166.139.111", "5.255.111.64", "51.89.138.51", "216.73.159.101", "166.70.207.2", "96.27.198.133", "194.15.115.212", "46.234.47.105", "146.59.35.246", "23.137.248.100", "185.220.102.241", "107.189.14.43", "212.95.50.77", "128.127.180.156", "80.67.172.162", "185.129.61.5", "185.129.61.10", "23.129.64.214", "185.220.100.254", "160.119.249.240", "185.243.218.46", "185.220.102.246", "104.244.74.97", "23.129.64.228", "23.129.64.218", "185.220.100.243", "54.36.101.21", "5.255.99.124", "107.189.13.253", "130.149.80.199", "171.25.193.80", "144.24.197.112", "199.195.251.78", "23.129.64.223", "195.80.151.30", "185.7.33.146", "107.189.4.12", "45.95.169.229", "107.189.6.124", "46.38.255.27", "107.189.8.226", "143.42.199.223", "103.251.167.10", "185.34.33.2", "5.255.98.23", "74.82.47.194", "194.163.157.49", "192.42.116.215", "185.220.101.14", "194.15.113.118", "89.147.108.62", "185.220.101.15", "185.42.170.203", "23.154.177.6", "162.247.74.27", "199.195.253.124", "193.189.100.201", "62.182.84.146", "191.101.217.24", "23.129.64.229", "85.93.218.204", "178.17.174.164", "205.185.117.149", "193.218.118.133", "23.154.177.21", "5.255.101.10", "82.221.131.5", "193.189.100.204", "103.196.37.111", "103.109.101.105", "192.42.116.18", "23.129.64.226", "107.189.13.251", "45.56.81.190", "192.42.116.13", "107.189.11.111", "198.46.166.157", "185.220.103.119", "54.38.183.101", "77.68.20.217", "185.220.101.36", "103.236.201.88", "162.247.74.213", "185.129.61.8", "89.147.110.154", "45.95.169.225", "141.239.149.94", "82.221.128.191", "72.14.179.10", "46.232.251.191", "23.129.64.215", "162.247.74.7", "23.154.177.14", "89.147.109.226", "193.41.226.117", "89.147.108.209", "23.129.64.137", "93.123.12.112", "185.14.97.37", "103.163.218.11", "23.129.64.131", "23.129.64.142", "23.137.249.185", "89.58.41.251", "185.220.101.9", "202.182.99.129", "205.185.119.35", "193.189.100.194", "204.85.191.8", "185.56.171.94", "23.129.64.144", "102.130.127.117", "192.42.116.24", "179.43.159.198", "185.38.175.133", "185.220.101.39", "193.168.143.129", "5.255.127.222", "95.211.210.103", "185.220.103.116", "23.129.64.211", "23.129.64.220", "185.113.128.30", "151.80.148.159", "192.99.149.111", "23.129.64.210", "37.228.129.128", "91.208.75.239", "185.220.103.120", "185.165.171.84", "193.105.134.150", "209.141.46.203", "209.141.50.178", "104.244.74.23", "45.95.169.224", "23.129.64.140", "176.118.193.33", "204.85.191.7", "104.244.73.193", "162.247.74.204", "91.208.75.156", "205.185.116.34", "125.212.241.131", "5.2.72.110", "179.43.159.195", "185.154.110.142", "91.206.26.26", "45.79.177.21", "23.154.177.9", "193.189.100.197", "46.165.243.36", "107.189.2.108", "23.154.177.17", "23.129.64.148", "5.45.98.162", "5.255.101.131", "23.129.64.136", "107.189.31.33", "185.82.219.109", "104.244.73.136", "185.129.61.7", "5.255.115.58", "23.154.177.24", "165.73.242.163", "193.189.100.200", "192.46.227.185", "5.196.8.113", "77.91.86.95", "85.209.176.103", "23.137.249.8", "5.255.98.151", "23.129.64.221", "23.129.64.219", "23.129.64.216", "185.243.218.35", "104.244.77.208", "94.228.169.70", "51.75.64.23", "176.58.100.98", "23.154.177.11", "23.129.64.138", "143.42.110.237", "94.16.112.22", "144.172.118.4", "185.130.47.58", "185.154.110.17", "104.244.72.132", "5.2.79.190", "23.129.64.212", "109.169.33.163", "5.2.67.226", "109.69.67.17", "108.181.27.205", "5.255.103.190", "107.189.14.106", "5.255.99.147", "193.189.100.206", "193.218.118.182", "185.181.61.142", "23.129.64.222", "193.35.18.77", "185.100.86.128", "91.203.5.118", "83.97.20.77", "45.138.16.203", "2.57.122.58", "185.181.61.18", "195.176.3.19", "195.176.3.20", "198.58.107.53", "138.128.222.68", "118.163.74.160", "185.241.208.54", "38.97.116.244", "104.244.77.79", "103.253.24.18", "185.225.69.203", "162.247.74.206", "79.124.8.241", "91.203.5.115", "144.172.118.102", "144.172.118.124", "185.225.69.232", "163.5.143.76", "144.172.118.51", "178.20.55.182", "109.104.153.22", "193.233.133.109", "51.158.115.62", "92.205.31.137", "185.193.158.134", "217.12.215.167", "45.15.158.39", "185.174.136.114", "91.219.239.166", "91.219.237.56", "51.159.211.57", "192.210.255.181", "185.170.114.25", "205.185.123.93", "205.185.121.170", "107.189.13.180", "104.244.78.162", "104.244.76.170", "104.244.74.57", "195.160.220.104", "31.220.98.139", "158.220.92.203", "23.184.48.101", "178.31.22.116", "79.102.34.63", "185.220.103.5", "179.43.128.16", "45.128.133.242", "185.220.103.118", "185.100.85.132", "107.189.7.48", "5.135.174.211", "45.8.22.207", "185.220.101.159", "185.220.101.141", "185.220.101.134", "185.220.101.147", "185.220.101.153", "185.220.101.145", "185.220.101.158", "185.220.101.160", "185.220.101.137", "185.220.101.140", "185.220.101.132", "185.220.101.157", "185.220.101.150", "185.220.101.143", "158.69.201.47", "107.189.1.175", "176.58.89.182", "185.220.101.138", "82.118.242.158", "217.170.201.71", "193.189.100.195", "144.172.118.48", "185.220.101.135", "185.220.101.191", "185.220.101.136", "185.220.101.179", "185.220.101.170", "185.220.101.149", "185.220.101.173", "185.220.101.171", "185.220.101.161", "185.220.101.163", "185.220.101.152", "185.220.101.162", "185.220.101.176", "185.220.101.188", "185.82.127.128", "85.235.145.205", "172.81.131.139", "5.255.100.26", "62.63.244.7", "104.219.236.101", "23.137.248.139", "185.241.208.204", "45.141.215.111", "185.241.208.202", "45.141.215.21", "45.61.185.172", "185.241.208.206", "205.185.113.180", "93.242.68.75", "185.220.100.248", "185.220.100.251", "185.220.100.247", "185.220.100.245", "185.220.100.246", "185.220.100.249", "185.220.100.250", "185.220.100.244", "77.72.85.30", "51.222.142.67", "107.172.31.165", "107.174.231.197", "198.144.178.163", "23.137.250.34", "107.172.13.143", "107.172.31.146", "173.232.195.137", "50.3.182.156", "173.232.195.144", "173.232.195.146", "172.81.131.168", "172.81.131.84", "77.48.28.239", "172.81.131.156", "185.183.159.40", "196.189.30.114", "107.189.8.5", "185.220.101.168", "185.220.101.165", "185.220.101.142", "185.220.101.167", "185.220.101.166", "185.220.101.169", "77.48.28.193", "37.228.129.5", "144.172.73.11", "107.189.14.57", "84.16.224.227", "185.220.103.4", "162.247.74.202", "185.220.103.6", "162.247.74.200", "185.220.103.9", "185.220.103.8", "154.12.254.57", "94.103.124.184", "185.220.101.189", "67.219.109.141", "185.220.101.187", "185.220.101.186", "185.220.101.183", "50.3.182.133", "185.220.101.182", "185.220.101.184", "188.172.229.15", "89.58.18.210", "45.9.150.130", "190.103.179.98", "108.181.124.143", "178.218.144.51", "185.220.101.66", "185.220.101.70", "185.220.101.68", "185.220.101.77", "185.220.101.78", "185.220.101.81", "185.220.101.71", "185.220.101.83", "185.220.101.75", "185.220.101.85", "185.220.101.73", "185.220.101.82", "185.220.101.65", "185.220.101.84", "185.220.101.76", "185.220.101.86", "185.220.101.69", "185.220.101.67", "185.220.101.80", "185.220.101.64", "185.220.101.74", "185.220.101.79", "185.220.101.72", "185.220.101.87", "199.249.230.120", "184.75.221.171", "5.182.86.212", "104.244.72.115", "198.23.133.132", "23.94.36.142", "198.98.60.90", "84.19.182.20", "45.9.148.219", "217.160.88.146", "104.219.232.126", "45.139.122.241", "199.195.253.156", "75.119.142.240", "199.249.230.103", "199.249.230.104", "199.249.230.116", "199.249.230.101", "199.249.230.119", "199.249.230.100", "199.249.230.102", "199.249.230.109", "199.249.230.81", "199.249.230.176", "199.249.230.79", "199.249.230.167", "199.249.230.88", "199.249.230.188", "199.249.230.80", "199.249.230.144", "199.249.230.78", "199.249.230.111", "199.249.230.68", "199.249.230.180", "199.249.230.150", "199.249.230.70", "199.249.230.77", "199.249.230.112", "199.249.230.65", "199.249.230.183", "199.249.230.189", "199.249.230.178", "199.249.230.145", "199.249.230.115", "199.249.230.147", "199.249.230.66", "199.249.230.140", "199.249.230.114", "199.249.230.170", "199.249.230.71", "199.249.230.148", "199.249.230.67", "199.249.230.75", "199.249.230.146", "199.249.230.151", "199.249.230.187", "199.249.230.174", "199.249.230.143", "199.249.230.118", "199.249.230.64", "199.249.230.85", "199.249.230.113", "199.249.230.155", "199.249.230.153", "199.249.230.89", "45.77.67.251", "123.253.35.32", "45.83.104.137", "94.32.66.15", "185.220.101.181", "185.220.101.178", "185.220.101.177", "185.220.101.175", "185.220.101.172", "94.16.116.86", "5.181.80.107", "198.50.207.20", "107.189.7.168", "85.215.76.62", "185.247.184.105", "178.236.247.122", "109.107.190.171", "193.233.233.124", "193.218.118.188", "2.58.95.45", "45.154.98.102", "92.205.185.52", "92.205.163.226", "185.217.125.210", "5.255.118.104", "212.69.167.80", "23.137.249.227", "5.255.118.244", "71.19.148.129", "143.42.114.46", "45.33.15.243", "104.237.158.32", "172.232.161.205", "172.232.161.206", "74.207.248.172", "172.233.209.179", "45.66.35.21", "45.66.35.35", "45.66.35.10", "45.66.35.20", "45.66.35.22", "51.210.138.64", "130.204.161.3", "175.214.127.6", "31.220.85.162", "198.96.155.3", "50.118.225.160", "45.135.132.20", "23.152.24.77", "45.95.169.99", "94.75.225.81", "37.228.129.131", "23.137.249.62", "103.172.134.26", "199.249.230.121", "191.252.111.55", "35.0.127.52", "185.129.62.63", "23.94.211.25", "185.220.101.139", "185.220.101.144", "185.220.101.130", "185.220.101.156", "185.220.101.128", "185.220.101.131", "185.220.101.154", "185.220.101.164", "185.220.101.180", "185.220.101.155", "185.220.101.133", "185.220.101.190", "185.220.101.151", "185.220.101.174", "185.220.101.148", "185.220.101.129", "185.220.101.185", "37.221.208.68", "87.120.254.132", "5.255.106.9", "45.15.158.165", "193.35.18.105", "178.17.170.23", "185.146.232.243", "194.163.178.164", "94.140.115.63", "37.228.129.24", "81.0.248.210", "193.35.18.98", "45.128.232.170", "193.35.18.96", "45.128.232.102", "193.35.18.94", "193.35.18.95", "149.102.128.242", "89.187.143.31", "193.239.232.228", "103.208.86.5", "193.35.18.120", "185.130.44.43", "185.219.142.126", "37.1.201.144", "5.255.99.108", "85.204.116.211", "130.193.10.21", "130.193.15.79", "84.239.46.144", "178.218.162.62", "199.249.230.122", "199.249.230.84", "45.141.202.164", "199.249.230.74", "148.113.2.107", "199.249.230.105", "199.249.230.73", "199.249.230.110", "199.249.230.72", "199.249.230.86", "103.129.222.46", "64.5.123.66", "185.239.71.160", "5.42.80.233", "5.42.80.235", "200.25.27.112", "46.226.107.206", "103.106.3.175", "96.42.26.63", "192.42.116.26", "192.42.116.17", "192.42.116.14", "192.42.116.22", "192.42.116.25", "192.42.116.27", "74.208.106.128", "213.232.235.83", "91.208.197.144", "51.195.166.174", "198.98.53.136", "157.143.80.38", "198.50.128.237", "193.233.232.86", "144.126.152.77", "158.220.80.216", "154.16.116.61", "45.88.223.151", "144.126.132.30", "89.147.110.214", "89.163.155.136", "107.189.13.93", "77.232.143.255", "77.232.143.243", "77.232.143.248", "94.228.163.25", "199.249.230.186", "199.249.230.177", "199.249.230.159", "199.249.230.161", "199.249.230.163", "199.249.230.149", "199.249.230.154", "199.249.230.164", "199.249.230.160", "199.249.230.173", "199.249.230.158", "199.249.230.157", "199.249.230.108", "199.249.230.83", "199.249.230.168", "199.249.230.82", "199.249.230.166", "199.249.230.123", "199.249.230.106", "199.249.230.76", "199.249.230.117", "199.249.230.169", "199.249.230.171", "199.249.230.175", "199.249.230.107", "199.249.230.152", "199.249.230.162", "2.58.95.53", "199.249.230.69", "2.58.95.47", "2.58.95.59", "2.58.95.56", "178.175.142.26", "199.249.230.156", "199.249.230.87", "103.28.52.93", "185.107.70.56", "89.147.108.56", "148.113.2.104", "38.242.203.135", "162.247.74.201", "172.232.238.10", "5.255.98.198", "5.255.98.231", "23.137.249.150", "149.102.155.205", "199.249.230.179", "199.249.230.165", "199.249.230.182", "199.249.230.184", "199.249.230.142", "136.243.147.59", "199.249.230.185", "185.220.101.89", "149.102.145.222", "185.220.101.90", "185.220.101.88", "87.118.110.27", "37.48.70.156", "185.165.190.111", "5.255.125.153", "205.185.124.176", "107.189.14.41", "93.95.228.81", "172.81.131.140", "185.38.142.4", "95.168.173.143", "178.218.144.18", "189.147.238.226", "189.147.187.10", "189.147.242.169", "104.219.236.93", "161.35.129.51", "86.104.194.13", "104.244.74.159", "185.220.101.40", "185.220.101.32", "185.220.101.38", "185.220.101.37", "185.220.101.35", "185.220.101.33", "185.220.101.34", "185.220.101.41", "185.220.101.42", "205.185.127.100", "185.220.101.57", "185.220.101.43", "185.220.101.46", "185.220.101.58", "185.220.101.61", "185.220.101.60", "185.220.101.63", "185.220.101.54", "185.220.101.52", "185.220.101.62", "185.220.101.56", "185.220.101.44", "185.220.101.49", "5.255.117.56", "185.220.101.55", "185.220.101.45", "185.220.101.53", "185.220.101.59", "185.220.101.51", "185.220.101.48", "185.220.101.47", "185.220.101.50", "95.111.238.0", "152.89.233.169", "89.147.110.82", "176.58.117.81", "23.155.8.104", "51.89.153.112", "5.61.51.143", "5.135.174.213", "37.120.166.23", "37.252.255.135", "82.153.138.48", "185.81.115.120", "45.139.122.176", "84.211.225.54", "31.220.87.46", "144.172.73.6", "51.89.200.109", "212.44.107.82", "89.147.111.124", "94.177.106.59", "94.177.106.55", "94.177.106.46", "93.95.231.88", "152.32.238.235", "74.208.96.95", "38.242.239.62", "87.118.114.44", "80.78.25.9", "185.193.125.95", "107.173.179.59", "179.43.159.78", "81.17.28.95", "45.79.129.209", "82.221.139.190", "107.189.13.254", "81.19.137.127", "149.102.129.11", "81.0.218.34", "93.90.74.31", "51.81.254.4", "109.123.231.55", "185.196.8.2", "158.220.81.45", "62.149.23.133", "158.220.81.47", "158.220.81.78", "209.141.51.180", "176.121.81.51", "178.17.170.184", "202.61.226.98", "202.139.229.157", "89.147.111.106"]); const checkIfTor = floBlockchainAPI.checkIfTor = () => { - return fetch('https://api.ipify.org?format=json').then(response => response.json()) - .then(result => { - return torExitNodes.has(result.ip) + return fetch('https://check.torproject.org/api/ip') + .then(res => res.json()) + .then(res => { + return res.IsTor }).catch(e => { console.error(e) return false @@ -32,8 +32,8 @@ checkIfTor().then(result => { isTor = result if (isTor) { - DEFAULT.apiURL.FLO.push('http://kvrddx6heo47rbbt77etxg6litckacbgos3nv5z7vc23ol2kjjeq72id.onion/') - // DEFAULT.apiURL.FLO_TEST.push('http://omwkzk6bd6zuragdqsrhdyzgxzre7yx4vzrou4vzftintzc2dmagp6qd.onion:15017/') + DEFAULT.apiURL.FLO.push('http://xge4kejxl6xs4cad3u3a7dnw7idndlkn3vmyo33t3a4ctk566y65eoad.onion/') + DEFAULT.apiURL.FLO_TEST.push('http://fdjrsde2qhfecvx6fkgmcidwkp34bdek7jo4y2fpqatrhzxtxkk6f4ad.onion/') } }); diff --git a/js/floBlockchainAPI.min.js b/js/floBlockchainAPI.min.js index fc5674b..fad0a6a 100644 --- a/js/floBlockchainAPI.min.js +++ b/js/floBlockchainAPI.min.js @@ -1 +1 @@ -!function(EXPORTS){"use strict";const floBlockchainAPI="object"===typeof module?module.exports:window.floBlockchainAPI={},DEFAULT={blockchain:floGlobals.blockchain,apiURL:{FLO:["https://blockbook.ranchimall.net/"],FLO_TEST:["https://blockbook-testnet.ranchimall.net/"]},sendAmt:3e-4,fee:2e-4,minChangeAmt:2e-4,receiverID:floGlobals.adminID},isUndefined=val=>void 0===val,torExitNodes=new Set(["185.241.208.232","194.26.192.64","171.25.193.25","80.67.167.81","192.42.116.187","198.98.51.189","89.58.26.216","109.70.100.4","149.56.22.133","5.45.102.93","178.17.174.14","192.42.116.196","185.220.101.4","45.141.215.62","94.102.51.15","192.42.116.213","107.189.28.166","185.241.208.243","45.141.215.80","193.26.115.61","192.42.116.175","149.56.44.47","107.189.13.91","87.118.116.103","178.17.171.102","185.243.218.110","192.42.116.208","89.58.41.156","2.58.56.43","104.192.1.138","45.95.169.184","107.189.8.56","176.58.121.177","185.220.101.31","45.141.215.200","109.70.100.1","185.244.192.175","185.129.61.2","144.172.118.41","192.42.116.184","45.151.167.10","185.220.101.27","91.203.144.194","45.141.215.88","179.43.182.232","185.220.101.5","109.70.100.2","107.189.14.4","94.16.116.81","185.220.101.8","185.220.101.12","88.80.20.86","23.154.177.15","45.141.215.56","5.42.66.6","23.129.64.225","104.244.75.74","45.95.169.228","37.187.5.192","45.141.215.169","109.70.100.66","45.79.144.222","185.227.68.78","179.43.159.199","2.57.122.246","192.42.116.201","185.220.102.248","195.176.3.23","45.138.16.42","216.73.159.75","185.165.169.239","23.129.64.213","109.70.100.6","45.80.158.27","45.138.16.240","178.20.55.16","192.42.116.173","51.15.249.160","192.42.116.200","185.220.102.254","45.141.215.63","193.218.118.151","192.42.116.211","185.100.85.24","185.195.71.12","107.189.8.181","193.189.100.199","109.70.100.69","185.100.87.250","31.220.93.201","89.236.112.100","45.141.215.90","185.35.202.222","109.70.100.65","95.142.161.63","192.42.116.181","192.42.116.23","194.26.192.77","193.189.100.198","180.150.226.99","23.129.64.227","107.189.4.23","45.141.215.235","185.220.102.252","109.70.100.67","185.220.100.255","185.220.101.21","185.100.85.22","128.31.0.13","46.182.21.248","192.42.116.174","185.241.208.115","185.220.101.1","192.42.116.202","45.141.215.97","185.243.218.204","78.142.18.219","192.42.116.192","190.120.229.98","192.42.116.177","45.138.16.113","192.42.116.212","185.220.101.3","45.138.16.222","5.42.80.232","87.118.122.51","107.189.11.166","185.220.102.245","185.220.102.251","46.182.21.250","5.255.103.235","185.243.218.89","185.193.52.180","185.220.101.24","2.57.122.215","45.15.157.177","185.220.100.253","37.48.120.64","204.8.156.142","192.42.116.179","185.220.100.240","185.241.208.236","185.195.71.244","193.105.134.155","51.15.59.15","185.100.85.23","45.151.167.11","82.197.182.161","192.42.116.191","27.255.75.198","171.25.193.79","45.95.169.255","45.138.16.230","107.189.29.103","163.172.213.212","95.143.193.125","23.154.177.7","185.220.101.23","195.176.3.24","107.189.1.9","192.42.116.182","23.137.249.240","192.42.116.189","23.129.64.146","45.138.16.107","107.189.5.121","107.189.30.236","94.16.121.91","109.70.100.70","185.254.196.141","194.15.112.133","192.42.116.180","173.249.57.253","185.220.102.250","185.100.85.25","185.220.101.13","185.220.101.25","192.42.116.199","23.154.177.2","107.189.31.232","45.141.215.81","192.42.116.220","185.67.82.114","45.141.215.114","185.243.218.61","107.189.13.184","107.189.10.141","104.244.79.61","185.106.94.195","176.126.253.190","23.154.177.22","192.42.116.210","185.220.102.249","23.184.48.127","192.42.116.218","91.208.75.4","192.42.116.178","178.175.148.209","208.109.36.224","23.137.251.61","94.142.241.194","162.251.5.152","23.154.177.4","45.138.16.76","45.9.150.103","213.252.140.118","185.243.218.95","45.134.225.36","109.70.100.5","185.243.218.202","185.220.101.19","192.42.116.176","109.70.100.71","45.151.167.13","185.220.102.4","185.220.102.7","104.244.79.50","178.17.174.198","199.195.249.214","66.146.193.33","107.189.8.238","139.99.8.57","45.141.215.95","192.42.116.219","114.199.75.111","185.220.100.242","5.42.80.234","173.237.206.68","139.99.172.11","23.129.64.143","80.241.60.207","192.42.116.194","45.95.169.226","185.220.102.8","109.70.100.3","179.43.159.200","192.42.116.217","185.220.101.6","198.98.50.199","185.100.87.192","193.189.100.202","163.172.45.102","185.220.101.0","107.189.8.133","185.129.61.6","104.244.78.233","192.42.116.15","192.42.116.195","45.141.215.110","193.189.100.203","77.48.28.237","104.244.79.232","193.26.115.43","199.195.250.165","190.211.254.97","45.141.215.61","185.220.101.17","192.42.116.203","185.220.102.247","91.132.144.59","185.141.147.129","23.129.64.149","185.183.157.214","95.211.244.28","192.42.116.188","188.214.104.21","192.42.116.186","192.42.116.197","107.189.13.247","212.73.134.204","185.235.146.29","188.68.49.235","92.205.237.227","23.154.177.12","199.195.253.180","171.25.193.234","185.241.208.71","96.66.15.152","94.16.121.226","204.85.191.9","91.210.59.57","5.255.115.42","185.220.103.113","216.239.90.19","77.91.87.79","192.42.116.216","23.154.177.23","192.42.116.198","173.255.255.215","144.217.80.80","107.189.10.175","45.95.169.227","103.251.167.20","185.220.101.30","5.255.125.196","198.98.48.192","185.220.102.242","23.154.177.18","185.86.148.90","185.142.239.49","185.220.101.2","5.255.100.219","107.189.5.7","199.195.251.119","185.220.101.10","92.246.84.133","66.220.242.222","184.105.48.40","23.129.64.133","185.130.44.108","192.42.116.20","185.181.61.115","192.42.116.19","149.202.79.129","146.59.35.38","23.154.177.20","185.191.204.254","23.154.177.3","185.233.100.23","23.154.177.19","45.92.1.74","107.189.31.225","89.58.18.10","138.59.18.110","185.246.188.73","192.42.116.221","104.244.77.192","192.42.116.214","178.170.37.11","188.68.41.191","192.42.116.183","185.220.103.115","178.175.135.7","209.141.51.30","141.98.11.62","171.25.193.235","23.137.249.143","179.43.159.197","192.99.168.180","185.220.101.11","185.243.218.41","89.234.157.254","47.243.74.136","107.189.28.199","185.129.61.9","185.220.101.28","185.220.101.29","5.255.99.5","179.43.182.58","185.129.61.3","23.129.64.135","107.189.30.69","51.15.227.109","185.207.107.216","185.129.61.129","185.100.87.41","23.129.64.145","179.43.159.201","23.129.64.224","192.42.116.28","93.99.104.194","185.244.192.184","45.95.169.223","104.244.73.43","185.56.83.83","87.120.254.48","185.185.170.27","195.88.74.206","107.174.138.172","109.70.100.68","23.129.64.139","94.230.208.147","77.91.85.147","77.81.247.72","2.58.56.220","185.220.103.7","149.202.79.101","5.255.104.202","178.175.148.195","83.96.213.63","185.100.87.174","79.137.195.103","185.220.101.20","107.189.3.11","185.220.101.22","185.220.101.7","217.12.221.131","179.43.159.196","45.95.169.230","107.189.1.160","208.109.215.188","171.25.193.78","204.194.29.4","104.244.77.80","162.247.72.199","89.58.52.25","192.42.116.209","217.146.2.41","185.220.103.117","23.154.177.10","91.208.75.3","94.230.208.148","95.128.43.164","171.25.193.20","102.130.113.9","91.92.109.43","107.189.7.144","185.220.102.240","5.255.124.150","198.98.60.158","185.227.134.106","193.233.233.221","71.19.144.106","185.84.31.254","23.129.64.132","62.171.137.169","193.189.100.196","185.220.101.18","107.189.12.3","91.208.75.178","193.35.18.49","185.246.188.74","45.132.246.245","209.141.55.26","198.98.48.20","185.129.61.1","108.61.189.136","185.220.102.243","107.189.1.96","185.100.87.136","213.95.149.22","23.129.64.217","192.42.116.185","5.45.104.176","192.42.116.193","23.154.177.16","198.98.49.203","171.25.193.77","91.208.75.153","162.247.74.216","179.43.159.194","54.36.108.162","198.98.48.33","188.68.52.231","185.220.100.252","205.185.124.193","104.244.73.190","185.100.87.139","23.154.177.25","77.105.146.42","79.137.202.92","51.38.81.135","87.118.116.90","23.129.64.134","185.246.188.67","185.129.62.62","185.220.100.241","82.221.131.71","209.141.59.116","194.195.120.132","185.207.107.130","178.218.144.99","172.104.243.155","93.99.104.128","87.118.122.30","185.100.87.253","51.195.91.124","104.192.3.74","185.252.232.218","23.129.64.141","5.196.95.34","185.220.102.6","23.184.48.128","193.239.232.102","185.220.101.16","91.203.145.116","185.129.61.4","23.129.64.147","37.228.129.63","45.151.167.12","93.95.228.205","185.220.102.244","209.141.54.203","93.95.230.165","94.142.244.16","162.247.72.192","185.146.232.234","81.16.33.42","107.189.30.86","51.81.222.62","23.154.177.5","77.220.196.253","72.167.47.69","185.220.101.26","104.219.236.100","192.42.116.204","185.246.128.161","200.122.181.2","199.195.253.247","109.201.133.100","142.44.234.69","89.147.110.202","89.185.85.140","104.244.79.44","5.2.79.179","23.129.64.130","104.244.78.187","23.154.177.13","5.255.97.221","92.205.129.119","80.82.78.14","23.154.177.8","51.38.113.118","45.61.184.205","107.189.31.134","185.220.103.114","179.48.251.188","135.125.205.25","198.98.54.49","193.189.100.205","185.220.102.253","45.79.50.161","202.69.76.36","79.137.198.213","46.166.139.111","5.255.111.64","51.89.138.51","216.73.159.101","166.70.207.2","96.27.198.133","194.15.115.212","46.234.47.105","146.59.35.246","23.137.248.100","185.220.102.241","107.189.14.43","212.95.50.77","128.127.180.156","80.67.172.162","185.129.61.5","185.129.61.10","23.129.64.214","185.220.100.254","160.119.249.240","185.243.218.46","185.220.102.246","104.244.74.97","23.129.64.228","23.129.64.218","185.220.100.243","54.36.101.21","5.255.99.124","107.189.13.253","130.149.80.199","171.25.193.80","144.24.197.112","199.195.251.78","23.129.64.223","195.80.151.30","185.7.33.146","107.189.4.12","45.95.169.229","107.189.6.124","46.38.255.27","107.189.8.226","143.42.199.223","103.251.167.10","185.34.33.2","5.255.98.23","74.82.47.194","194.163.157.49","192.42.116.215","185.220.101.14","194.15.113.118","89.147.108.62","185.220.101.15","185.42.170.203","23.154.177.6","162.247.74.27","199.195.253.124","193.189.100.201","62.182.84.146","191.101.217.24","23.129.64.229","85.93.218.204","178.17.174.164","205.185.117.149","193.218.118.133","23.154.177.21","5.255.101.10","82.221.131.5","193.189.100.204","103.196.37.111","103.109.101.105","192.42.116.18","23.129.64.226","107.189.13.251","45.56.81.190","192.42.116.13","107.189.11.111","198.46.166.157","185.220.103.119","54.38.183.101","77.68.20.217","185.220.101.36","103.236.201.88","162.247.74.213","185.129.61.8","89.147.110.154","45.95.169.225","141.239.149.94","82.221.128.191","72.14.179.10","46.232.251.191","23.129.64.215","162.247.74.7","23.154.177.14","89.147.109.226","193.41.226.117","89.147.108.209","23.129.64.137","93.123.12.112","185.14.97.37","103.163.218.11","23.129.64.131","23.129.64.142","23.137.249.185","89.58.41.251","185.220.101.9","202.182.99.129","205.185.119.35","193.189.100.194","204.85.191.8","185.56.171.94","23.129.64.144","102.130.127.117","192.42.116.24","179.43.159.198","185.38.175.133","185.220.101.39","193.168.143.129","5.255.127.222","95.211.210.103","185.220.103.116","23.129.64.211","23.129.64.220","185.113.128.30","151.80.148.159","192.99.149.111","23.129.64.210","37.228.129.128","91.208.75.239","185.220.103.120","185.165.171.84","193.105.134.150","209.141.46.203","209.141.50.178","104.244.74.23","45.95.169.224","23.129.64.140","176.118.193.33","204.85.191.7","104.244.73.193","162.247.74.204","91.208.75.156","205.185.116.34","125.212.241.131","5.2.72.110","179.43.159.195","185.154.110.142","91.206.26.26","45.79.177.21","23.154.177.9","193.189.100.197","46.165.243.36","107.189.2.108","23.154.177.17","23.129.64.148","5.45.98.162","5.255.101.131","23.129.64.136","107.189.31.33","185.82.219.109","104.244.73.136","185.129.61.7","5.255.115.58","23.154.177.24","165.73.242.163","193.189.100.200","192.46.227.185","5.196.8.113","77.91.86.95","85.209.176.103","23.137.249.8","5.255.98.151","23.129.64.221","23.129.64.219","23.129.64.216","185.243.218.35","104.244.77.208","94.228.169.70","51.75.64.23","176.58.100.98","23.154.177.11","23.129.64.138","143.42.110.237","94.16.112.22","144.172.118.4","185.130.47.58","185.154.110.17","104.244.72.132","5.2.79.190","23.129.64.212","109.169.33.163","5.2.67.226","109.69.67.17","108.181.27.205","5.255.103.190","107.189.14.106","5.255.99.147","193.189.100.206","193.218.118.182","185.181.61.142","23.129.64.222","193.35.18.77","185.100.86.128","91.203.5.118","83.97.20.77","45.138.16.203","2.57.122.58","185.181.61.18","195.176.3.19","195.176.3.20","198.58.107.53","138.128.222.68","118.163.74.160","185.241.208.54","38.97.116.244","104.244.77.79","103.253.24.18","185.225.69.203","162.247.74.206","79.124.8.241","91.203.5.115","144.172.118.102","144.172.118.124","185.225.69.232","163.5.143.76","144.172.118.51","178.20.55.182","109.104.153.22","193.233.133.109","51.158.115.62","92.205.31.137","185.193.158.134","217.12.215.167","45.15.158.39","185.174.136.114","91.219.239.166","91.219.237.56","51.159.211.57","192.210.255.181","185.170.114.25","205.185.123.93","205.185.121.170","107.189.13.180","104.244.78.162","104.244.76.170","104.244.74.57","195.160.220.104","31.220.98.139","158.220.92.203","23.184.48.101","178.31.22.116","79.102.34.63","185.220.103.5","179.43.128.16","45.128.133.242","185.220.103.118","185.100.85.132","107.189.7.48","5.135.174.211","45.8.22.207","185.220.101.159","185.220.101.141","185.220.101.134","185.220.101.147","185.220.101.153","185.220.101.145","185.220.101.158","185.220.101.160","185.220.101.137","185.220.101.140","185.220.101.132","185.220.101.157","185.220.101.150","185.220.101.143","158.69.201.47","107.189.1.175","176.58.89.182","185.220.101.138","82.118.242.158","217.170.201.71","193.189.100.195","144.172.118.48","185.220.101.135","185.220.101.191","185.220.101.136","185.220.101.179","185.220.101.170","185.220.101.149","185.220.101.173","185.220.101.171","185.220.101.161","185.220.101.163","185.220.101.152","185.220.101.162","185.220.101.176","185.220.101.188","185.82.127.128","85.235.145.205","172.81.131.139","5.255.100.26","62.63.244.7","104.219.236.101","23.137.248.139","185.241.208.204","45.141.215.111","185.241.208.202","45.141.215.21","45.61.185.172","185.241.208.206","205.185.113.180","93.242.68.75","185.220.100.248","185.220.100.251","185.220.100.247","185.220.100.245","185.220.100.246","185.220.100.249","185.220.100.250","185.220.100.244","77.72.85.30","51.222.142.67","107.172.31.165","107.174.231.197","198.144.178.163","23.137.250.34","107.172.13.143","107.172.31.146","173.232.195.137","50.3.182.156","173.232.195.144","173.232.195.146","172.81.131.168","172.81.131.84","77.48.28.239","172.81.131.156","185.183.159.40","196.189.30.114","107.189.8.5","185.220.101.168","185.220.101.165","185.220.101.142","185.220.101.167","185.220.101.166","185.220.101.169","77.48.28.193","37.228.129.5","144.172.73.11","107.189.14.57","84.16.224.227","185.220.103.4","162.247.74.202","185.220.103.6","162.247.74.200","185.220.103.9","185.220.103.8","154.12.254.57","94.103.124.184","185.220.101.189","67.219.109.141","185.220.101.187","185.220.101.186","185.220.101.183","50.3.182.133","185.220.101.182","185.220.101.184","188.172.229.15","89.58.18.210","45.9.150.130","190.103.179.98","108.181.124.143","178.218.144.51","185.220.101.66","185.220.101.70","185.220.101.68","185.220.101.77","185.220.101.78","185.220.101.81","185.220.101.71","185.220.101.83","185.220.101.75","185.220.101.85","185.220.101.73","185.220.101.82","185.220.101.65","185.220.101.84","185.220.101.76","185.220.101.86","185.220.101.69","185.220.101.67","185.220.101.80","185.220.101.64","185.220.101.74","185.220.101.79","185.220.101.72","185.220.101.87","199.249.230.120","184.75.221.171","5.182.86.212","104.244.72.115","198.23.133.132","23.94.36.142","198.98.60.90","84.19.182.20","45.9.148.219","217.160.88.146","104.219.232.126","45.139.122.241","199.195.253.156","75.119.142.240","199.249.230.103","199.249.230.104","199.249.230.116","199.249.230.101","199.249.230.119","199.249.230.100","199.249.230.102","199.249.230.109","199.249.230.81","199.249.230.176","199.249.230.79","199.249.230.167","199.249.230.88","199.249.230.188","199.249.230.80","199.249.230.144","199.249.230.78","199.249.230.111","199.249.230.68","199.249.230.180","199.249.230.150","199.249.230.70","199.249.230.77","199.249.230.112","199.249.230.65","199.249.230.183","199.249.230.189","199.249.230.178","199.249.230.145","199.249.230.115","199.249.230.147","199.249.230.66","199.249.230.140","199.249.230.114","199.249.230.170","199.249.230.71","199.249.230.148","199.249.230.67","199.249.230.75","199.249.230.146","199.249.230.151","199.249.230.187","199.249.230.174","199.249.230.143","199.249.230.118","199.249.230.64","199.249.230.85","199.249.230.113","199.249.230.155","199.249.230.153","199.249.230.89","45.77.67.251","123.253.35.32","45.83.104.137","94.32.66.15","185.220.101.181","185.220.101.178","185.220.101.177","185.220.101.175","185.220.101.172","94.16.116.86","5.181.80.107","198.50.207.20","107.189.7.168","85.215.76.62","185.247.184.105","178.236.247.122","109.107.190.171","193.233.233.124","193.218.118.188","2.58.95.45","45.154.98.102","92.205.185.52","92.205.163.226","185.217.125.210","5.255.118.104","212.69.167.80","23.137.249.227","5.255.118.244","71.19.148.129","143.42.114.46","45.33.15.243","104.237.158.32","172.232.161.205","172.232.161.206","74.207.248.172","172.233.209.179","45.66.35.21","45.66.35.35","45.66.35.10","45.66.35.20","45.66.35.22","51.210.138.64","130.204.161.3","175.214.127.6","31.220.85.162","198.96.155.3","50.118.225.160","45.135.132.20","23.152.24.77","45.95.169.99","94.75.225.81","37.228.129.131","23.137.249.62","103.172.134.26","199.249.230.121","191.252.111.55","35.0.127.52","185.129.62.63","23.94.211.25","185.220.101.139","185.220.101.144","185.220.101.130","185.220.101.156","185.220.101.128","185.220.101.131","185.220.101.154","185.220.101.164","185.220.101.180","185.220.101.155","185.220.101.133","185.220.101.190","185.220.101.151","185.220.101.174","185.220.101.148","185.220.101.129","185.220.101.185","37.221.208.68","87.120.254.132","5.255.106.9","45.15.158.165","193.35.18.105","178.17.170.23","185.146.232.243","194.163.178.164","94.140.115.63","37.228.129.24","81.0.248.210","193.35.18.98","45.128.232.170","193.35.18.96","45.128.232.102","193.35.18.94","193.35.18.95","149.102.128.242","89.187.143.31","193.239.232.228","103.208.86.5","193.35.18.120","185.130.44.43","185.219.142.126","37.1.201.144","5.255.99.108","85.204.116.211","130.193.10.21","130.193.15.79","84.239.46.144","178.218.162.62","199.249.230.122","199.249.230.84","45.141.202.164","199.249.230.74","148.113.2.107","199.249.230.105","199.249.230.73","199.249.230.110","199.249.230.72","199.249.230.86","103.129.222.46","64.5.123.66","185.239.71.160","5.42.80.233","5.42.80.235","200.25.27.112","46.226.107.206","103.106.3.175","96.42.26.63","192.42.116.26","192.42.116.17","192.42.116.14","192.42.116.22","192.42.116.25","192.42.116.27","74.208.106.128","213.232.235.83","91.208.197.144","51.195.166.174","198.98.53.136","157.143.80.38","198.50.128.237","193.233.232.86","144.126.152.77","158.220.80.216","154.16.116.61","45.88.223.151","144.126.132.30","89.147.110.214","89.163.155.136","107.189.13.93","77.232.143.255","77.232.143.243","77.232.143.248","94.228.163.25","199.249.230.186","199.249.230.177","199.249.230.159","199.249.230.161","199.249.230.163","199.249.230.149","199.249.230.154","199.249.230.164","199.249.230.160","199.249.230.173","199.249.230.158","199.249.230.157","199.249.230.108","199.249.230.83","199.249.230.168","199.249.230.82","199.249.230.166","199.249.230.123","199.249.230.106","199.249.230.76","199.249.230.117","199.249.230.169","199.249.230.171","199.249.230.175","199.249.230.107","199.249.230.152","199.249.230.162","2.58.95.53","199.249.230.69","2.58.95.47","2.58.95.59","2.58.95.56","178.175.142.26","199.249.230.156","199.249.230.87","103.28.52.93","185.107.70.56","89.147.108.56","148.113.2.104","38.242.203.135","162.247.74.201","172.232.238.10","5.255.98.198","5.255.98.231","23.137.249.150","149.102.155.205","199.249.230.179","199.249.230.165","199.249.230.182","199.249.230.184","199.249.230.142","136.243.147.59","199.249.230.185","185.220.101.89","149.102.145.222","185.220.101.90","185.220.101.88","87.118.110.27","37.48.70.156","185.165.190.111","5.255.125.153","205.185.124.176","107.189.14.41","93.95.228.81","172.81.131.140","185.38.142.4","95.168.173.143","178.218.144.18","189.147.238.226","189.147.187.10","189.147.242.169","104.219.236.93","161.35.129.51","86.104.194.13","104.244.74.159","185.220.101.40","185.220.101.32","185.220.101.38","185.220.101.37","185.220.101.35","185.220.101.33","185.220.101.34","185.220.101.41","185.220.101.42","205.185.127.100","185.220.101.57","185.220.101.43","185.220.101.46","185.220.101.58","185.220.101.61","185.220.101.60","185.220.101.63","185.220.101.54","185.220.101.52","185.220.101.62","185.220.101.56","185.220.101.44","185.220.101.49","5.255.117.56","185.220.101.55","185.220.101.45","185.220.101.53","185.220.101.59","185.220.101.51","185.220.101.48","185.220.101.47","185.220.101.50","95.111.238.0","152.89.233.169","89.147.110.82","176.58.117.81","23.155.8.104","51.89.153.112","5.61.51.143","5.135.174.213","37.120.166.23","37.252.255.135","82.153.138.48","185.81.115.120","45.139.122.176","84.211.225.54","31.220.87.46","144.172.73.6","51.89.200.109","212.44.107.82","89.147.111.124","94.177.106.59","94.177.106.55","94.177.106.46","93.95.231.88","152.32.238.235","74.208.96.95","38.242.239.62","87.118.114.44","80.78.25.9","185.193.125.95","107.173.179.59","179.43.159.78","81.17.28.95","45.79.129.209","82.221.139.190","107.189.13.254","81.19.137.127","149.102.129.11","81.0.218.34","93.90.74.31","51.81.254.4","109.123.231.55","185.196.8.2","158.220.81.45","62.149.23.133","158.220.81.47","158.220.81.78","209.141.51.180","176.121.81.51","178.17.170.184","202.61.226.98","202.139.229.157","89.147.111.106"]),checkIfTor=floBlockchainAPI.checkIfTor=()=>fetch("https://api.ipify.org?format=json").then((response=>response.json())).then((result=>torExitNodes.has(result.ip))).catch((e=>(console.error(e),!1)));let isTor=!1;checkIfTor().then((result=>{isTor=result,isTor&&DEFAULT.apiURL.FLO.push("http://kvrddx6heo47rbbt77etxg6litckacbgos3nv5z7vc23ol2kjjeq72id.onion/")}));const util=floBlockchainAPI.util={};util.Sat_to_FLO=value=>parseFloat((value/1e8).toFixed(8)),util.FLO_to_Sat=value=>parseInt(1e8*value),util.toFixed=value=>parseFloat(value.toFixed(8)),Object.defineProperties(floBlockchainAPI,{sendAmt:{get:()=>DEFAULT.sendAmt,set:amt=>isNaN(amt)?null:DEFAULT.sendAmt=amt},fee:{get:()=>DEFAULT.fee,set:fee=>isNaN(fee)?null:DEFAULT.fee=fee},defaultReceiver:{get:()=>DEFAULT.receiverID,set:floID=>DEFAULT.receiverID=floID},blockchain:{get:()=>DEFAULT.blockchain}}),floGlobals.sendAmt&&(floBlockchainAPI.sendAmt=floGlobals.sendAmt),floGlobals.fee&&(floBlockchainAPI.fee=floGlobals.fee),Object.defineProperties(floGlobals,{sendAmt:{get:()=>DEFAULT.sendAmt,set:amt=>isNaN(amt)?null:DEFAULT.sendAmt=amt},fee:{get:()=>DEFAULT.fee,set:fee=>isNaN(fee)?null:DEFAULT.fee=fee}});const allServerList=new Set(floGlobals.apiURL&&floGlobals.apiURL[DEFAULT.blockchain]?floGlobals.apiURL[DEFAULT.blockchain]:DEFAULT.apiURL[DEFAULT.blockchain]);var serverList=Array.from(allServerList),curPos=floCrypto.randInt(0,serverList.length-1);function fetch_retry(apicall,rm_node){return new Promise(((resolve,reject)=>{let i=serverList.indexOf(rm_node);-1!=i&&serverList.splice(i,1),curPos=floCrypto.randInt(0,serverList.length-1),fetch_api(apicall,!1).then((result=>resolve(result))).catch((error=>reject(error)))}))}function fetch_api(apicall,ic=!0){return new Promise(((resolve,reject)=>{if(0===serverList.length)ic?(serverList=Array.from(allServerList),curPos=floCrypto.randInt(0,serverList.length-1),fetch_api(apicall,!1).then((result=>resolve(result))).catch((error=>reject(error)))):reject("No FLO blockbook server working");else{let serverURL=serverList[curPos];fetch(serverURL+apicall).then((response=>{response.ok?response.json().then((data=>resolve(data))):fetch_retry(apicall,serverURL).then((result=>resolve(result))).catch((error=>reject(error)))})).catch((error=>{fetch_retry(apicall,serverURL).then((result=>resolve(result))).catch((error=>reject(error)))}))}}))}Object.defineProperties(floBlockchainAPI,{serverList:{get:()=>Array.from(serverList)},current_server:{get:()=>serverList[curPos]}});const promisedAPI=floBlockchainAPI.promisedAPI=floBlockchainAPI.fetch=function(apicall,query_params=void 0){return new Promise(((resolve,reject)=>{isUndefined(query_params)||(apicall+="?"+new URLSearchParams(JSON.parse(JSON.stringify(query_params))).toString()),fetch_api(apicall).then((result=>resolve(result))).catch((error=>reject(error)))}))},getBalance=floBlockchainAPI.getBalance=function(addr){return new Promise(((resolve,reject)=>{promisedAPI(`api/address/${addr}`,{details:"basic"}).then((result=>resolve(result.balance))).catch((error=>reject(error)))}))};const getUTXOs=address=>new Promise(((resolve,reject)=>{promisedAPI(`api/utxo/${address}`,{confirmed:!0}).then((utxos=>{let scriptPubKey=function(address){var tx=bitjs.transaction();tx.addoutput(address,0);let outputBuffer=tx.outputs.pop().script;return Crypto.util.bytesToHex(outputBuffer)}(address);utxos.forEach((u=>u.scriptPubKey=scriptPubKey)),resolve(utxos)})).catch((error=>reject(error)))})),createTx=function(senderAddr,receiverAddr,sendAmt,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>floCrypto.validateASCII(floData)?floCrypto.validateFloID(senderAddr,!0)?floCrypto.validateFloID(receiverAddr)?"number"!=typeof sendAmt||sendAmt<=0?reject(`Invalid sendAmt : ${sendAmt}`):void getBalance(senderAddr).then((balance=>{var fee=DEFAULT.fee;if(balance{for(var trx=bitjs.transaction(),utxoAmt=0,i=utxos.length-1;i>=0&&utxoAmtDEFAULT.minChangeAmt&&trx.addoutput(senderAddr,change),trx.addflodata(floData.replace(/\n/g," ")),resolve(trx)}})).catch((error=>reject(error)))})).catch((error=>reject(error))):reject(`Invalid address : ${receiverAddr}`):reject(`Invalid address : ${senderAddr}`):reject("Invalid FLO_Data: only printable ASCII characters are allowed")))};floBlockchainAPI.createTx=function(senderAddr,receiverAddr,sendAmt,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>{createTx(senderAddr,receiverAddr,sendAmt,floData,strict_utxo).then((trx=>resolve(trx.serialize()))).catch((error=>reject(error)))}))};const sendTx=floBlockchainAPI.sendTx=function(senderAddr,receiverAddr,sendAmt,privKey,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>floCrypto.validateFloID(senderAddr,!0)?privKey.length<1||!floCrypto.verifyPrivKey(privKey,senderAddr)?reject("Invalid Private key!"):void createTx(senderAddr,receiverAddr,sendAmt,floData,strict_utxo).then((trx=>{var signedTxHash=trx.sign(privKey,1);broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error))):reject(`Invalid address : ${senderAddr}`)))};floBlockchainAPI.writeData=function(senderAddr,data,privKey,receiverAddr=DEFAULT.receiverID,options={}){let strict_utxo=!1!==options.strict_utxo,sendAmt=isNaN(options.sendAmt)?DEFAULT.sendAmt:options.sendAmt;return new Promise(((resolve,reject)=>{"string"!=typeof data&&(data=JSON.stringify(data)),sendTx(senderAddr,receiverAddr,sendAmt,privKey,data,strict_utxo).then((txid=>resolve(txid))).catch((error=>reject(error)))}))},floBlockchainAPI.mergeUTXOs=function(floID,privKey,floData=""){return new Promise(((resolve,reject)=>{if(!floCrypto.validateFloID(floID,!0))return reject("Invalid floID");if(!floCrypto.verifyPrivKey(privKey,floID))return reject("Invalid Private Key");if(!floCrypto.validateASCII(floData))return reject("Invalid FLO_Data: only printable ASCII characters are allowed");var trx=bitjs.transaction(),utxoAmt=0,fee=DEFAULT.fee;getUTXOs(floID).then((utxos=>{for(var i=utxos.length-1;i>=0;i--)utxos[i].confirmations&&(trx.addinput(utxos[i].txid,utxos[i].vout,utxos[i].scriptPubKey),utxoAmt+=utxos[i].amount);trx.addoutput(floID,utxoAmt-fee),trx.addflodata(floData.replace(/\n/g," "));var signedTxHash=trx.sign(privKey,1);broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floBlockchainAPI.splitUTXOs=function(floID,privKey,count,floData=""){return new Promise(((resolve,reject)=>{if(!floCrypto.validateFloID(floID,!0))return reject("Invalid floID");if(!floCrypto.verifyPrivKey(privKey,floID))return reject("Invalid Private Key");if(!floCrypto.validateASCII(floData))return reject("Invalid FLO_Data: only printable ASCII characters are allowed");var fee=DEFAULT.fee,splitAmt=DEFAULT.sendAmt+fee,totalAmt=splitAmt*count;getBalance(floID).then((balance=>{var fee=DEFAULT.fee;if(balance{var trx=bitjs.transaction(),utxoAmt=0;for(let i=utxos.length-1;i>=0&&utxoAmtDEFAULT.minChangeAmt&&trx.addoutput(floID,change),trx.addflodata(floData.replace(/\n/g," "));var signedTxHash=trx.sign(privKey,1);broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))}})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floBlockchainAPI.writeDataMultiple=function(senderPrivKeys,data,receivers=[DEFAULT.receiverID],options={}){return new Promise(((resolve,reject)=>{if(!Array.isArray(senderPrivKeys))return reject("Invalid senderPrivKeys: SenderPrivKeys must be Array");if(!1===options.preserveRatio){let tmp={},amount=DEFAULT.sendAmt*receivers.length/senderPrivKeys.length;senderPrivKeys.forEach((key=>tmp[key]=amount)),senderPrivKeys=tmp}if(!Array.isArray(receivers))return reject("Invalid receivers: Receivers must be Array");{let tmp={},amount=options.sendAmt||DEFAULT.sendAmt;receivers.forEach((floID=>tmp[floID]=amount)),receivers=tmp}"string"!=typeof data&&(data=JSON.stringify(data)),sendTxMultiple(senderPrivKeys,receivers,data).then((txid=>resolve(txid))).catch((error=>reject(error)))}))};const sendTxMultiple=floBlockchainAPI.sendTxMultiple=function(senderPrivKeys,receivers,floData=""){return new Promise(((resolve,reject)=>{if(!floCrypto.validateASCII(floData))return reject("Invalid FLO_Data: only printable ASCII characters are allowed");let preserveRatio,senders={};try{let invalids={InvalidSenderPrivKeys:[],InvalidSenderAmountFor:[],InvalidReceiverIDs:[],InvalidReceiveAmountFor:[]},inputVal=0,outputVal=0;if(Array.isArray(senderPrivKeys))senderPrivKeys.forEach((key=>{try{if(key){let floID=floCrypto.getFloID(key);senders[floID]={wif:key}}else invalids.InvalidSenderPrivKeys.push(key)}catch(error){invalids.InvalidSenderPrivKeys.push(key)}})),preserveRatio=!0;else{for(let key in senderPrivKeys)try{if(key){"number"!=typeof senderPrivKeys[key]||senderPrivKeys[key]<=0?invalids.InvalidSenderAmountFor.push(key):inputVal+=senderPrivKeys[key];let floID=floCrypto.getFloID(key);senders[floID]={wif:key,coins:senderPrivKeys[key]}}else invalids.InvalidSenderPrivKeys.push(key)}catch(error){invalids.InvalidSenderPrivKeys.push(key)}preserveRatio=!1}for(let floID in receivers)floCrypto.validateFloID(floID)||invalids.InvalidReceiverIDs.push(floID),"number"!=typeof receivers[floID]||receivers[floID]<=0?invalids.InvalidReceiveAmountFor.push(floID):outputVal+=receivers[floID];for(let i in invalids)invalids[i].length||delete invalids[i];if(Object.keys(invalids).length)return reject(invalids);if(!preserveRatio&&inputVal!=outputVal)return reject(`Input Amount (${inputVal}) not equal to Output Amount (${outputVal})`)}catch(error){return reject(error)}let promises=[];for(let floID in senders)promises.push(getBalance(floID));Promise.all(promises).then((results=>{let totalBalance=0,totalFee=DEFAULT.fee,balance={};if(!preserveRatio)var dividedFee=totalFee/Object.keys(senders).length;let insufficient=[];for(let floID in senders)balance[floID]=parseFloat(results.shift()),(isNaN(balance[floID])||preserveRatio&&balance[floID]<=totalFee||!preserveRatio&&balance[floID]{var trx=bitjs.transaction();for(let floID in senders){let sendAmt,utxos=results.shift();if(preserveRatio){let ratio=balance[floID]/totalBalance;sendAmt=totalSendAmt*ratio}else sendAmt=senders[floID].coins+dividedFee;let utxoAmt=0;for(let i=utxos.length-1;i>=0&&utxoAmt0&&trx.addoutput(floID,change)}for(let floID in receivers)trx.addoutput(floID,receivers[floID]);trx.addflodata(floData.replace(/\n/g," "));for(let floID in senders)trx.sign(senders[floID].wif,1);var signedTxHash=trx.serialize();broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},createMultisigTx=function(redeemScript,receivers,amounts,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>{var multisig=floCrypto.decodeRedeemScript(redeemScript);if(!multisig)return reject("Invalid redeemScript");var senderAddr=multisig.address;if(!floCrypto.validateFloID(senderAddr))return reject(`Invalid multisig : ${senderAddr}`);if(!floCrypto.validateASCII(floData))return reject("Invalid FLO_Data: only printable ASCII characters are allowed");Array.isArray(receivers)||(receivers=[receivers]);for(let r of receivers)if(!floCrypto.validateFloID(r))return reject(`Invalid address : ${r}`);if(Array.isArray(amounts)||(amounts=[amounts]),amounts.length!=receivers.length)return reject("Receivers and amounts have different length");var sendAmt=0;for(let a of amounts){if("number"!=typeof a||a<=0)return reject(`Invalid amount : ${a}`);sendAmt+=a}getBalance(senderAddr).then((balance=>{var fee=DEFAULT.fee;if(balance{for(var trx=bitjs.transaction(),utxoAmt=0,i=utxos.length-1;i>=0&&utxoAmtDEFAULT.minChangeAmt&&trx.addoutput(senderAddr,change),trx.addflodata(floData.replace(/\n/g," ")),resolve(trx)}})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))};floBlockchainAPI.createMultisigTx=function(redeemScript,receivers,amounts,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>{createMultisigTx(redeemScript,receivers,amounts,floData,strict_utxo).then((trx=>resolve(trx.serialize()))).catch((error=>reject(error)))}))};const sendMultisigTx=floBlockchainAPI.sendMultisigTx=function(redeemScript,privateKeys,receivers,amounts,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>{var multisig=floCrypto.decodeRedeemScript(redeemScript);if(!multisig)return reject("Invalid redeemScript");if(privateKeys.length{for(let pk of privateKeys)trx.sign(pk,1);var signedTxHash=trx.serialize();broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))};function deserializeTx(tx){if("string"==typeof tx||Array.isArray(tx))try{tx=bitjs.transaction(tx)}catch{throw"Invalid transaction hex"}else if("object"!=typeof tx||"function"!=typeof tx.sign)throw"Invalid transaction object";return tx}floBlockchainAPI.writeMultisigData=function(redeemScript,data,privatekeys,receiverAddr=DEFAULT.receiverID,options={}){let strict_utxo=!1!==options.strict_utxo,sendAmt=isNaN(options.sendAmt)?DEFAULT.sendAmt:options.sendAmt;return new Promise(((resolve,reject)=>{if(!floCrypto.validateFloID(receiverAddr))return reject(`Invalid receiver: ${receiverAddr}`);sendMultisigTx(redeemScript,privatekeys,receiverAddr,sendAmt,data,strict_utxo).then((txid=>resolve(txid))).catch((error=>reject(error)))}))},floBlockchainAPI.signTx=function(tx,privateKey,sighashtype=1){if(!floCrypto.getFloID(privateKey))throw"Invalid Private key";return(tx=deserializeTx(tx)).sign(privateKey,sighashtype)};const checkSigned=floBlockchainAPI.checkSigned=function(tx,bool=!0){tx=deserializeTx(tx);let n=[];for(let i=0;ix.t)throw"signaturesRequired is more than publicKeys";x.s!0!==x)).length:n};floBlockchainAPI.checkIfSameTx=function(tx1,tx2){if(tx1=deserializeTx(tx1),tx2=deserializeTx(tx2),tx1.inputs.length!==tx2.inputs.length||tx1.outputs.length!==tx2.outputs.length)return!1;if(tx1.floData!==tx2.floData)return!1;for(let i=0;inew Promise(((resolve,reject)=>{promisedAPI(`api/tx/${txid}`).then((result=>resolve(result.vout[i]))).catch((error=>reject(error)))}));function getOutputAddress(outscript){var bytes,version;switch(outscript[0]){case 118:bytes=outscript.slice(3,outscript.length-2),version=bitjs.pub;break;case 169:bytes=outscript.slice(2,outscript.length-1),version=bitjs.multisig;break;default:return}bytes.unshift(version);var checksum=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0}).slice(0,4);return bitjs.Base58.encode(bytes.concat(checksum))}floBlockchainAPI.parseTransaction=function(tx){return new Promise(((resolve,reject)=>{tx=deserializeTx(tx);let result={},promises=[];for(let i=0;i{result.inputs=inputs.map((inp=>Object({address:inp.scriptPubKey.addresses[0],value:parseFloat(inp.value)})));let signed=checkSigned(tx,!1);result.inputs.forEach(((inp,i)=>inp.signed=signed[i])),result.outputs=tx.outputs.map((out=>Object({address:getOutputAddress(out.script),value:util.Sat_to_FLO(out.value)}))),result.total_input=parseFloat(result.inputs.reduce(((a,inp)=>a+inp.value),0).toFixed(8)),result.total_output=parseFloat(result.outputs.reduce(((a,out)=>a+out.value),0).toFixed(8)),result.fee=parseFloat((result.total_input-result.total_output).toFixed(8)),result.floData=tx.floData,resolve(result)})).catch((error=>reject(error)))}))};const broadcastTx=floBlockchainAPI.broadcastTx=function(signedTxHash){return new Promise(((resolve,reject)=>{if(signedTxHash.length<1)return reject("Empty Transaction Data");promisedAPI("/api/sendtx/"+signedTxHash).then((response=>resolve(response.result))).catch((error=>reject(error)))}))},getTx=floBlockchainAPI.getTx=function(txid){return new Promise(((resolve,reject)=>{promisedAPI(`api/tx/${txid}`).then((response=>resolve(response))).catch((error=>reject(error)))}))},waitForConfirmation=floBlockchainAPI.waitForConfirmation=function(txid,max_retry=-1,retry_timeout=20){return new Promise(((resolve,reject)=>{setTimeout((function(){getTx(txid).then((tx=>tx?tx.confirmations?resolve(tx):0===max_retry?reject("Waiting timeout: tx still not confirmed"):void waitForConfirmation(txid,max_retry=max_retry<0?-1:max_retry-1,retry_timeout).then((result=>resolve(result))).catch((error=>reject(error))):reject("Transaction not found"))).catch((error=>reject(error)))}),1e3*retry_timeout)}))},readTxs=floBlockchainAPI.readTxs=function(addr,options={}){return new Promise(((resolve,reject)=>{let query_params={details:"txs"};!isUndefined(options.page)&&Number.isInteger(options.page)&&(query_params.page=options.page),!isUndefined(options.pageSize)&&Number.isInteger(options.pageSize)&&(query_params.pageSize=options.pageSize),options.confirmed&&(query_params.confirmed=!0),promisedAPI(`api/address/${addr}`,query_params).then((response=>{Array.isArray(response.txs)||(response.txs=[]),resolve(response)})).catch((error=>reject(error)))}))};function readAllTxs_oldSupport(addr,options,ignoreOld=0,cacheTotal=0){return new Promise(((resolve,reject)=>{readTxs(addr,options).then((response=>{cacheTotal+=response.txs.length;let n_remaining=response.txApperances-cacheTotal;if(n_remainingresolve(response.txs.concat(result)))).catch((error=>reject(error))))})).catch((error=>reject(error)))}))}function readAllTxs_new(addr,options,lastItem){return new Promise(((resolve,reject)=>{readTxs(addr,options).then((response=>{let i=response.txs.findIndex((t=>t.txid===lastItem));-1!=i?resolve(response.txs.slice(0,i)):response.page==response.totalPages?resolve(response.txs):(options.page=response.page+1,readAllTxs_new(addr,options,lastItem).then((result=>resolve(response.txs.concat(result)))).catch((error=>reject(error))))})).catch((error=>reject(error)))}))}const readAllTxs=floBlockchainAPI.readAllTxs=function(addr,options={}){return new Promise(((resolve,reject)=>{Number.isInteger(options.ignoreOld)?readAllTxs_oldSupport(addr,options,options.ignoreOld).then((txs=>{let last_tx=txs.find((t=>t.confirmations>0)),new_lastItem=last_tx?last_tx.txid:options.ignoreOld;resolve({lastItem:new_lastItem,items:txs})})).catch((error=>reject(error))):readAllTxs_new(addr,options,options.after).then((txs=>{let last_tx=txs.find((t=>t.confirmations>0)),new_lastItem=last_tx?last_tx.txid:options.after;resolve({lastItem:new_lastItem,items:txs})})).catch((error=>reject(error)))}))};floBlockchainAPI.readData=function(addr,options={}){return new Promise(((resolve,reject)=>{let query_options={};query_options.confirmed=!!isUndefined(options.confirmed)||options.confirmed,isUndefined(options.after)?isUndefined(options.ignoreOld)||(query_options.ignoreOld=options.ignoreOld):query_options.after=options.after,readAllTxs(addr,query_options).then((response=>{"string"==typeof options.senders&&(options.senders=[options.senders]),"string"==typeof options.receivers&&(options.receivers=[options.receivers]);const filteredData=response.items.filter((tx=>{if(!tx.confirmations)return!1;if(options.sentOnly&&!tx.vin.some((vin=>vin.addresses[0]===addr)))return!1;if(Array.isArray(options.senders)&&!tx.vin.some((vin=>options.senders.includes(vin.addresses[0]))))return!1;if(options.receivedOnly&&!tx.vout.some((vout=>vout.scriptPubKey.addresses[0]===addr)))return!1;if(Array.isArray(options.receivers)&&!tx.vout.some((vout=>options.receivers.includes(vout.scriptPubKey.addresses[0]))))return!1;if(options.pattern)try{let jsonContent=JSON.parse(tx.floData);if(!Object.keys(jsonContent).includes(options.pattern))return!1}catch{return!1}return!(options.filter&&!options.filter(tx.floData))})).map((tx=>options.tx?{txid:tx.txid,time:tx.time,blockheight:tx.blockheight,senders:new Set(tx.vin.map((v=>v.addresses[0]))),receivers:new Set(tx.vout.map((v=>v.scriptPubKey.addresses[0]))),data:tx.floData}:tx.floData)),result={lastItem:response.lastItem};options.tx?result.items=filteredData:result.data=filteredData,resolve(result)})).catch((error=>reject(error)))}))};const getLatestData=floBlockchainAPI.getLatestData=function(addr,caseFn,options={}){return new Promise(((resolve,reject)=>{let new_lastItem,query_options={};query_options.confirmed=!!isUndefined(options.confirmed)||options.confirmed,isUndefined(options.page)||(query_options.page=options.page),readTxs(addr,query_options).then((response=>{if(!new_lastItem){let last_tx=response.items.find((t=>t.confirmations>0));last_tx&&(new_lastItem=last_tx.txid)}"string"==typeof options.senders&&(options.senders=[options.senders]),"string"==typeof options.receivers&&(options.receivers=[options.receivers]);let i_after=response.txs.findIndex((t=>t.txid===options.after));-1!=i_after&&response.items.splice(i_after);var item=response.items.find((tx=>!!tx.confirmations&&(!(options.sentOnly&&!tx.vin.some((vin=>vin.addresses[0]===addr)))&&(!(Array.isArray(options.senders)&&!tx.vin.some((vin=>options.senders.includes(vin.addresses[0]))))&&(!(options.receivedOnly&&!tx.vout.some((vout=>vout.scriptPubKey.addresses[0]===addr)))&&(!(Array.isArray(options.receivers)&&!tx.vout.some((vout=>options.receivers.includes(vout.scriptPubKey.addresses[0]))))&&!!caseFn(tx.floData)))))));if(!isUndefined(item)){const result={lastItem:new_lastItem||item.txid};return options.tx?result.item={txid:item.txid,time:item.time,blockheight:item.blockheight,senders:new Set(item.vin.map((v=>v.addresses[0]))),receivers:new Set(item.vout.map((v=>v.scriptPubKey.addresses[0]))),data:item.floData}:result.data=item.floData,resolve(result)}response.page==response.totalPages||-1!=i_after?resolve({lastItem:new_lastItem||options.after}):(options.page=response.page+1,getLatestData(addr,caseFn,options).then((result=>resolve(result))).catch((error=>reject(error))))})).catch((error=>reject(error)))}))}}(); \ No newline at end of file +!function(EXPORTS){"use strict";const floBlockchainAPI="object"===typeof module?module.exports:window.floBlockchainAPI={},DEFAULT={blockchain:floGlobals.blockchain,apiURL:{FLO:["https://blockbook.ranchimall.net/"],FLO_TEST:["https://blockbook-testnet.ranchimall.net/"]},sendAmt:3e-4,fee:2e-4,minChangeAmt:2e-4,receiverID:floGlobals.adminID},isUndefined=val=>void 0===val,checkIfTor=floBlockchainAPI.checkIfTor=()=>fetch("https://check.torproject.org/api/ip").then((res=>res.json())).then((res=>res.IsTor)).catch((e=>(console.error(e),!1)));let isTor=!1;checkIfTor().then((result=>{isTor=result,isTor&&(DEFAULT.apiURL.FLO.push("http://xge4kejxl6xs4cad3u3a7dnw7idndlkn3vmyo33t3a4ctk566y65eoad.onion/"),DEFAULT.apiURL.FLO_TEST.push("http://fdjrsde2qhfecvx6fkgmcidwkp34bdek7jo4y2fpqatrhzxtxkk6f4ad.onion/"))}));const util=floBlockchainAPI.util={};util.Sat_to_FLO=value=>parseFloat((value/1e8).toFixed(8)),util.FLO_to_Sat=value=>parseInt(1e8*value),util.toFixed=value=>parseFloat(value.toFixed(8)),Object.defineProperties(floBlockchainAPI,{sendAmt:{get:()=>DEFAULT.sendAmt,set:amt=>isNaN(amt)?null:DEFAULT.sendAmt=amt},fee:{get:()=>DEFAULT.fee,set:fee=>isNaN(fee)?null:DEFAULT.fee=fee},defaultReceiver:{get:()=>DEFAULT.receiverID,set:floID=>DEFAULT.receiverID=floID},blockchain:{get:()=>DEFAULT.blockchain}}),floGlobals.sendAmt&&(floBlockchainAPI.sendAmt=floGlobals.sendAmt),floGlobals.fee&&(floBlockchainAPI.fee=floGlobals.fee),Object.defineProperties(floGlobals,{sendAmt:{get:()=>DEFAULT.sendAmt,set:amt=>isNaN(amt)?null:DEFAULT.sendAmt=amt},fee:{get:()=>DEFAULT.fee,set:fee=>isNaN(fee)?null:DEFAULT.fee=fee}});const allServerList=new Set(floGlobals.apiURL&&floGlobals.apiURL[DEFAULT.blockchain]?floGlobals.apiURL[DEFAULT.blockchain]:DEFAULT.apiURL[DEFAULT.blockchain]);var serverList=Array.from(allServerList),curPos=floCrypto.randInt(0,serverList.length-1);function fetch_retry(apicall,rm_node){return new Promise(((resolve,reject)=>{let i=serverList.indexOf(rm_node);-1!=i&&serverList.splice(i,1),curPos=floCrypto.randInt(0,serverList.length-1),fetch_api(apicall,!1).then((result=>resolve(result))).catch((error=>reject(error)))}))}function fetch_api(apicall,ic=!0){return new Promise(((resolve,reject)=>{if(0===serverList.length)ic?(serverList=Array.from(allServerList),curPos=floCrypto.randInt(0,serverList.length-1),fetch_api(apicall,!1).then((result=>resolve(result))).catch((error=>reject(error)))):reject("No FLO blockbook server working");else{let serverURL=serverList[curPos];fetch(serverURL+apicall).then((response=>{response.ok?response.json().then((data=>resolve(data))):fetch_retry(apicall,serverURL).then((result=>resolve(result))).catch((error=>reject(error)))})).catch((error=>{fetch_retry(apicall,serverURL).then((result=>resolve(result))).catch((error=>reject(error)))}))}}))}Object.defineProperties(floBlockchainAPI,{serverList:{get:()=>Array.from(serverList)},current_server:{get:()=>serverList[curPos]}});const promisedAPI=floBlockchainAPI.promisedAPI=floBlockchainAPI.fetch=function(apicall,query_params=void 0){return new Promise(((resolve,reject)=>{isUndefined(query_params)||(apicall+="?"+new URLSearchParams(JSON.parse(JSON.stringify(query_params))).toString()),fetch_api(apicall).then((result=>resolve(result))).catch((error=>reject(error)))}))},getBalance=floBlockchainAPI.getBalance=function(addr){return new Promise(((resolve,reject)=>{promisedAPI(`api/address/${addr}`,{details:"basic"}).then((result=>resolve(result.balance))).catch((error=>reject(error)))}))};const getUTXOs=address=>new Promise(((resolve,reject)=>{promisedAPI(`api/utxo/${address}`,{confirmed:!0}).then((utxos=>{let scriptPubKey=function(address){var tx=bitjs.transaction();tx.addoutput(address,0);let outputBuffer=tx.outputs.pop().script;return Crypto.util.bytesToHex(outputBuffer)}(address);utxos.forEach((u=>u.scriptPubKey=scriptPubKey)),resolve(utxos)})).catch((error=>reject(error)))})),createTx=function(senderAddr,receiverAddr,sendAmt,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>floCrypto.validateASCII(floData)?floCrypto.validateFloID(senderAddr,!0)?floCrypto.validateFloID(receiverAddr)?"number"!=typeof sendAmt||sendAmt<=0?reject(`Invalid sendAmt : ${sendAmt}`):void getBalance(senderAddr).then((balance=>{var fee=DEFAULT.fee;if(balance{for(var trx=bitjs.transaction(),utxoAmt=0,i=utxos.length-1;i>=0&&utxoAmtDEFAULT.minChangeAmt&&trx.addoutput(senderAddr,change),trx.addflodata(floData.replace(/\n/g," ")),resolve(trx)}})).catch((error=>reject(error)))})).catch((error=>reject(error))):reject(`Invalid address : ${receiverAddr}`):reject(`Invalid address : ${senderAddr}`):reject("Invalid FLO_Data: only printable ASCII characters are allowed")))};floBlockchainAPI.createTx=function(senderAddr,receiverAddr,sendAmt,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>{createTx(senderAddr,receiverAddr,sendAmt,floData,strict_utxo).then((trx=>resolve(trx.serialize()))).catch((error=>reject(error)))}))};const sendTx=floBlockchainAPI.sendTx=function(senderAddr,receiverAddr,sendAmt,privKey,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>floCrypto.validateFloID(senderAddr,!0)?privKey.length<1||!floCrypto.verifyPrivKey(privKey,senderAddr)?reject("Invalid Private key!"):void createTx(senderAddr,receiverAddr,sendAmt,floData,strict_utxo).then((trx=>{var signedTxHash=trx.sign(privKey,1);broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error))):reject(`Invalid address : ${senderAddr}`)))};floBlockchainAPI.writeData=function(senderAddr,data,privKey,receiverAddr=DEFAULT.receiverID,options={}){let strict_utxo=!1!==options.strict_utxo,sendAmt=isNaN(options.sendAmt)?DEFAULT.sendAmt:options.sendAmt;return new Promise(((resolve,reject)=>{"string"!=typeof data&&(data=JSON.stringify(data)),sendTx(senderAddr,receiverAddr,sendAmt,privKey,data,strict_utxo).then((txid=>resolve(txid))).catch((error=>reject(error)))}))},floBlockchainAPI.mergeUTXOs=function(floID,privKey,floData=""){return new Promise(((resolve,reject)=>{if(!floCrypto.validateFloID(floID,!0))return reject("Invalid floID");if(!floCrypto.verifyPrivKey(privKey,floID))return reject("Invalid Private Key");if(!floCrypto.validateASCII(floData))return reject("Invalid FLO_Data: only printable ASCII characters are allowed");var trx=bitjs.transaction(),utxoAmt=0,fee=DEFAULT.fee;getUTXOs(floID).then((utxos=>{for(var i=utxos.length-1;i>=0;i--)utxos[i].confirmations&&(trx.addinput(utxos[i].txid,utxos[i].vout,utxos[i].scriptPubKey),utxoAmt+=utxos[i].amount);trx.addoutput(floID,utxoAmt-fee),trx.addflodata(floData.replace(/\n/g," "));var signedTxHash=trx.sign(privKey,1);broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floBlockchainAPI.splitUTXOs=function(floID,privKey,count,floData=""){return new Promise(((resolve,reject)=>{if(!floCrypto.validateFloID(floID,!0))return reject("Invalid floID");if(!floCrypto.verifyPrivKey(privKey,floID))return reject("Invalid Private Key");if(!floCrypto.validateASCII(floData))return reject("Invalid FLO_Data: only printable ASCII characters are allowed");var fee=DEFAULT.fee,splitAmt=DEFAULT.sendAmt+fee,totalAmt=splitAmt*count;getBalance(floID).then((balance=>{var fee=DEFAULT.fee;if(balance{var trx=bitjs.transaction(),utxoAmt=0;for(let i=utxos.length-1;i>=0&&utxoAmtDEFAULT.minChangeAmt&&trx.addoutput(floID,change),trx.addflodata(floData.replace(/\n/g," "));var signedTxHash=trx.sign(privKey,1);broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))}})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floBlockchainAPI.writeDataMultiple=function(senderPrivKeys,data,receivers=[DEFAULT.receiverID],options={}){return new Promise(((resolve,reject)=>{if(!Array.isArray(senderPrivKeys))return reject("Invalid senderPrivKeys: SenderPrivKeys must be Array");if(!1===options.preserveRatio){let tmp={},amount=DEFAULT.sendAmt*receivers.length/senderPrivKeys.length;senderPrivKeys.forEach((key=>tmp[key]=amount)),senderPrivKeys=tmp}if(!Array.isArray(receivers))return reject("Invalid receivers: Receivers must be Array");{let tmp={},amount=options.sendAmt||DEFAULT.sendAmt;receivers.forEach((floID=>tmp[floID]=amount)),receivers=tmp}"string"!=typeof data&&(data=JSON.stringify(data)),sendTxMultiple(senderPrivKeys,receivers,data).then((txid=>resolve(txid))).catch((error=>reject(error)))}))};const sendTxMultiple=floBlockchainAPI.sendTxMultiple=function(senderPrivKeys,receivers,floData=""){return new Promise(((resolve,reject)=>{if(!floCrypto.validateASCII(floData))return reject("Invalid FLO_Data: only printable ASCII characters are allowed");let preserveRatio,senders={};try{let invalids={InvalidSenderPrivKeys:[],InvalidSenderAmountFor:[],InvalidReceiverIDs:[],InvalidReceiveAmountFor:[]},inputVal=0,outputVal=0;if(Array.isArray(senderPrivKeys))senderPrivKeys.forEach((key=>{try{if(key){let floID=floCrypto.getFloID(key);senders[floID]={wif:key}}else invalids.InvalidSenderPrivKeys.push(key)}catch(error){invalids.InvalidSenderPrivKeys.push(key)}})),preserveRatio=!0;else{for(let key in senderPrivKeys)try{if(key){"number"!=typeof senderPrivKeys[key]||senderPrivKeys[key]<=0?invalids.InvalidSenderAmountFor.push(key):inputVal+=senderPrivKeys[key];let floID=floCrypto.getFloID(key);senders[floID]={wif:key,coins:senderPrivKeys[key]}}else invalids.InvalidSenderPrivKeys.push(key)}catch(error){invalids.InvalidSenderPrivKeys.push(key)}preserveRatio=!1}for(let floID in receivers)floCrypto.validateFloID(floID)||invalids.InvalidReceiverIDs.push(floID),"number"!=typeof receivers[floID]||receivers[floID]<=0?invalids.InvalidReceiveAmountFor.push(floID):outputVal+=receivers[floID];for(let i in invalids)invalids[i].length||delete invalids[i];if(Object.keys(invalids).length)return reject(invalids);if(!preserveRatio&&inputVal!=outputVal)return reject(`Input Amount (${inputVal}) not equal to Output Amount (${outputVal})`)}catch(error){return reject(error)}let promises=[];for(let floID in senders)promises.push(getBalance(floID));Promise.all(promises).then((results=>{let totalBalance=0,totalFee=DEFAULT.fee,balance={};if(!preserveRatio)var dividedFee=totalFee/Object.keys(senders).length;let insufficient=[];for(let floID in senders)balance[floID]=parseFloat(results.shift()),(isNaN(balance[floID])||preserveRatio&&balance[floID]<=totalFee||!preserveRatio&&balance[floID]{var trx=bitjs.transaction();for(let floID in senders){let sendAmt,utxos=results.shift();if(preserveRatio){let ratio=balance[floID]/totalBalance;sendAmt=totalSendAmt*ratio}else sendAmt=senders[floID].coins+dividedFee;let utxoAmt=0;for(let i=utxos.length-1;i>=0&&utxoAmt0&&trx.addoutput(floID,change)}for(let floID in receivers)trx.addoutput(floID,receivers[floID]);trx.addflodata(floData.replace(/\n/g," "));for(let floID in senders)trx.sign(senders[floID].wif,1);var signedTxHash=trx.serialize();broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},createMultisigTx=function(redeemScript,receivers,amounts,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>{var multisig=floCrypto.decodeRedeemScript(redeemScript);if(!multisig)return reject("Invalid redeemScript");var senderAddr=multisig.address;if(!floCrypto.validateFloID(senderAddr))return reject(`Invalid multisig : ${senderAddr}`);if(!floCrypto.validateASCII(floData))return reject("Invalid FLO_Data: only printable ASCII characters are allowed");Array.isArray(receivers)||(receivers=[receivers]);for(let r of receivers)if(!floCrypto.validateFloID(r))return reject(`Invalid address : ${r}`);if(Array.isArray(amounts)||(amounts=[amounts]),amounts.length!=receivers.length)return reject("Receivers and amounts have different length");var sendAmt=0;for(let a of amounts){if("number"!=typeof a||a<=0)return reject(`Invalid amount : ${a}`);sendAmt+=a}getBalance(senderAddr).then((balance=>{var fee=DEFAULT.fee;if(balance{for(var trx=bitjs.transaction(),utxoAmt=0,i=utxos.length-1;i>=0&&utxoAmtDEFAULT.minChangeAmt&&trx.addoutput(senderAddr,change),trx.addflodata(floData.replace(/\n/g," ")),resolve(trx)}})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))};floBlockchainAPI.createMultisigTx=function(redeemScript,receivers,amounts,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>{createMultisigTx(redeemScript,receivers,amounts,floData,strict_utxo).then((trx=>resolve(trx.serialize()))).catch((error=>reject(error)))}))};const sendMultisigTx=floBlockchainAPI.sendMultisigTx=function(redeemScript,privateKeys,receivers,amounts,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>{var multisig=floCrypto.decodeRedeemScript(redeemScript);if(!multisig)return reject("Invalid redeemScript");if(privateKeys.length{for(let pk of privateKeys)trx.sign(pk,1);var signedTxHash=trx.serialize();broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))};function deserializeTx(tx){if("string"==typeof tx||Array.isArray(tx))try{tx=bitjs.transaction(tx)}catch{throw"Invalid transaction hex"}else if("object"!=typeof tx||"function"!=typeof tx.sign)throw"Invalid transaction object";return tx}floBlockchainAPI.writeMultisigData=function(redeemScript,data,privatekeys,receiverAddr=DEFAULT.receiverID,options={}){let strict_utxo=!1!==options.strict_utxo,sendAmt=isNaN(options.sendAmt)?DEFAULT.sendAmt:options.sendAmt;return new Promise(((resolve,reject)=>{if(!floCrypto.validateFloID(receiverAddr))return reject(`Invalid receiver: ${receiverAddr}`);sendMultisigTx(redeemScript,privatekeys,receiverAddr,sendAmt,data,strict_utxo).then((txid=>resolve(txid))).catch((error=>reject(error)))}))},floBlockchainAPI.signTx=function(tx,privateKey,sighashtype=1){if(!floCrypto.getFloID(privateKey))throw"Invalid Private key";return(tx=deserializeTx(tx)).sign(privateKey,sighashtype)};const checkSigned=floBlockchainAPI.checkSigned=function(tx,bool=!0){tx=deserializeTx(tx);let n=[];for(let i=0;ix.t)throw"signaturesRequired is more than publicKeys";x.s!0!==x)).length:n};floBlockchainAPI.checkIfSameTx=function(tx1,tx2){if(tx1=deserializeTx(tx1),tx2=deserializeTx(tx2),tx1.inputs.length!==tx2.inputs.length||tx1.outputs.length!==tx2.outputs.length)return!1;if(tx1.floData!==tx2.floData)return!1;for(let i=0;inew Promise(((resolve,reject)=>{promisedAPI(`api/tx/${txid}`).then((result=>resolve(result.vout[i]))).catch((error=>reject(error)))}));function getOutputAddress(outscript){var bytes,version;switch(outscript[0]){case 118:bytes=outscript.slice(3,outscript.length-2),version=bitjs.pub;break;case 169:bytes=outscript.slice(2,outscript.length-1),version=bitjs.multisig;break;default:return}bytes.unshift(version);var checksum=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0}).slice(0,4);return bitjs.Base58.encode(bytes.concat(checksum))}floBlockchainAPI.parseTransaction=function(tx){return new Promise(((resolve,reject)=>{tx=deserializeTx(tx);let result={},promises=[];for(let i=0;i{result.inputs=inputs.map((inp=>Object({address:inp.scriptPubKey.addresses[0],value:parseFloat(inp.value)})));let signed=checkSigned(tx,!1);result.inputs.forEach(((inp,i)=>inp.signed=signed[i])),result.outputs=tx.outputs.map((out=>Object({address:getOutputAddress(out.script),value:util.Sat_to_FLO(out.value)}))),result.total_input=parseFloat(result.inputs.reduce(((a,inp)=>a+inp.value),0).toFixed(8)),result.total_output=parseFloat(result.outputs.reduce(((a,out)=>a+out.value),0).toFixed(8)),result.fee=parseFloat((result.total_input-result.total_output).toFixed(8)),result.floData=tx.floData,resolve(result)})).catch((error=>reject(error)))}))};const broadcastTx=floBlockchainAPI.broadcastTx=function(signedTxHash){return new Promise(((resolve,reject)=>{if(signedTxHash.length<1)return reject("Empty Transaction Data");promisedAPI("/api/sendtx/"+signedTxHash).then((response=>resolve(response.result))).catch((error=>reject(error)))}))},getTx=floBlockchainAPI.getTx=function(txid){return new Promise(((resolve,reject)=>{promisedAPI(`api/tx/${txid}`).then((response=>resolve(response))).catch((error=>reject(error)))}))},waitForConfirmation=floBlockchainAPI.waitForConfirmation=function(txid,max_retry=-1,retry_timeout=20){return new Promise(((resolve,reject)=>{setTimeout((function(){getTx(txid).then((tx=>tx?tx.confirmations?resolve(tx):0===max_retry?reject("Waiting timeout: tx still not confirmed"):void waitForConfirmation(txid,max_retry=max_retry<0?-1:max_retry-1,retry_timeout).then((result=>resolve(result))).catch((error=>reject(error))):reject("Transaction not found"))).catch((error=>reject(error)))}),1e3*retry_timeout)}))},readTxs=floBlockchainAPI.readTxs=function(addr,options={}){return new Promise(((resolve,reject)=>{let query_params={details:"txs"};!isUndefined(options.page)&&Number.isInteger(options.page)&&(query_params.page=options.page),!isUndefined(options.pageSize)&&Number.isInteger(options.pageSize)&&(query_params.pageSize=options.pageSize),options.confirmed&&(query_params.confirmed=!0),promisedAPI(`api/address/${addr}`,query_params).then((response=>{Array.isArray(response.txs)||(response.txs=[]),resolve(response)})).catch((error=>reject(error)))}))};function readAllTxs_oldSupport(addr,options,ignoreOld=0,cacheTotal=0){return new Promise(((resolve,reject)=>{readTxs(addr,options).then((response=>{cacheTotal+=response.txs.length;let n_remaining=response.txApperances-cacheTotal;if(n_remainingresolve(response.txs.concat(result)))).catch((error=>reject(error))))})).catch((error=>reject(error)))}))}function readAllTxs_new(addr,options,lastItem){return new Promise(((resolve,reject)=>{readTxs(addr,options).then((response=>{let i=response.txs.findIndex((t=>t.txid===lastItem));-1!=i?resolve(response.txs.slice(0,i)):response.page==response.totalPages?resolve(response.txs):(options.page=response.page+1,readAllTxs_new(addr,options,lastItem).then((result=>resolve(response.txs.concat(result)))).catch((error=>reject(error))))})).catch((error=>reject(error)))}))}const readAllTxs=floBlockchainAPI.readAllTxs=function(addr,options={}){return new Promise(((resolve,reject)=>{Number.isInteger(options.ignoreOld)?readAllTxs_oldSupport(addr,options,options.ignoreOld).then((txs=>{let last_tx=txs.find((t=>t.confirmations>0)),new_lastItem=last_tx?last_tx.txid:options.ignoreOld;resolve({lastItem:new_lastItem,items:txs})})).catch((error=>reject(error))):readAllTxs_new(addr,options,options.after).then((txs=>{let last_tx=txs.find((t=>t.confirmations>0)),new_lastItem=last_tx?last_tx.txid:options.after;resolve({lastItem:new_lastItem,items:txs})})).catch((error=>reject(error)))}))};floBlockchainAPI.readData=function(addr,options={}){return new Promise(((resolve,reject)=>{let query_options={};query_options.confirmed=!!isUndefined(options.confirmed)||options.confirmed,isUndefined(options.after)?isUndefined(options.ignoreOld)||(query_options.ignoreOld=options.ignoreOld):query_options.after=options.after,readAllTxs(addr,query_options).then((response=>{"string"==typeof options.senders&&(options.senders=[options.senders]),"string"==typeof options.receivers&&(options.receivers=[options.receivers]);const filteredData=response.items.filter((tx=>{if(!tx.confirmations)return!1;if(options.sentOnly&&!tx.vin.some((vin=>vin.addresses[0]===addr)))return!1;if(Array.isArray(options.senders)&&!tx.vin.some((vin=>options.senders.includes(vin.addresses[0]))))return!1;if(options.receivedOnly&&!tx.vout.some((vout=>vout.scriptPubKey.addresses[0]===addr)))return!1;if(Array.isArray(options.receivers)&&!tx.vout.some((vout=>options.receivers.includes(vout.scriptPubKey.addresses[0]))))return!1;if(options.pattern)try{let jsonContent=JSON.parse(tx.floData);if(!Object.keys(jsonContent).includes(options.pattern))return!1}catch{return!1}return!(options.filter&&!options.filter(tx.floData))})).map((tx=>options.tx?{txid:tx.txid,time:tx.time,blockheight:tx.blockheight,senders:new Set(tx.vin.map((v=>v.addresses[0]))),receivers:new Set(tx.vout.map((v=>v.scriptPubKey.addresses[0]))),data:tx.floData}:tx.floData)),result={lastItem:response.lastItem};options.tx?result.items=filteredData:result.data=filteredData,resolve(result)})).catch((error=>reject(error)))}))};const getLatestData=floBlockchainAPI.getLatestData=function(addr,caseFn,options={}){return new Promise(((resolve,reject)=>{let new_lastItem,query_options={};query_options.confirmed=!!isUndefined(options.confirmed)||options.confirmed,isUndefined(options.page)||(query_options.page=options.page),readTxs(addr,query_options).then((response=>{if(!new_lastItem){let last_tx=response.items.find((t=>t.confirmations>0));last_tx&&(new_lastItem=last_tx.txid)}"string"==typeof options.senders&&(options.senders=[options.senders]),"string"==typeof options.receivers&&(options.receivers=[options.receivers]);let i_after=response.txs.findIndex((t=>t.txid===options.after));-1!=i_after&&response.items.splice(i_after);var item=response.items.find((tx=>!!tx.confirmations&&(!(options.sentOnly&&!tx.vin.some((vin=>vin.addresses[0]===addr)))&&(!(Array.isArray(options.senders)&&!tx.vin.some((vin=>options.senders.includes(vin.addresses[0]))))&&(!(options.receivedOnly&&!tx.vout.some((vout=>vout.scriptPubKey.addresses[0]===addr)))&&(!(Array.isArray(options.receivers)&&!tx.vout.some((vout=>options.receivers.includes(vout.scriptPubKey.addresses[0]))))&&!!caseFn(tx.floData)))))));if(!isUndefined(item)){const result={lastItem:new_lastItem||item.txid};return options.tx?result.item={txid:item.txid,time:item.time,blockheight:item.blockheight,senders:new Set(item.vin.map((v=>v.addresses[0]))),receivers:new Set(item.vout.map((v=>v.scriptPubKey.addresses[0]))),data:item.floData}:result.data=item.floData,resolve(result)}response.page==response.totalPages||-1!=i_after?resolve({lastItem:new_lastItem||options.after}):(options.page=response.page+1,getLatestData(addr,caseFn,options).then((result=>resolve(result))).catch((error=>reject(error))))})).catch((error=>reject(error)))}))}}(); \ No newline at end of file diff --git a/js/floCloudAPI.min.js b/js/floCloudAPI.min.js new file mode 100644 index 0000000..84fe9f4 --- /dev/null +++ b/js/floCloudAPI.min.js @@ -0,0 +1 @@ +!function(EXPORTS){"use strict";const floCloudAPI="object"===typeof module?module.exports:window.floCloudAPI={},DEFAULT={blockchainPrefix:35,SNStorageID:floGlobals.SNStorageID||"FNaN9McoBAEFUjkRmNQRYLmBF8SpS7Tgfk",adminID:floGlobals.adminID,application:floGlobals.application,SNStorageName:"SuperNodeStorage",callback:(d,e)=>console.debug(d,e)};var user_id,user_public,user_private,aes_key,appObjects,generalData,lastVC;function user(id,priv){if(!priv||!id)return user.clear();let pub=floCrypto.getPubKeyHex(priv);if(!pub||!floCrypto.verifyPubKey(pub,id))return user.clear();let n=floCrypto.randInt(12,20);return aes_key=floCrypto.randString(n),user_private=Crypto.AES.encrypt(priv,aes_key),user_public=pub,user_id=id}Object.defineProperties(user,{id:{get:()=>{if(!user_id)throw"User not set";return user_id}},public:{get:()=>{if(!user_public)throw"User not set";return user_public}},sign:{value:msg=>{if(!user_private)throw"User not set";return floCrypto.signData(msg,Crypto.AES.decrypt(user_private,aes_key))}},clear:{value:()=>user_id=user_public=user_private=aes_key=void 0}}),Object.defineProperties(floCloudAPI,{SNStorageID:{get:()=>DEFAULT.SNStorageID},SNStorageName:{get:()=>DEFAULT.SNStorageName},adminID:{get:()=>DEFAULT.adminID},application:{get:()=>DEFAULT.application},user:{get:()=>user}}),Object.defineProperties(floGlobals,{appObjects:{get:()=>appObjects,set:obj=>appObjects=obj},generalData:{get:()=>generalData,set:data=>generalData=data},generalDataset:{value:(type,options={})=>generalData[filterKey(type,options)]},lastVC:{get:()=>lastVC,set:vc=>lastVC=vc}});var kBucket,supernodes={};Object.defineProperty(floCloudAPI,"nodes",{get:()=>JSON.parse(JSON.stringify(supernodes))});const K_Bucket=floCloudAPI.K_Bucket=function(masterID,nodeList){const decodeID=floID=>{let k=bitjs.Base58.decode(floID);k.shift(),k.splice(-4,4);let decodedId=Crypto.util.bytesToHex(k),nodeIdBytes=new BigInteger(decodedId,16).toByteArrayUnsigned();return new Uint8Array(nodeIdBytes)},_KB=new BuildKBucket({localNodeId:decodeID(masterID)});nodeList.forEach((id=>_KB.add({id:decodeID(id),floID:id})));const _CO=nodeList.map((id=>[_KB.distance(_KB.localNodeId,decodeID(id)),id])).sort(((a,b)=>a[0]-b[0])).map((a=>a[1]));Object.defineProperty(this,"tree",{get:()=>_KB}),Object.defineProperty(this,"list",{get:()=>Array.from(_CO)}),this.isNode=floID=>_CO.includes(floID),this.innerNodes=function(id1,id2){if(!_CO.includes(id1)||!_CO.includes(id2))throw Error("Given nodes are not supernode");let iNodes=[];for(let i=_CO.indexOf(id1)+1;_CO[i]!=id2;i++)i<_CO.length?iNodes.push(_CO[i]):i=-1;return iNodes},this.outterNodes=function(id1,id2){if(!_CO.includes(id1)||!_CO.includes(id2))throw Error("Given nodes are not supernode");let oNodes=[];for(let i=_CO.indexOf(id2)+1;_CO[i]!=id1;i++)i<_CO.length?oNodes.push(_CO[i]):i=-1;return oNodes},this.prevNode=function(id,N=1){let n=N||_CO.length;if(!_CO.includes(id))throw Error("Given node is not supernode");let pNodes=[];for(let i=0,j=_CO.indexOf(id)-1;i-1?pNodes[i++]=_CO[j]:j=_CO.length;return 1==N?pNodes[0]:pNodes},this.nextNode=function(id,N=1){let n=N||_CO.length;if(!_CO.includes(id))throw Error("Given node is not supernode");n||(n=_CO.length);let nNodes=[];for(let i=0,j=_CO.indexOf(id)+1;ik.floID));return 1==N?cNodes[0]:cNodes}};floCloudAPI.init=function(nodes){return new Promise(((resolve,reject)=>{try{supernodes=nodes,kBucket=new K_Bucket(DEFAULT.SNStorageID,Object.keys(supernodes)),resolve("Cloud init successful")}catch(error){reject(error)}}))},Object.defineProperty(floCloudAPI,"kBucket",{get:()=>kBucket});const _inactive=new Set;function ws_activeConnect(snID,reverse=!1){return new Promise(((resolve,reject)=>{if(_inactive.size===kBucket.list.length)return reject("Cloud offline");snID in supernodes||(snID=kBucket.closestNode(proxyID(snID))),function(snID){return new Promise(((resolve,reject)=>{if(!(snID in supernodes))return reject(`${snID} is not a supernode`);if(_inactive.has(snID))return reject(`${snID} is not active`);var wsConn=new WebSocket("wss://"+supernodes[snID].uri+"/");wsConn.onopen=evt=>resolve(wsConn),wsConn.onerror=evt=>{_inactive.add(snID),reject(`${snID} is unavailable`)}}))}(snID).then((node=>resolve(node))).catch((error=>{if(reverse)var nxtNode=kBucket.prevNode(snID);else nxtNode=kBucket.nextNode(snID);ws_activeConnect(nxtNode,reverse).then((node=>resolve(node))).catch((error=>reject(error)))}))}))}function fetch_ActiveAPI(snID,data,reverse=!1){return new Promise(((resolve,reject)=>{if(_inactive.size===kBucket.list.length)return reject("Cloud offline");snID in supernodes||(snID=kBucket.closestNode(proxyID(snID))),function(snID,data){return new Promise(((resolve,reject)=>{if(_inactive.has(snID))return reject(`${snID} is not active`);let fetcher,sn_url="https://"+supernodes[snID].uri;"string"==typeof data?fetcher=fetch(sn_url+"?"+data):"object"==typeof data&&"POST"===data.method&&(fetcher=fetch(sn_url,data)),fetcher.then((response=>{response.ok||400===response.status||500===response.status?resolve(response):reject(response)})).catch((error=>reject(error)))}))}(snID,data).then((result=>resolve(result))).catch((error=>{if(_inactive.add(snID),reverse)var nxtNode=kBucket.prevNode(snID);else nxtNode=kBucket.nextNode(snID);fetch_ActiveAPI(nxtNode,data,reverse).then((result=>resolve(result))).catch((error=>reject(error)))}))}))}function singleRequest(floID,data_obj,method="POST"){return new Promise(((resolve,reject)=>{let data;data="POST"===method?{method:"POST",body:JSON.stringify(data_obj)}:new URLSearchParams(JSON.parse(JSON.stringify(data_obj))).toString(),fetch_ActiveAPI(floID,data).then((response=>{response.ok?response.json().then((result=>resolve(result))).catch((error=>reject(error))):response.text().then((result=>reject(response.status+": "+result))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))}const _liveRequest={};function liveRequest(floID,request,callback){const filterData=void 0!==request.status?data=>{if(request.status)return data;{let filtered={};for(let i in data)request.trackList.includes(i)&&(filtered[i]=data[i]);return filtered}}:data=>{data=objectifier(data);let filtered={},proxy=proxyID(request.receiverID),r=request;for(let v in data){let d=data[v];r.atVectorClock&&r.atVectorClock!=v||!(r.atVectorClock||!r.lowerVectorClock||r.lowerVectorClock<=v)||!(r.atVectorClock||!r.upperVectorClock||r.upperVectorClock>=v)||r.afterTime&&!(r.afterTime{ws_activeConnect(floID).then((node=>{let randID=floCrypto.randString(5);node.send(JSON.stringify(request)),node.onmessage=evt=>{let d=null,e=null;try{d=filterData(JSON.parse(evt.data))}catch(error){e=evt.data}finally{callback(d,e)}},_liveRequest[randID]=node,_liveRequest[randID].request=request,resolve(randID)})).catch((error=>reject(error)))}))}Object.defineProperty(floCloudAPI,"liveRequest",{get:()=>_liveRequest}),Object.defineProperty(floCloudAPI,"inactive",{get:()=>_inactive});const util=floCloudAPI.util={},encodeMessage=util.encodeMessage=function(message){return btoa(unescape(encodeURIComponent(JSON.stringify(message))))},decodeMessage=util.decodeMessage=function(message){return JSON.parse(decodeURIComponent(escape(atob(message))))},filterKey=util.filterKey=function(type,options={}){return type+(options.comment?":"+options.comment:"")+"|"+(options.group||options.receiverID||DEFAULT.adminID)+"|"+(options.application||DEFAULT.application)},proxyID=util.proxyID=function(address){if(address){var bytes;if(33==address.length||34==address.length){let decode=bitjs.Base58.decode(address);bytes=decode.slice(0,decode.length-4);let checksum=decode.slice(decode.length-4),hash=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0});hash[0]!=checksum[0]||hash[1]!=checksum[1]||hash[2]!=checksum[2]||hash[3]!=checksum[3]?bytes=void 0:bytes.shift()}else if(42==address.length||62==address.length){if("function"!=typeof coinjs)throw"library missing (lib_btc.js)";let decode=coinjs.bech32_decode(address);decode&&((bytes=decode.data).shift(),bytes=coinjs.bech32_convert(bytes,5,8,!1),62==address.length&&(bytes=coinjs.bech32_convert(bytes,5,8,!1)))}else 66==address.length&&(bytes=ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(address),{asBytes:!0})));if(bytes){bytes.unshift(DEFAULT.blockchainPrefix);let hash=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0});return bitjs.Base58.encode(bytes.concat(hash.slice(0,4)))}throw"Invalid address: "+address}},lastCommit={};function updateObject(objectName,dataSet){try{console.log(dataSet);let vcList=Object.keys(dataSet).sort();for(let vc of vcList)if(!(vclastVC[fk]&&(lastVC[fk]=dataSet[vc].log_time);compactIDB.writeData("lastVC",lastVC[fk],fk),compactIDB.writeData("generalData",generalData[fk],fk)}catch(error){console.error(error)}}function objectifier(data){return Array.isArray(data)||(data=[data]),Object.fromEntries(data.map((d=>(d.message=decodeMessage(d.message),[d.vectorClock,d]))))}Object.defineProperty(lastCommit,"get",{value:objName=>JSON.parse(lastCommit[objName])}),Object.defineProperty(lastCommit,"set",{value:objName=>lastCommit[objName]=JSON.stringify(appObjects[objName])}),floCloudAPI.setStatus=function(options={}){return new Promise(((resolve,reject)=>{let callback=options.callback instanceof Function?options.callback:DEFAULT.callback;var request={floID:user.id,application:options.application||DEFAULT.application,time:Date.now(),status:!0,pubKey:user.public};let hashcontent=["time","application","floID"].map((d=>request[d])).join("|");request.sign=user.sign(hashcontent),liveRequest(options.refID||DEFAULT.adminID,request,callback).then((result=>resolve(result))).catch((error=>reject(error)))}))},floCloudAPI.requestStatus=function(trackList,options={}){return new Promise(((resolve,reject)=>{Array.isArray(trackList)||(trackList=[trackList]);let callback=options.callback instanceof Function?options.callback:DEFAULT.callback,request={status:!1,application:options.application||DEFAULT.application,trackList:trackList};liveRequest(options.refID||DEFAULT.adminID,request,callback).then((result=>resolve(result))).catch((error=>reject(error)))}))};const sendApplicationData=floCloudAPI.sendApplicationData=function(message,type,options={}){return new Promise(((resolve,reject)=>{var data={senderID:user.id,receiverID:options.receiverID||DEFAULT.adminID,pubKey:user.public,message:encodeMessage(message),time:Date.now(),application:options.application||DEFAULT.application,type:type,comment:options.comment||""};let hashcontent=["receiverID","time","application","type","message","comment"].map((d=>data[d])).join("|");data.sign=user.sign(hashcontent),singleRequest(data.receiverID,data).then((result=>resolve(result))).catch((error=>reject(error)))}))},requestApplicationData=floCloudAPI.requestApplicationData=function(type,options={}){return new Promise(((resolve,reject)=>{var request={receiverID:options.receiverID||DEFAULT.adminID,senderID:options.senderID||void 0,application:options.application||DEFAULT.application,type:type,comment:options.comment||void 0,lowerVectorClock:options.lowerVectorClock||void 0,upperVectorClock:options.upperVectorClock||void 0,atVectorClock:options.atVectorClock||void 0,afterTime:options.afterTime||void 0,mostRecent:options.mostRecent||void 0};options.callback instanceof Function?liveRequest(request.receiverID,request,options.callback).then((result=>resolve(result))).catch((error=>reject(error))):("POST"===options.method&&(request={time:Date.now(),request:request}),singleRequest(request.receiverID,request,options.method||"GET").then((data=>resolve(data))).catch((error=>reject(error))))}))};floCloudAPI.editApplicationData=function(vectorClock,comment_edit,options={}){return new Promise(((resolve,reject)=>{let req_options=Object.assign({},options);req_options.atVectorClock=vectorClock,requestApplicationData(void 0,req_options).then((result=>{if(!result.length)return reject("Data not found");let data=result[0];if(data.senderID!==user.id)return reject("Only sender can edit comment");data.comment=comment_edit;let hashcontent=["receiverID","time","application","type","message","comment"].map((d=>data[d])).join("|"),re_sign=user.sign(hashcontent);var request={receiverID:options.receiverID||DEFAULT.adminID,requestorID:user.id,pubKey:user.public,time:Date.now(),vectorClock:vectorClock,edit:comment_edit,re_sign:re_sign};let request_hash=["time","vectorClock","edit","re_sign"].map((d=>request[d])).join("|");request.sign=user.sign(request_hash),singleRequest(request.receiverID,request).then((result=>resolve(result))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floCloudAPI.tagApplicationData=function(vectorClock,tag,options={}){return new Promise(((resolve,reject)=>{if(!floGlobals.subAdmins.includes(user.id))return reject("Only subAdmins can tag data");var request={receiverID:options.receiverID||DEFAULT.adminID,requestorID:user.id,pubKey:user.public,time:Date.now(),vectorClock:vectorClock,tag:tag};let hashcontent=["time","vectorClock","tag"].map((d=>request[d])).join("|");request.sign=user.sign(hashcontent),singleRequest(request.receiverID,request).then((result=>resolve(result))).catch((error=>reject(error)))}))},floCloudAPI.noteApplicationData=function(vectorClock,note,options={}){return new Promise(((resolve,reject)=>{var request={receiverID:options.receiverID||DEFAULT.adminID,requestorID:user.id,pubKey:user.public,time:Date.now(),vectorClock:vectorClock,note:note};let hashcontent=["time","vectorClock","note"].map((d=>request[d])).join("|");request.sign=user.sign(hashcontent),singleRequest(request.receiverID,request).then((result=>resolve(result))).catch((error=>reject(error)))}))},floCloudAPI.sendGeneralData=function(message,type,options={}){return new Promise(((resolve,reject)=>{if(options.encrypt){let encryptionKey=!0===options.encrypt?floGlobals.settings.encryptionKey:options.encrypt;message=floCrypto.encryptData(JSON.stringify(message),encryptionKey)}sendApplicationData(message,type,options).then((result=>resolve(result))).catch((error=>reject(error)))}))},floCloudAPI.requestGeneralData=function(type,options={}){return new Promise(((resolve,reject)=>{var fk=filterKey(type,options);if(lastVC[fk]=parseInt(lastVC[fk])||0,options.afterTime=options.afterTime||lastVC[fk],options.callback instanceof Function){let new_options=Object.create(options);new_options.callback=(d,e)=>{storeGeneral(fk,d),options.callback(d,e)},requestApplicationData(type,new_options).then((result=>resolve(result))).catch((error=>reject(error)))}else requestApplicationData(type,options).then((dataSet=>{storeGeneral(fk,objectifier(dataSet)),resolve(dataSet)})).catch((error=>reject(error)))}))},floCloudAPI.requestObjectData=function(objectName,options={}){return new Promise(((resolve,reject)=>{options.lowerVectorClock=options.lowerVectorClock||lastVC[objectName]+1,options.senderID=[!1,null].includes(options.senderID)?null:options.senderID||floGlobals.subAdmins,options.mostRecent=!0,options.comment="RESET";let callback=null;if(options.callback instanceof Function){let old_callback=options.callback;callback=(d,e)=>{updateObject(objectName,d),old_callback(d,e)},delete options.callback}requestApplicationData(objectName,options).then((dataSet=>{if(updateObject(objectName,objectifier(dataSet)),delete options.comment,options.lowerVectorClock=lastVC[objectName]+1,delete options.mostRecent,callback){let new_options=Object.create(options);new_options.callback=callback,requestApplicationData(objectName,new_options).then((result=>resolve(result))).catch((error=>reject(error)))}else requestApplicationData(objectName,options).then((dataSet=>{updateObject(objectName,objectifier(dataSet)),resolve(appObjects[objectName])})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floCloudAPI.closeRequest=function(requestID){return new Promise(((resolve,reject)=>{let conn=_liveRequest[requestID];if(!conn)return reject("Request not found");conn.onclose=evt=>{delete _liveRequest[requestID],resolve("Request connection closed")},conn.close()}))},floCloudAPI.resetObjectData=function(objectName,options={}){return new Promise(((resolve,reject)=>{let message={reset:appObjects[objectName]};options.comment="RESET",sendApplicationData(message,objectName,options).then((result=>{lastCommit.set(objectName),resolve(result)})).catch((error=>reject(error)))}))},floCloudAPI.updateObjectData=function(objectName,options={}){return new Promise(((resolve,reject)=>{let message={diff:diff.find(lastCommit.get(objectName),appObjects[objectName])};options.comment="UPDATE",sendApplicationData(message,objectName,options).then((result=>{lastCommit.set(objectName),resolve(result)})).catch((error=>reject(error)))}))},floCloudAPI.uploadFile=function(fileBlob,type,options={}){return new Promise(((resolve,reject)=>{if(!(fileBlob instanceof File||fileBlob instanceof Blob))return reject("file must be instance of File/Blob");fileBlob.arrayBuffer().then((arraybuf=>{let file_data={type:fileBlob.type,name:fileBlob.name};if(file_data.content=Crypto.util.bytesToBase64(new Uint8Array(arraybuf)),options.encrypt){let encryptionKey=!0===options.encrypt?floGlobals.settings.encryptionKey:options.encrypt;file_data=floCrypto.encryptData(JSON.stringify(file_data),encryptionKey)}sendApplicationData(file_data,type,options).then((({vectorClock:vectorClock,receiverID:receiverID,type:type,application:application})=>resolve({vectorClock:vectorClock,receiverID:receiverID,type:type,application:application}))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floCloudAPI.downloadFile=function(vectorClock,options={}){return new Promise(((resolve,reject)=>{options.atVectorClock=vectorClock,requestApplicationData(options.type,options).then((result=>{if(!result.length)return reject("File not found");result=result[0];try{let file_data=decodeMessage(result.message);if(file_data instanceof Object&&"secret"in file_data){if(!options.decrypt)return reject("Data is encrypted");let decryptionKey=!0===options.decrypt?Crypto.AES.decrypt(user_private,aes_key):options.decrypt;Array.isArray(decryptionKey)||(decryptionKey=[decryptionKey]);let flag=!1;for(let key of decryptionKey)try{let tmp=floCrypto.decryptData(file_data,key);file_data=JSON.parse(tmp),flag=!0;break}catch(error){}if(!flag)return reject("Unable to decrypt file: Invalid private key")}let arraybuf=new Uint8Array(Crypto.util.base64ToBytes(file_data.content));result.file=new File([arraybuf],file_data.name,{type:file_data.type}),resolve(result)}catch(error){console.error(error),reject("Data is not a file")}})).catch((error=>reject(error)))}))};var diff=function(){const isDate=d=>d instanceof Date,isEmpty=o=>0===Object.keys(o).length,isObject=o=>null!=o&&"object"==typeof o,properObject=o=>isObject(o)&&!o.hasOwnProperty?{...o}:o,updatedDiff=(lhs,rhs)=>{if(lhs===rhs)return{};if(!isObject(lhs)||!isObject(rhs))return rhs;const l=properObject(lhs),r=properObject(rhs);return isDate(l)||isDate(r)?l.valueOf()==r.valueOf()?{}:r:Object.keys(r).reduce(((acc,key)=>{if(l.hasOwnProperty(key)){const difference=updatedDiff(l[key],r[key]);return isObject(difference)&&isEmpty(difference)&&!isDate(difference)?acc:{...acc,[key]:difference}}return acc}),{})},addedDiff=(lhs,rhs)=>{if(lhs===rhs||!isObject(lhs)||!isObject(rhs))return{};const l=properObject(lhs),r=properObject(rhs);return Object.keys(r).reduce(((acc,key)=>{if(l.hasOwnProperty(key)){const difference=addedDiff(l[key],r[key]);return isObject(difference)&&isEmpty(difference)?acc:{...acc,[key]:difference}}return{...acc,[key]:r[key]}}),{})},deletedDiff=(lhs,rhs)=>{if(lhs===rhs||!isObject(lhs)||!isObject(rhs))return{};const l=properObject(lhs),r=properObject(rhs);return Object.keys(l).reduce(((acc,key)=>{if(r.hasOwnProperty(key)){const difference=deletedDiff(l[key],r[key]);return isObject(difference)&&isEmpty(difference)?acc:{...acc,[key]:difference}}return{...acc,[key]:null}}),{})},mergeRecursive=(obj1,obj2,deleteMode=!1)=>{for(var p in obj2)try{obj2[p].constructor==Object?obj1[p]=mergeRecursive(obj1[p],obj2[p],deleteMode):Array.isArray(obj2[p])?obj2[p].length<1?obj1[p]=obj2[p]:obj1[p]=mergeRecursive(obj1[p],obj2[p],deleteMode):obj1[p]=deleteMode&&null===obj2[p]?void 0:obj2[p]}catch(e){obj1[p]=deleteMode&&null===obj2[p]?void 0:obj2[p]}return obj1},cleanse=obj=>(Object.keys(obj).forEach((key=>{var value=obj[key];"object"==typeof value&&null!==value?obj[key]=cleanse(value):void 0===value&&delete obj[key]})),Array.isArray(obj)&&(obj=obj.filter((v=>void 0!==v))),obj);return{find:(lhs,rhs)=>({added:addedDiff(lhs,rhs),deleted:deletedDiff(lhs,rhs),updated:updatedDiff(lhs,rhs)}),merge:(obj,diff)=>(0!==Object.keys(diff.updated).length&&(obj=mergeRecursive(obj,diff.updated)),0!==Object.keys(diff.deleted).length&&(obj=mergeRecursive(obj,diff.deleted,!0),obj=cleanse(obj)),0!==Object.keys(diff.added).length&&(obj=mergeRecursive(obj,diff.added)),obj)}}()}(); \ No newline at end of file diff --git a/js/floCrypto.min.js b/js/floCrypto.min.js new file mode 100644 index 0000000..bb25e14 --- /dev/null +++ b/js/floCrypto.min.js @@ -0,0 +1 @@ +!function(EXPORTS){"use strict";const floCrypto="object"===typeof module?module.exports:window.floCrypto={},p=BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",16),ecparams=EllipticCurve.getSECCurveByName("secp256k1"),ascii_alternatives="‘ '\n’ '\n“ \"\n” \"\n– --\n— ---\n≥ >=\n≤ <=\n≠ !=\n× *\n÷ /\n← <-\n→ ->\n↔ <->\n⇒ =>\n⇐ <=\n⇔ <=>",exponent1=()=>p.add(BigInteger.ONE).divide(BigInteger("4"));function getUncompressedPublicKey(compressedPublicKey){let pubKeyBytes=Crypto.util.hexToBytes(compressedPublicKey);let prefix_modulus=pubKeyBytes.shift()%2;pubKeyBytes.unshift(0);let x=new BigInteger(pubKeyBytes),xDecimalValue=x.toString(),y=function(x){let exp=exponent1();return x.modPow(BigInteger("3"),p).add(BigInteger("7")).mod(p).modPow(exp,p)}(x),yDecimalValue=y.toString();return prefix_modulus!==y.mod(BigInteger("2")).toString()%2&&(yDecimalValue=y.negate().mod(p).toString()),{x:xDecimalValue,y:yDecimalValue}}coinjs.compressed=!0,floCrypto.randInt=function(min,max){return min=Math.ceil(min),max=Math.floor(max),Math.floor(securedMathRandom()*(max-min+1))+min},floCrypto.randString=function(length,alphaNumeric=!0){for(var result="",characters=alphaNumeric?"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+-./*?@#&$<>=[]{}():",i=0;igenerateNewID()},hashID:{value:str=>{let bytes=ripemd160(Crypto.SHA256(str,{asBytes:!0}),{asBytes:!0});bytes.unshift(bitjs.pub);var checksum=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0}).slice(0,4);return bitjs.Base58.encode(bytes.concat(checksum))}},tmpID:{get:()=>{let bytes=Crypto.util.randomBytes(20);bytes.unshift(bitjs.pub);var checksum=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0}).slice(0,4);return bitjs.Base58.encode(bytes.concat(checksum))}}}),floCrypto.getPubKeyHex=function(privateKeyHex){if(!privateKeyHex)return null;var key=new Bitcoin.ECKey(privateKeyHex);return null==key.priv?null:(key.setCompressed(!0),key.getPubKeyHex())},floCrypto.getFloID=function(keyHex){if(!keyHex)return null;try{var key=new Bitcoin.ECKey(keyHex);return null==key.priv&&key.setPub(keyHex),key.getBitcoinAddress()}catch{return null}},floCrypto.getAddress=function(privateKeyHex,strict=!1){if(!privateKeyHex)return;var key=new Bitcoin.ECKey(privateKeyHex);if(null==key.priv)return null;key.setCompressed(!0);let pubKey=key.getPubKeyHex();switch(bitjs.Base58.decode(privateKeyHex)[0]){case coinjs.priv:return coinjs.bech32Address(pubKey).address;case bitjs.priv:return bitjs.pubkey2address(pubKey);default:return!strict&&bitjs.pubkey2address(pubKey)}},floCrypto.verifyPrivKey=function(privateKeyHex,pubKey_floID,isfloID=!0){if(!privateKeyHex||!pubKey_floID)return!1;try{var key=new Bitcoin.ECKey(privateKeyHex);return null!=key.priv&&(key.setCompressed(!0),!(!isfloID||pubKey_floID!=key.getBitcoinAddress())||!isfloID&&pubKey_floID.toUpperCase()==key.getPubKeyHex().toUpperCase())}catch{return null}},floCrypto.getMultisigAddress=function(publicKeyList,requiredSignatures){if(!Array.isArray(publicKeyList)||!publicKeyList.length)return null;if(!Number.isInteger(requiredSignatures)||requiredSignatures<1||requiredSignatures>publicKeyList.length)return null;try{return bitjs.pubkeys2multisig(publicKeyList,requiredSignatures)}catch{return null}},floCrypto.decodeRedeemScript=function(redeemScript){try{return bitjs.transaction().decodeRedeemScript(redeemScript)}catch{return null}},floCrypto.validateFloID=function(floID,regularOnly=!1){if(!floID)return!1;try{let addr=new Bitcoin.Address(floID);return!regularOnly||addr.version==Bitcoin.Address.standardVersion}catch{return!1}},floCrypto.validateAddr=function(address,std=!0,bech=!0){let raw=decodeAddress(address);return!!raw&&(void 0!==raw.version?0!=std&&!!(!0===std||!Array.isArray(std)&&std===raw.version||Array.isArray(std)&&std.includes(raw.version)):void 0!==raw.bech_version&&(!1!==bech&&!!(!0===bech||!Array.isArray(bech)&&bech===raw.bech_version||Array.isArray(bech)&&bech.includes(raw.bech_version))))},floCrypto.verifyPubKey=function(pubKeyHex,address){let raw=decodeAddress(address);if(!raw)return;let pub_hash=Crypto.util.bytesToHex(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubKeyHex),{asBytes:!0})));return void 0!==raw.bech_version&&32==raw.bytes.length&&(raw.hex=Crypto.util.bytesToHex(ripemd160(raw.bytes,{asBytes:!0}))),pub_hash===raw.hex},floCrypto.toFloID=function(address,options=null){if(!address)return;let raw=decodeAddress(address);if(!raw)return;if(options){if(!(void 0===raw.version||options.std&&options.std.includes(raw.version)))return;if(!(void 0===raw.bech_version||options.bech&&options.bech.includes(raw.bech_version)))return}raw.bytes.unshift(bitjs.pub);let hash=Crypto.SHA256(Crypto.SHA256(raw.bytes,{asBytes:!0}),{asBytes:!0});return bitjs.Base58.encode(raw.bytes.concat(hash.slice(0,4)))},floCrypto.rawToFloID=function(raw_bytes){if("string"==typeof raw_bytes&&(raw_bytes=Crypto.util.hexToBytes(raw_bytes)),20!=raw_bytes.length)return null;raw_bytes.unshift(bitjs.pub);let hash=Crypto.SHA256(Crypto.SHA256(raw_bytes,{asBytes:!0}),{asBytes:!0});return bitjs.Base58.encode(raw_bytes.concat(hash.slice(0,4)))},floCrypto.toMultisigFloID=function(address,options=null){if(!address)return;let raw=decodeAddress(address);if(!raw)return;if(options){if(!(void 0===raw.version||options.std&&options.std.includes(raw.version)))return;if(!(void 0===raw.bech_version||options.bech&&options.bech.includes(raw.bech_version)))return}if(void 0!==raw.bech_version){if(32!=raw.bytes.length)return;raw.bytes=ripemd160(raw.bytes,{asBytes:!0})}raw.bytes.unshift(bitjs.multisig);let hash=Crypto.SHA256(Crypto.SHA256(raw.bytes,{asBytes:!0}),{asBytes:!0});return bitjs.Base58.encode(raw.bytes.concat(hash.slice(0,4)))},floCrypto.isSameAddr=function(addr1,addr2){if(!addr1||!addr2)return;let raw1=decodeAddress(addr1),raw2=decodeAddress(addr2);return!(!raw1||!raw2)&&(void 0!==raw1.bech_version&&32==raw1.bytes.length&&(raw1.hex=Crypto.util.bytesToHex(ripemd160(raw1.bytes,{asBytes:!0}))),void 0!==raw2.bech_version&&32==raw2.bytes.length&&(raw2.hex=Crypto.util.bytesToHex(ripemd160(raw2.bytes,{asBytes:!0}))),raw1.hex===raw2.hex)};const decodeAddress=floCrypto.decodeAddr=function(address){if(address){if(33==address.length||34==address.length){let decode=bitjs.Base58.decode(address),bytes=decode.slice(0,decode.length-4),checksum=decode.slice(decode.length-4),hash=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0});return hash[0]!=checksum[0]||hash[1]!=checksum[1]||hash[2]!=checksum[2]||hash[3]!=checksum[3]?null:{version:bytes.shift(),hex:Crypto.util.bytesToHex(bytes),bytes:bytes}}if(42==address.length||62==address.length){let decode=coinjs.bech32_decode(address);if(decode){let bytes=decode.data,bech_version=bytes.shift();return bytes=coinjs.bech32_convert(bytes,5,8,!1),{bech_version:bech_version,hrp:decode.hrp,hex:Crypto.util.bytesToHex(bytes),bytes:bytes}}return null}}};floCrypto.createShamirsSecretShares=function(str,total_shares,threshold_limit){try{if(str.length>0){var strHex=shamirSecretShare.str2hex(str);return shamirSecretShare.share(strHex,total_shares,threshold_limit)}return!1}catch{return!1}};const retrieveShamirSecret=floCrypto.retrieveShamirSecret=function(sharesArray){try{if(sharesArray.length>0){var comb=shamirSecretShare.combine(sharesArray.slice(0,sharesArray.length));return comb=shamirSecretShare.hex2str(comb)}return!1}catch{return!1}};floCrypto.verifyShamirsSecret=function(sharesArray,str){return str?retrieveShamirSecret(sharesArray)===str:null};const validateASCII=floCrypto.validateASCII=function(string,bool=!0){if("string"!=typeof string)return null;if(bool){let x;for(let i=0;i127)return!1;return!0}{let x,invalids={};for(let i=0;i127)&&(x in invalids?invalids[string[i]].push(i):invalids[string[i]]=[i]);return!Object.keys(invalids).length||invalids}};floCrypto.convertToASCII=function(string,mode="soft-remove"){let chars=validateASCII(string,!1);if(!0===chars)return string;if(null===chars)return null;let convertor,result=string,refAlt={};if(ascii_alternatives.split("\n").forEach((a=>refAlt[a[0]]=a.slice(2))),"hard-unicode"===(mode=mode.toLowerCase()))convertor=c=>`\\u${("000"+c.charCodeAt().toString(16)).slice(-4)}`;else if("soft-unicode"===mode)convertor=c=>refAlt[c]||`\\u${("000"+c.charCodeAt().toString(16)).slice(-4)}`;else if("hard-remove"===mode)convertor=c=>"";else{if("soft-remove"!==mode)return null;convertor=c=>refAlt[c]||""}for(let c in chars)result=result.replaceAll(c,convertor(c));return result},floCrypto.revertUnicode=function(string){return string.replace(/\\u[\dA-F]{4}/gi,(m=>String.fromCharCode(parseInt(m.replace(/\\u/g,""),16))))}}(); \ No newline at end of file diff --git a/js/floDapps.min.js b/js/floDapps.min.js new file mode 100644 index 0000000..152132c --- /dev/null +++ b/js/floDapps.min.js @@ -0,0 +1 @@ +!function(EXPORTS){"use strict";const floDapps="object"===typeof module?module.exports:window.floDapps={},DEFAULT={root:"floDapps",application:floGlobals.application,adminID:floGlobals.adminID};var user_priv_raw,aes_key,user_priv_wrap;Object.defineProperties(floDapps,{application:{get:()=>DEFAULT.application},adminID:{get:()=>DEFAULT.adminID},root:{get:()=>DEFAULT.root}});const raw_user={get private(){if(!user_priv_raw)throw"User not logged in";return Crypto.AES.decrypt(user_priv_raw,aes_key)}};var user_id,user_public,user_private;const user=floDapps.user={get id(){if(!user_id)throw"User not logged in";return user_id},get public(){if(!user_public)throw"User not logged in";return user_public},get private(){if(user_private)return user_private instanceof Function?user_private():Crypto.AES.decrypt(user_private,aes_key);throw"User not logged in"},sign:message=>floCrypto.signData(message,raw_user.private),decrypt:data=>floCrypto.decryptData(data,raw_user.private),encipher:message=>Crypto.AES.encrypt(message,raw_user.private),decipher:data=>Crypto.AES.decrypt(data,raw_user.private),get db_name(){return"floDapps#"+floCrypto.toFloID(user.id)},lock(){user_private=user_priv_wrap},async unlock(){await user.private===raw_user.private&&(user_private=user_priv_raw)},get_contact(id){if(!user.contacts)throw"Contacts not available";if(user.contacts[id])return user.contacts[id];{let id_raw=floCrypto.decodeAddr(id).hex;for(let i in user.contacts)if(floCrypto.decodeAddr(i).hex==id_raw)return user.contacts[i]}},get_pubKey(id){if(!user.pubKeys)throw"Contacts not available";if(user.pubKeys[id])return user.pubKeys[id];{let id_raw=floCrypto.decodeAddr(id).hex;for(let i in user.pubKeys)if(floCrypto.decodeAddr(i).hex==id_raw)return user.pubKeys[i]}},clear(){user_id=user_public=user_private=void 0,user_priv_raw=aes_key=void 0,delete user.contacts,delete user.pubKeys,delete user.messages}};var subAdmins,trustedIDs,settings;function initIndexedDB(){return new Promise(((resolve,reject)=>{var obs_a={credentials:{},subAdmins:{},trustedIDs:{},settings:{},appObjects:{},generalData:{},lastVC:{}};initIndexedDB.appObs=initIndexedDB.appObs||{};for(let o in initIndexedDB.appObs)o in obs_a||(obs_a[o]=initIndexedDB.appObs[o]);Promise.all([compactIDB.initDB(DEFAULT.application,obs_a),compactIDB.initDB(DEFAULT.root,{lastTx:{},supernodes:{}})]).then((result=>{compactIDB.setDefaultDB(DEFAULT.application),resolve("IndexedDB App Storage Initated Successfully")})).catch((error=>reject(error)))}))}Object.defineProperties(window,{myFloID:{get:()=>{try{return user.id}catch{return}}},myUserID:{get:()=>{try{return user.id}catch{return}}},myPubKey:{get:()=>{try{return user.public}catch{return}}},myPrivKey:{get:()=>{try{return user.private}catch{return}}}}),Object.defineProperties(floGlobals,{subAdmins:{get:()=>subAdmins},trustedIDs:{get:()=>trustedIDs},settings:{get:()=>settings},contacts:{get:()=>user.contacts},pubKeys:{get:()=>user.pubKeys},messages:{get:()=>user.messages}});const startUpOptions={cloud:!0,app_config:!0};floDapps.startUpOptions={set app_config(val){!0!==val&&!1!==val||(startUpOptions.app_config=val)},get app_config(){return startUpOptions.app_config},set cloud(val){!0!==val&&!1!==val||(startUpOptions.cloud=val)},get cloud(){return startUpOptions.cloud}};const startUpFunctions=[];startUpFunctions.push((function(){return new Promise(((resolve,reject)=>{if(!startUpOptions.cloud)return resolve("No cloud for this app");const CLOUD_KEY="floCloudAPI#"+floCloudAPI.SNStorageID;compactIDB.readData("lastTx",CLOUD_KEY,DEFAULT.root).then((lastTx=>{var query_options={sentOnly:!0,pattern:floCloudAPI.SNStorageName};"number"==typeof lastTx?query_options.ignoreOld=lastTx:"string"==typeof lastTx&&(query_options.after=lastTx),floBlockchainAPI.readData(floCloudAPI.SNStorageID,query_options).then((result=>{compactIDB.readData("supernodes",CLOUD_KEY,DEFAULT.root).then((nodes=>{nodes=nodes||{};for(var i=result.data.length-1;i>=0;i--){var content=JSON.parse(result.data[i])[floCloudAPI.SNStorageName];for(let sn in content.removeNodes)delete nodes[sn];for(let sn in content.newNodes)nodes[sn]=content.newNodes[sn];for(let sn in content.updateNodes)sn in nodes&&(nodes[sn].uri=content.updateNodes[sn])}Promise.all([compactIDB.writeData("lastTx",result.lastItem,CLOUD_KEY,DEFAULT.root),compactIDB.writeData("supernodes",nodes,CLOUD_KEY,DEFAULT.root)]).then((_=>{floCloudAPI.init(nodes).then((result=>resolve("Loaded Supernode list\n"+result))).catch((error=>reject(error)))})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))})).catch((error=>reject(error)))}))})),startUpFunctions.push((function(){return new Promise(((resolve,reject)=>{if(!startUpOptions.app_config)return resolve("No configs for this app");compactIDB.readData("lastTx",`${DEFAULT.application}|${DEFAULT.adminID}`,DEFAULT.root).then((lastTx=>{var query_options={sentOnly:!0,pattern:DEFAULT.application};"number"==typeof lastTx?query_options.ignoreOld=lastTx:"string"==typeof lastTx&&(query_options.after=lastTx),floBlockchainAPI.readData(DEFAULT.adminID,query_options).then((result=>{for(var i=result.data.length-1;i>=0;i--){var content=JSON.parse(result.data[i])[DEFAULT.application];if(content&&"object"==typeof content){if(Array.isArray(content.removeSubAdmin))for(var j=0;j{subAdmins=Object.keys(result),compactIDB.readAllData("trustedIDs").then((result=>{trustedIDs=Object.keys(result),compactIDB.readAllData("settings").then((result=>{settings=result,resolve("Read app configuration from blockchain")}))}))}))}))})).catch((error=>reject(error)))}))})),startUpFunctions.push((function(){return new Promise(((resolve,reject)=>{if(!startUpOptions.cloud)return resolve("No cloud for this app");for(var loadData=["appObjects","generalData","lastVC"],promises=[],i=0;i{for(var i=0;ireject(error)))}))}));var keyInput=type=>new Promise(((resolve,reject)=>{let inputVal=prompt(`Enter ${type}: `);null===inputVal?reject(null):resolve(inputVal)}));function getCredentials(){const writeSharesToIDB=(shares,i=0,resultIndexes=[])=>new Promise((resolve=>{if(i>=shares.length)return resolve(resultIndexes);var n=floCrypto.randInt(0,1e5);compactIDB.addData("credentials",shares[i],n).then((res=>{resultIndexes.push(n),writeSharesToIDB(shares,i+1,resultIndexes).then((result=>resolve(result)))})).catch((error=>{writeSharesToIDB(shares,i,resultIndexes).then((result=>resolve(result)))}))})),getPrivateKeyCredentials=()=>new Promise(((resolve,reject)=>{var privKey,indexArr=localStorage.getItem(`${DEFAULT.application}#privKey`);indexArr?(indexArr=>new Promise(((resolve,reject)=>{for(var promises=[],i=0;i{var secret=floCrypto.retrieveShamirSecret(shares);secret?resolve(secret):reject("Shares are insufficient or incorrect")})).catch((error=>{clearCredentials(),location.reload()}))})))(JSON.parse(indexArr)).then((result=>resolve(result))).catch((error=>reject(error))):keyInput("PRIVATE_KEY").then((result=>{if(!result)return reject("Empty Private Key");var floID=floCrypto.getFloID(result);if(!floID||!floCrypto.validateFloID(floID))return reject("Invalid Private Key");privKey=result})).catch((error=>{console.log(error,"Generating Random Keys"),privKey=floCrypto.generateNewID().privKey})).finally((_=>{if(privKey){var threshold=floCrypto.randInt(10,20),shares=floCrypto.createShamirsSecretShares(privKey,threshold,threshold);writeSharesToIDB(shares).then((resultIndexes=>{localStorage.setItem(`${DEFAULT.application}#privKey`,JSON.stringify(resultIndexes));var randomPrivKey=floCrypto.generateNewID().privKey,randomThreshold=floCrypto.randInt(10,20),randomShares=floCrypto.createShamirsSecretShares(randomPrivKey,randomThreshold,randomThreshold);writeSharesToIDB(randomShares),resolve(privKey)}))}}))})),checkIfPinRequired=key=>new Promise(((resolve,reject)=>{52==key.length?resolve(key):keyInput("PIN/Password").then((pwd=>{try{let privKey=Crypto.AES.decrypt(key,pwd);resolve(privKey)}catch(error){reject("Access Denied: Incorrect PIN/Password")}})).catch((error=>reject("Access Denied: PIN/Password required")))}));return new Promise(((resolve,reject)=>{getPrivateKeyCredentials().then((key=>{checkIfPinRequired(key).then((privKey=>{try{user_public=floCrypto.getPubKeyHex(privKey),user_id=floCrypto.getAddress(privKey),startUpOptions.cloud&&floCloudAPI.user(user_id,privKey),user_priv_wrap=()=>checkIfPinRequired(key);let n=floCrypto.randInt(12,20);aes_key=floCrypto.randString(n),user_priv_raw=Crypto.AES.encrypt(privKey,aes_key),user_private=user_priv_wrap,resolve("Login Credentials loaded successful")}catch(error){console.log(error),reject("Corrupted Private Key")}})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))}var startUpLog=(status,log)=>status?console.log(log):console.error(log);const callStartUpFunction=i=>new Promise(((resolve,reject)=>{startUpFunctions[i]().then((result=>{callStartUpFunction.completed+=1,startUpLog(!0,`${result}\nCompleted ${callStartUpFunction.completed}/${callStartUpFunction.total} Startup functions`),resolve(!0)})).catch((error=>{callStartUpFunction.failed+=1,startUpLog(!1,`${error}\nFailed ${callStartUpFunction.failed}/${callStartUpFunction.total} Startup functions`),reject(!1)}))}));var _midFunction;const callAndLog=p=>new Promise(((res,rej)=>{p.then((r=>{startUpLog(!0,r),res(r)})).catch((e=>{startUpLog(!1,e),rej(e)}))}));floDapps.launchStartUp=function(){return new Promise(((resolve,reject)=>{initIndexedDB().then((log=>{console.log(log),callStartUpFunction.total=startUpFunctions.length,callStartUpFunction.completed=0,callStartUpFunction.failed=0;let p1=new Promise(((res,rej)=>{Promise.all(startUpFunctions.map(((f,i)=>callStartUpFunction(i)))).then((r=>{callAndLog(new Promise(((res,rej)=>{_midFunction instanceof Function?_midFunction().then((r=>res("Mid startup function completed"))).catch((e=>rej("Mid startup function failed"))):res("No mid startup function")}))).then((r=>res(!0))).catch((e=>rej(!1)))}))})),p2=new Promise(((res,rej)=>{callAndLog(getCredentials()).then((r=>{callAndLog(new Promise(((resolve,reject)=>{compactIDB.initDB(user.db_name,{contacts:{},pubKeys:{},messages:{}}).then((result=>{resolve("UserDB Initated Successfully")})).catch((error=>reject("Init userDB failed")))}))).then((r=>{callAndLog(new Promise(((resolve,reject)=>{for(var loadData=["contacts","pubKeys","messages"],promises=[],i=0;i{for(var i=0;ireject("Load userDB failed")))}))).then((r=>res(!0))).catch((e=>rej(!1)))})).catch((e=>rej(!1)))})).catch((e=>rej(!1)))}));Promise.all([p1,p2]).then((r=>resolve("App Startup finished successful"))).catch((e=>reject("App Startup failed")))})).catch((error=>{startUpLog(!1,error),reject("App database initiation failed")}))}))},floDapps.addStartUpFunction=fn=>fn instanceof Function&&!startUpFunctions.includes(fn)&&startUpFunctions.push(fn),floDapps.setMidStartup=fn=>fn instanceof Function&&(_midFunction=fn),floDapps.setCustomStartupLogger=fn=>fn instanceof Function&&(startUpLog=fn),floDapps.setCustomPrivKeyInput=fn=>fn instanceof Function&&(keyInput=fn),floDapps.setAppObjectStores=appObs=>initIndexedDB.appObs=appObs,floDapps.storeContact=function(floID,name){return new Promise(((resolve,reject)=>{if(!floCrypto.validateAddr(floID))return reject("Invalid floID!");compactIDB.writeData("contacts",name,floID,user.db_name).then((result=>{user.contacts[floID]=name,resolve("Contact stored")})).catch((error=>reject(error)))}))},floDapps.storePubKey=function(floID,pubKey){return new Promise(((resolve,reject)=>floID in user.pubKeys?resolve("pubKey already stored"):floCrypto.validateAddr(floID)?floCrypto.verifyPubKey(pubKey,floID)?void compactIDB.writeData("pubKeys",pubKey,floID,user.db_name).then((result=>{user.pubKeys[floID]=pubKey,resolve("pubKey stored")})).catch((error=>reject(error))):reject("Incorrect pubKey"):reject("Invalid floID!")))},floDapps.sendMessage=function(floID,message){return new Promise(((resolve,reject)=>{let options={receiverID:floID,application:DEFAULT.root,comment:DEFAULT.application};floID in user.pubKeys&&(message=floCrypto.encryptData(JSON.stringify(message),user.pubKeys[floID])),floCloudAPI.sendApplicationData(message,"Message",options).then((result=>resolve(result))).catch((error=>reject(error)))}))},floDapps.requestInbox=function(callback){return new Promise(((resolve,reject)=>{let lastVC=Object.keys(user.messages).sort().pop(),options={receiverID:user.id,application:DEFAULT.root,lowerVectorClock:lastVC+1},privKey=raw_user.private;options.callback=(d,e)=>{for(let v in d){try{d[v].message instanceof Object&&"secret"in d[v].message&&(d[v].message=floCrypto.decryptData(d[v].message,privKey))}catch(error){}compactIDB.writeData("messages",d[v],v,user.db_name),user.messages[v]=d[v]}callback instanceof Function&&callback(d,e)},floCloudAPI.requestApplicationData("Message",options).then((result=>resolve(result))).catch((error=>reject(error)))}))},floDapps.manageAppConfig=function(adminPrivKey,addList,rmList,settings){return new Promise(((resolve,reject)=>{if(!startUpOptions.app_config)return reject("No configs for this app");if(Array.isArray(addList)&&addList.length||(addList=void 0),Array.isArray(rmList)&&rmList.length||(rmList=void 0),settings&&"object"==typeof settings&&Object.keys(settings).length||(settings=void 0),!addList&&!rmList&&!settings)return reject("No configuration change");var floData={[DEFAULT.application]:{addSubAdmin:addList,removeSubAdmin:rmList,settings:settings}},floID=floCrypto.getFloID(adminPrivKey);floID!=DEFAULT.adminID?reject("Access Denied for Admin privilege"):floBlockchainAPI.writeData(floID,JSON.stringify(floData),adminPrivKey).then((result=>resolve(["Updated App Configuration",result]))).catch((error=>reject(error)))}))},floDapps.manageAppTrustedIDs=function(adminPrivKey,addList,rmList){return new Promise(((resolve,reject)=>{if(!startUpOptions.app_config)return reject("No configs for this app");if(Array.isArray(addList)&&addList.length||(addList=void 0),Array.isArray(rmList)&&rmList.length||(rmList=void 0),!addList&&!rmList)return reject("No change in list");var floData={[DEFAULT.application]:{addTrustedID:addList,removeTrustedID:rmList}},floID=floCrypto.getFloID(adminPrivKey);floID!=DEFAULT.adminID?reject("Access Denied for Admin privilege"):floBlockchainAPI.writeData(floID,JSON.stringify(floData),adminPrivKey).then((result=>resolve(["Updated App Configuration",result]))).catch((error=>reject(error)))}))};const clearCredentials=floDapps.clearCredentials=function(){return new Promise(((resolve,reject)=>{compactIDB.clearData("credentials",DEFAULT.application).then((result=>{localStorage.removeItem(`${DEFAULT.application}#privKey`),user.clear(),resolve("privKey credentials deleted!")})).catch((error=>reject(error)))}))};floDapps.deleteUserData=function(credentials=!1){return new Promise(((resolve,reject)=>{let p=[];p.push(compactIDB.deleteDB(user.db_name)),credentials&&p.push(clearCredentials()),Promise.all(p).then((result=>resolve("User database(local) deleted"))).catch((error=>reject(error)))}))},floDapps.deleteAppData=function(){return new Promise(((resolve,reject)=>{compactIDB.deleteDB(DEFAULT.application).then((result=>{localStorage.removeItem(`${DEFAULT.application}#privKey`),user.clear(),compactIDB.removeData("lastTx",`${DEFAULT.application}|${DEFAULT.adminID}`,DEFAULT.root).then((result=>resolve("App database(local) deleted"))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floDapps.securePrivKey=function(pwd){return new Promise((async(resolve,reject)=>{let indexArr=localStorage.getItem(`${DEFAULT.application}#privKey`);if(!indexArr)return reject("PrivKey not found");indexArr=JSON.parse(indexArr);let encryptedKey=Crypto.AES.encrypt(await user.private,pwd),threshold=indexArr.length,shares=floCrypto.createShamirsSecretShares(encryptedKey,threshold,threshold),promises=[];for(var i=0;iresolve("Private Key Secured"))).catch((error=>reject(error)))}))},floDapps.verifyPin=function(pin=null){return new Promise(((resolve,reject)=>{var indexArr=localStorage.getItem(`${DEFAULT.application}#privKey`);console.info(indexArr),indexArr||reject("No login credentials found"),function(indexArr){return new Promise(((resolve,reject)=>{for(var promises=[],i=0;i{var secret=floCrypto.retrieveShamirSecret(shares);console.info(shares,secret),secret?resolve(secret):reject("Shares are insufficient or incorrect")})).catch((error=>{clearCredentials(),location.reload()}))}))}(JSON.parse(indexArr)).then((key=>{if(52==key.length)null===pin?resolve("Private key not secured"):reject("Private key not secured");else{if(null===pin)return reject("PIN/Password required");try{Crypto.AES.decrypt(key,pin);resolve("PIN/Password verified")}catch(error){reject("Incorrect PIN/Password")}}})).catch((error=>reject(error)))}))};const getNextGeneralData=floDapps.getNextGeneralData=function(type,vectorClock=null,options={}){var fk=floCloudAPI.util.filterKey(type,options);vectorClock=vectorClock||getNextGeneralData[fk]||"0";var filteredResult={};if(floGlobals.generalData[fk])for(let d in floGlobals.generalData[fk])d>vectorClock&&(filteredResult[d]=JSON.parse(JSON.stringify(floGlobals.generalData[fk][d])));else if(options.comment){let comment=options.comment;delete options.comment;let fk=floCloudAPI.util.filterKey(type,options);for(let d in floGlobals.generalData[fk])d>vectorClock&&floGlobals.generalData[fk][d].comment==comment&&(filteredResult[d]=JSON.parse(JSON.stringify(floGlobals.generalData[fk][d])))}if(options.decrypt){let decryptionKey=!0===options.decrypt?raw_user.private:options.decrypt;Array.isArray(decryptionKey)||(decryptionKey=[decryptionKey]);for(let f in filteredResult){let data=filteredResult[f];try{if(data.message instanceof Object&&"secret"in data.message)for(let key of decryptionKey)try{let tmp=floCrypto.decryptData(data.message,key);data.message=JSON.parse(tmp);break}catch(error){}}catch(error){}}}return getNextGeneralData[fk]=Object.keys(filteredResult).sort().pop(),filteredResult},syncData=floDapps.syncData={};syncData.oldDevice=()=>new Promise(((resolve,reject)=>{let sync={contacts:user.contacts,pubKeys:user.pubKeys,messages:user.messages},message=Crypto.AES.encrypt(JSON.stringify(sync),raw_user.private),options={receiverID:user.id,application:DEFAULT.root};floCloudAPI.sendApplicationData(message,"syncData",options).then((result=>resolve(result))).catch((error=>reject(error)))})),syncData.newDevice=()=>new Promise(((resolve,reject)=>{var options={receiverID:user.id,senderID:user.id,application:DEFAULT.root,mostRecent:!0};floCloudAPI.requestApplicationData("syncData",options).then((response=>{let vc=Object.keys(response).sort().pop(),sync=JSON.parse(Crypto.AES.decrypt(response[vc].message,raw_user.private)),promises=[];["contacts","pubKeys","messages"].forEach((c=>{for(let i in sync[c])key=i,val=sync[c][i],obs=c,promises.push(compactIDB.writeData(obs,val,key,user.db_name)),user[c][i]=sync[c][i];var key,val,obs})),Promise.all(promises).then((results=>resolve("Sync data successful"))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))}(); \ No newline at end of file diff --git a/js/floTokenAPI.js b/js/floTokenAPI.js deleted file mode 100644 index dd4eee6..0000000 --- a/js/floTokenAPI.js +++ /dev/null @@ -1,193 +0,0 @@ -(function (EXPORTS) { //floTokenAPI v1.2.0 - /* Token Operator to send/receive tokens via blockchain using API calls*/ - 'use strict'; - const tokenAPI = EXPORTS; - - const DEFAULT = { - apiURL: [floGlobals.tokenURL || "https://ranchimallflo.ranchimall.net/"], - currency: floGlobals.currency || "rupee" - } - - const torExitNodes = new Set(["185.241.208.232", "194.26.192.64", "171.25.193.25", "80.67.167.81", "192.42.116.187", "198.98.51.189", "89.58.26.216", "109.70.100.4", "149.56.22.133", "5.45.102.93", "178.17.174.14", "192.42.116.196", "185.220.101.4", "45.141.215.62", "94.102.51.15", "192.42.116.213", "107.189.28.166", "185.241.208.243", "45.141.215.80", "193.26.115.61", "192.42.116.175", "149.56.44.47", "107.189.13.91", "87.118.116.103", "178.17.171.102", "185.243.218.110", "192.42.116.208", "89.58.41.156", "2.58.56.43", "104.192.1.138", "45.95.169.184", "107.189.8.56", "176.58.121.177", "185.220.101.31", "45.141.215.200", "109.70.100.1", "185.244.192.175", "185.129.61.2", "144.172.118.41", "192.42.116.184", "45.151.167.10", "185.220.101.27", "91.203.144.194", "45.141.215.88", "179.43.182.232", "185.220.101.5", "109.70.100.2", "107.189.14.4", "94.16.116.81", "185.220.101.8", "185.220.101.12", "88.80.20.86", "23.154.177.15", "45.141.215.56", "5.42.66.6", "23.129.64.225", "104.244.75.74", "45.95.169.228", "37.187.5.192", "45.141.215.169", "109.70.100.66", "45.79.144.222", "185.227.68.78", "179.43.159.199", "2.57.122.246", "192.42.116.201", "185.220.102.248", "195.176.3.23", "45.138.16.42", "216.73.159.75", "185.165.169.239", "23.129.64.213", "109.70.100.6", "45.80.158.27", "45.138.16.240", "178.20.55.16", "192.42.116.173", "51.15.249.160", "192.42.116.200", "185.220.102.254", "45.141.215.63", "193.218.118.151", "192.42.116.211", "185.100.85.24", "185.195.71.12", "107.189.8.181", "193.189.100.199", "109.70.100.69", "185.100.87.250", "31.220.93.201", "89.236.112.100", "45.141.215.90", "185.35.202.222", "109.70.100.65", "95.142.161.63", "192.42.116.181", "192.42.116.23", "194.26.192.77", "193.189.100.198", "180.150.226.99", "23.129.64.227", "107.189.4.23", "45.141.215.235", "185.220.102.252", "109.70.100.67", "185.220.100.255", "185.220.101.21", "185.100.85.22", "128.31.0.13", "46.182.21.248", "192.42.116.174", "185.241.208.115", "185.220.101.1", "192.42.116.202", "45.141.215.97", "185.243.218.204", "78.142.18.219", "192.42.116.192", "190.120.229.98", "192.42.116.177", "45.138.16.113", "192.42.116.212", "185.220.101.3", "45.138.16.222", "5.42.80.232", "87.118.122.51", "107.189.11.166", "185.220.102.245", "185.220.102.251", "46.182.21.250", "5.255.103.235", "185.243.218.89", "185.193.52.180", "185.220.101.24", "2.57.122.215", "45.15.157.177", "185.220.100.253", "37.48.120.64", "204.8.156.142", "192.42.116.179", "185.220.100.240", "185.241.208.236", "185.195.71.244", "193.105.134.155", "51.15.59.15", "185.100.85.23", "45.151.167.11", "82.197.182.161", "192.42.116.191", "27.255.75.198", "171.25.193.79", "45.95.169.255", "45.138.16.230", "107.189.29.103", "163.172.213.212", "95.143.193.125", "23.154.177.7", "185.220.101.23", "195.176.3.24", "107.189.1.9", "192.42.116.182", "23.137.249.240", "192.42.116.189", "23.129.64.146", "45.138.16.107", "107.189.5.121", "107.189.30.236", "94.16.121.91", "109.70.100.70", "185.254.196.141", "194.15.112.133", "192.42.116.180", "173.249.57.253", "185.220.102.250", "185.100.85.25", "185.220.101.13", "185.220.101.25", "192.42.116.199", "23.154.177.2", "107.189.31.232", "45.141.215.81", "192.42.116.220", "185.67.82.114", "45.141.215.114", "185.243.218.61", "107.189.13.184", "107.189.10.141", "104.244.79.61", "185.106.94.195", "176.126.253.190", "23.154.177.22", "192.42.116.210", "185.220.102.249", "23.184.48.127", "192.42.116.218", "91.208.75.4", "192.42.116.178", "178.175.148.209", "208.109.36.224", "23.137.251.61", "94.142.241.194", "162.251.5.152", "23.154.177.4", "45.138.16.76", "45.9.150.103", "213.252.140.118", "185.243.218.95", "45.134.225.36", "109.70.100.5", "185.243.218.202", "185.220.101.19", "192.42.116.176", "109.70.100.71", "45.151.167.13", "185.220.102.4", "185.220.102.7", "104.244.79.50", "178.17.174.198", "199.195.249.214", "66.146.193.33", "107.189.8.238", "139.99.8.57", "45.141.215.95", "192.42.116.219", "114.199.75.111", "185.220.100.242", "5.42.80.234", "173.237.206.68", "139.99.172.11", "23.129.64.143", "80.241.60.207", "192.42.116.194", "45.95.169.226", "185.220.102.8", "109.70.100.3", "179.43.159.200", "192.42.116.217", "185.220.101.6", "198.98.50.199", "185.100.87.192", "193.189.100.202", "163.172.45.102", "185.220.101.0", "107.189.8.133", "185.129.61.6", "104.244.78.233", "192.42.116.15", "192.42.116.195", "45.141.215.110", "193.189.100.203", "77.48.28.237", "104.244.79.232", "193.26.115.43", "199.195.250.165", "190.211.254.97", "45.141.215.61", "185.220.101.17", "192.42.116.203", "185.220.102.247", "91.132.144.59", "185.141.147.129", "23.129.64.149", "185.183.157.214", "95.211.244.28", "192.42.116.188", "188.214.104.21", "192.42.116.186", "192.42.116.197", "107.189.13.247", "212.73.134.204", "185.235.146.29", "188.68.49.235", "92.205.237.227", "23.154.177.12", "199.195.253.180", "171.25.193.234", "185.241.208.71", "96.66.15.152", "94.16.121.226", "204.85.191.9", "91.210.59.57", "5.255.115.42", "185.220.103.113", "216.239.90.19", "77.91.87.79", "192.42.116.216", "23.154.177.23", "192.42.116.198", "173.255.255.215", "144.217.80.80", "107.189.10.175", "45.95.169.227", "103.251.167.20", "185.220.101.30", "5.255.125.196", "198.98.48.192", "185.220.102.242", "23.154.177.18", "185.86.148.90", "185.142.239.49", "185.220.101.2", "5.255.100.219", "107.189.5.7", "199.195.251.119", "185.220.101.10", "92.246.84.133", "66.220.242.222", "184.105.48.40", "23.129.64.133", "185.130.44.108", "192.42.116.20", "185.181.61.115", "192.42.116.19", "149.202.79.129", "146.59.35.38", "23.154.177.20", "185.191.204.254", "23.154.177.3", "185.233.100.23", "23.154.177.19", "45.92.1.74", "107.189.31.225", "89.58.18.10", "138.59.18.110", "185.246.188.73", "192.42.116.221", "104.244.77.192", "192.42.116.214", "178.170.37.11", "188.68.41.191", "192.42.116.183", "185.220.103.115", "178.175.135.7", "209.141.51.30", "141.98.11.62", "171.25.193.235", "23.137.249.143", "179.43.159.197", "192.99.168.180", "185.220.101.11", "185.243.218.41", "89.234.157.254", "47.243.74.136", "107.189.28.199", "185.129.61.9", "185.220.101.28", "185.220.101.29", "5.255.99.5", "179.43.182.58", "185.129.61.3", "23.129.64.135", "107.189.30.69", "51.15.227.109", "185.207.107.216", "185.129.61.129", "185.100.87.41", "23.129.64.145", "179.43.159.201", "23.129.64.224", "192.42.116.28", "93.99.104.194", "185.244.192.184", "45.95.169.223", "104.244.73.43", "185.56.83.83", "87.120.254.48", "185.185.170.27", "195.88.74.206", "107.174.138.172", "109.70.100.68", "23.129.64.139", "94.230.208.147", "77.91.85.147", "77.81.247.72", "2.58.56.220", "185.220.103.7", "149.202.79.101", "5.255.104.202", "178.175.148.195", "83.96.213.63", "185.100.87.174", "79.137.195.103", "185.220.101.20", "107.189.3.11", "185.220.101.22", "185.220.101.7", "217.12.221.131", "179.43.159.196", "45.95.169.230", "107.189.1.160", "208.109.215.188", "171.25.193.78", "204.194.29.4", "104.244.77.80", "162.247.72.199", "89.58.52.25", "192.42.116.209", "217.146.2.41", "185.220.103.117", "23.154.177.10", "91.208.75.3", "94.230.208.148", "95.128.43.164", "171.25.193.20", "102.130.113.9", "91.92.109.43", "107.189.7.144", "185.220.102.240", "5.255.124.150", "198.98.60.158", "185.227.134.106", "193.233.233.221", "71.19.144.106", "185.84.31.254", "23.129.64.132", "62.171.137.169", "193.189.100.196", "185.220.101.18", "107.189.12.3", "91.208.75.178", "193.35.18.49", "185.246.188.74", "45.132.246.245", "209.141.55.26", "198.98.48.20", "185.129.61.1", "108.61.189.136", "185.220.102.243", "107.189.1.96", "185.100.87.136", "213.95.149.22", "23.129.64.217", "192.42.116.185", "5.45.104.176", "192.42.116.193", "23.154.177.16", "198.98.49.203", "171.25.193.77", "91.208.75.153", "162.247.74.216", "179.43.159.194", "54.36.108.162", "198.98.48.33", "188.68.52.231", "185.220.100.252", "205.185.124.193", "104.244.73.190", "185.100.87.139", "23.154.177.25", "77.105.146.42", "79.137.202.92", "51.38.81.135", "87.118.116.90", "23.129.64.134", "185.246.188.67", "185.129.62.62", "185.220.100.241", "82.221.131.71", "209.141.59.116", "194.195.120.132", "185.207.107.130", "178.218.144.99", "172.104.243.155", "93.99.104.128", "87.118.122.30", "185.100.87.253", "51.195.91.124", "104.192.3.74", "185.252.232.218", "23.129.64.141", "5.196.95.34", "185.220.102.6", "23.184.48.128", "193.239.232.102", "185.220.101.16", "91.203.145.116", "185.129.61.4", "23.129.64.147", "37.228.129.63", "45.151.167.12", "93.95.228.205", "185.220.102.244", "209.141.54.203", "93.95.230.165", "94.142.244.16", "162.247.72.192", "185.146.232.234", "81.16.33.42", "107.189.30.86", "51.81.222.62", "23.154.177.5", "77.220.196.253", "72.167.47.69", "185.220.101.26", "104.219.236.100", "192.42.116.204", "185.246.128.161", "200.122.181.2", "199.195.253.247", "109.201.133.100", "142.44.234.69", "89.147.110.202", "89.185.85.140", "104.244.79.44", "5.2.79.179", "23.129.64.130", "104.244.78.187", "23.154.177.13", "5.255.97.221", "92.205.129.119", "80.82.78.14", "23.154.177.8", "51.38.113.118", "45.61.184.205", "107.189.31.134", "185.220.103.114", "179.48.251.188", "135.125.205.25", "198.98.54.49", "193.189.100.205", "185.220.102.253", "45.79.50.161", "202.69.76.36", "79.137.198.213", "46.166.139.111", "5.255.111.64", "51.89.138.51", "216.73.159.101", "166.70.207.2", "96.27.198.133", "194.15.115.212", "46.234.47.105", "146.59.35.246", "23.137.248.100", "185.220.102.241", "107.189.14.43", "212.95.50.77", "128.127.180.156", "80.67.172.162", "185.129.61.5", "185.129.61.10", "23.129.64.214", "185.220.100.254", "160.119.249.240", "185.243.218.46", "185.220.102.246", "104.244.74.97", "23.129.64.228", "23.129.64.218", "185.220.100.243", "54.36.101.21", "5.255.99.124", "107.189.13.253", "130.149.80.199", "171.25.193.80", "144.24.197.112", "199.195.251.78", "23.129.64.223", "195.80.151.30", "185.7.33.146", "107.189.4.12", "45.95.169.229", "107.189.6.124", "46.38.255.27", "107.189.8.226", "143.42.199.223", "103.251.167.10", "185.34.33.2", "5.255.98.23", "74.82.47.194", "194.163.157.49", "192.42.116.215", "185.220.101.14", "194.15.113.118", "89.147.108.62", "185.220.101.15", "185.42.170.203", "23.154.177.6", "162.247.74.27", "199.195.253.124", "193.189.100.201", "62.182.84.146", "191.101.217.24", "23.129.64.229", "85.93.218.204", "178.17.174.164", "205.185.117.149", "193.218.118.133", "23.154.177.21", "5.255.101.10", "82.221.131.5", "193.189.100.204", "103.196.37.111", "103.109.101.105", "192.42.116.18", "23.129.64.226", "107.189.13.251", "45.56.81.190", "192.42.116.13", "107.189.11.111", "198.46.166.157", "185.220.103.119", "54.38.183.101", "77.68.20.217", "185.220.101.36", "103.236.201.88", "162.247.74.213", "185.129.61.8", "89.147.110.154", "45.95.169.225", "141.239.149.94", "82.221.128.191", "72.14.179.10", "46.232.251.191", "23.129.64.215", "162.247.74.7", "23.154.177.14", "89.147.109.226", "193.41.226.117", "89.147.108.209", "23.129.64.137", "93.123.12.112", "185.14.97.37", "103.163.218.11", "23.129.64.131", "23.129.64.142", "23.137.249.185", "89.58.41.251", "185.220.101.9", "202.182.99.129", "205.185.119.35", "193.189.100.194", "204.85.191.8", "185.56.171.94", "23.129.64.144", "102.130.127.117", "192.42.116.24", "179.43.159.198", "185.38.175.133", "185.220.101.39", "193.168.143.129", "5.255.127.222", "95.211.210.103", "185.220.103.116", "23.129.64.211", "23.129.64.220", "185.113.128.30", "151.80.148.159", "192.99.149.111", "23.129.64.210", "37.228.129.128", "91.208.75.239", "185.220.103.120", "185.165.171.84", "193.105.134.150", "209.141.46.203", "209.141.50.178", "104.244.74.23", "45.95.169.224", "23.129.64.140", "176.118.193.33", "204.85.191.7", "104.244.73.193", "162.247.74.204", "91.208.75.156", "205.185.116.34", "125.212.241.131", "5.2.72.110", "179.43.159.195", "185.154.110.142", "91.206.26.26", "45.79.177.21", "23.154.177.9", "193.189.100.197", "46.165.243.36", "107.189.2.108", "23.154.177.17", "23.129.64.148", "5.45.98.162", "5.255.101.131", "23.129.64.136", "107.189.31.33", "185.82.219.109", "104.244.73.136", "185.129.61.7", "5.255.115.58", "23.154.177.24", "165.73.242.163", "193.189.100.200", "192.46.227.185", "5.196.8.113", "77.91.86.95", "85.209.176.103", "23.137.249.8", "5.255.98.151", "23.129.64.221", "23.129.64.219", "23.129.64.216", "185.243.218.35", "104.244.77.208", "94.228.169.70", "51.75.64.23", "176.58.100.98", "23.154.177.11", "23.129.64.138", "143.42.110.237", "94.16.112.22", "144.172.118.4", "185.130.47.58", "185.154.110.17", "104.244.72.132", "5.2.79.190", "23.129.64.212", "109.169.33.163", "5.2.67.226", "109.69.67.17", "108.181.27.205", "5.255.103.190", "107.189.14.106", "5.255.99.147", "193.189.100.206", "193.218.118.182", "185.181.61.142", "23.129.64.222", "193.35.18.77", "185.100.86.128", "91.203.5.118", "83.97.20.77", "45.138.16.203", "2.57.122.58", "185.181.61.18", "195.176.3.19", "195.176.3.20", "198.58.107.53", "138.128.222.68", "118.163.74.160", "185.241.208.54", "38.97.116.244", "104.244.77.79", "103.253.24.18", "185.225.69.203", "162.247.74.206", "79.124.8.241", "91.203.5.115", "144.172.118.102", "144.172.118.124", "185.225.69.232", "163.5.143.76", "144.172.118.51", "178.20.55.182", "109.104.153.22", "193.233.133.109", "51.158.115.62", "92.205.31.137", "185.193.158.134", "217.12.215.167", "45.15.158.39", "185.174.136.114", "91.219.239.166", "91.219.237.56", "51.159.211.57", "192.210.255.181", "185.170.114.25", "205.185.123.93", "205.185.121.170", "107.189.13.180", "104.244.78.162", "104.244.76.170", "104.244.74.57", "195.160.220.104", "31.220.98.139", "158.220.92.203", "23.184.48.101", "178.31.22.116", "79.102.34.63", "185.220.103.5", "179.43.128.16", "45.128.133.242", "185.220.103.118", "185.100.85.132", "107.189.7.48", "5.135.174.211", "45.8.22.207", "185.220.101.159", "185.220.101.141", "185.220.101.134", "185.220.101.147", "185.220.101.153", "185.220.101.145", "185.220.101.158", "185.220.101.160", "185.220.101.137", "185.220.101.140", "185.220.101.132", "185.220.101.157", "185.220.101.150", "185.220.101.143", "158.69.201.47", "107.189.1.175", "176.58.89.182", "185.220.101.138", "82.118.242.158", "217.170.201.71", "193.189.100.195", "144.172.118.48", "185.220.101.135", "185.220.101.191", "185.220.101.136", "185.220.101.179", "185.220.101.170", "185.220.101.149", "185.220.101.173", "185.220.101.171", "185.220.101.161", "185.220.101.163", "185.220.101.152", "185.220.101.162", "185.220.101.176", "185.220.101.188", "185.82.127.128", "85.235.145.205", "172.81.131.139", "5.255.100.26", "62.63.244.7", "104.219.236.101", "23.137.248.139", "185.241.208.204", "45.141.215.111", "185.241.208.202", "45.141.215.21", "45.61.185.172", "185.241.208.206", "205.185.113.180", "93.242.68.75", "185.220.100.248", "185.220.100.251", "185.220.100.247", "185.220.100.245", "185.220.100.246", "185.220.100.249", "185.220.100.250", "185.220.100.244", "77.72.85.30", "51.222.142.67", "107.172.31.165", "107.174.231.197", "198.144.178.163", "23.137.250.34", "107.172.13.143", "107.172.31.146", "173.232.195.137", "50.3.182.156", "173.232.195.144", "173.232.195.146", "172.81.131.168", "172.81.131.84", "77.48.28.239", "172.81.131.156", "185.183.159.40", "196.189.30.114", "107.189.8.5", "185.220.101.168", "185.220.101.165", "185.220.101.142", "185.220.101.167", "185.220.101.166", "185.220.101.169", "77.48.28.193", "37.228.129.5", "144.172.73.11", "107.189.14.57", "84.16.224.227", "185.220.103.4", "162.247.74.202", "185.220.103.6", "162.247.74.200", "185.220.103.9", "185.220.103.8", "154.12.254.57", "94.103.124.184", "185.220.101.189", "67.219.109.141", "185.220.101.187", "185.220.101.186", "185.220.101.183", "50.3.182.133", "185.220.101.182", "185.220.101.184", "188.172.229.15", "89.58.18.210", "45.9.150.130", "190.103.179.98", "108.181.124.143", "178.218.144.51", "185.220.101.66", "185.220.101.70", "185.220.101.68", "185.220.101.77", "185.220.101.78", "185.220.101.81", "185.220.101.71", "185.220.101.83", "185.220.101.75", "185.220.101.85", "185.220.101.73", "185.220.101.82", "185.220.101.65", "185.220.101.84", "185.220.101.76", "185.220.101.86", "185.220.101.69", "185.220.101.67", "185.220.101.80", "185.220.101.64", "185.220.101.74", "185.220.101.79", "185.220.101.72", "185.220.101.87", "199.249.230.120", "184.75.221.171", "5.182.86.212", "104.244.72.115", "198.23.133.132", "23.94.36.142", "198.98.60.90", "84.19.182.20", "45.9.148.219", "217.160.88.146", "104.219.232.126", "45.139.122.241", "199.195.253.156", "75.119.142.240", "199.249.230.103", "199.249.230.104", "199.249.230.116", "199.249.230.101", "199.249.230.119", "199.249.230.100", "199.249.230.102", "199.249.230.109", "199.249.230.81", "199.249.230.176", "199.249.230.79", "199.249.230.167", "199.249.230.88", "199.249.230.188", "199.249.230.80", "199.249.230.144", "199.249.230.78", "199.249.230.111", "199.249.230.68", "199.249.230.180", "199.249.230.150", "199.249.230.70", "199.249.230.77", "199.249.230.112", "199.249.230.65", "199.249.230.183", "199.249.230.189", "199.249.230.178", "199.249.230.145", "199.249.230.115", "199.249.230.147", "199.249.230.66", "199.249.230.140", "199.249.230.114", "199.249.230.170", "199.249.230.71", "199.249.230.148", "199.249.230.67", "199.249.230.75", "199.249.230.146", "199.249.230.151", "199.249.230.187", "199.249.230.174", "199.249.230.143", "199.249.230.118", "199.249.230.64", "199.249.230.85", "199.249.230.113", "199.249.230.155", "199.249.230.153", "199.249.230.89", "45.77.67.251", "123.253.35.32", "45.83.104.137", "94.32.66.15", "185.220.101.181", "185.220.101.178", "185.220.101.177", "185.220.101.175", "185.220.101.172", "94.16.116.86", "5.181.80.107", "198.50.207.20", "107.189.7.168", "85.215.76.62", "185.247.184.105", "178.236.247.122", "109.107.190.171", "193.233.233.124", "193.218.118.188", "2.58.95.45", "45.154.98.102", "92.205.185.52", "92.205.163.226", "185.217.125.210", "5.255.118.104", "212.69.167.80", "23.137.249.227", "5.255.118.244", "71.19.148.129", "143.42.114.46", "45.33.15.243", "104.237.158.32", "172.232.161.205", "172.232.161.206", "74.207.248.172", "172.233.209.179", "45.66.35.21", "45.66.35.35", "45.66.35.10", "45.66.35.20", "45.66.35.22", "51.210.138.64", "130.204.161.3", "175.214.127.6", "31.220.85.162", "198.96.155.3", "50.118.225.160", "45.135.132.20", "23.152.24.77", "45.95.169.99", "94.75.225.81", "37.228.129.131", "23.137.249.62", "103.172.134.26", "199.249.230.121", "191.252.111.55", "35.0.127.52", "185.129.62.63", "23.94.211.25", "185.220.101.139", "185.220.101.144", "185.220.101.130", "185.220.101.156", "185.220.101.128", "185.220.101.131", "185.220.101.154", "185.220.101.164", "185.220.101.180", "185.220.101.155", "185.220.101.133", "185.220.101.190", "185.220.101.151", "185.220.101.174", "185.220.101.148", "185.220.101.129", "185.220.101.185", "37.221.208.68", "87.120.254.132", "5.255.106.9", "45.15.158.165", "193.35.18.105", "178.17.170.23", "185.146.232.243", "194.163.178.164", "94.140.115.63", "37.228.129.24", "81.0.248.210", "193.35.18.98", "45.128.232.170", "193.35.18.96", "45.128.232.102", "193.35.18.94", "193.35.18.95", "149.102.128.242", "89.187.143.31", "193.239.232.228", "103.208.86.5", "193.35.18.120", "185.130.44.43", "185.219.142.126", "37.1.201.144", "5.255.99.108", "85.204.116.211", "130.193.10.21", "130.193.15.79", "84.239.46.144", "178.218.162.62", "199.249.230.122", "199.249.230.84", "45.141.202.164", "199.249.230.74", "148.113.2.107", "199.249.230.105", "199.249.230.73", "199.249.230.110", "199.249.230.72", "199.249.230.86", "103.129.222.46", "64.5.123.66", "185.239.71.160", "5.42.80.233", "5.42.80.235", "200.25.27.112", "46.226.107.206", "103.106.3.175", "96.42.26.63", "192.42.116.26", "192.42.116.17", "192.42.116.14", "192.42.116.22", "192.42.116.25", "192.42.116.27", "74.208.106.128", "213.232.235.83", "91.208.197.144", "51.195.166.174", "198.98.53.136", "157.143.80.38", "198.50.128.237", "193.233.232.86", "144.126.152.77", "158.220.80.216", "154.16.116.61", "45.88.223.151", "144.126.132.30", "89.147.110.214", "89.163.155.136", "107.189.13.93", "77.232.143.255", "77.232.143.243", "77.232.143.248", "94.228.163.25", "199.249.230.186", "199.249.230.177", "199.249.230.159", "199.249.230.161", "199.249.230.163", "199.249.230.149", "199.249.230.154", "199.249.230.164", "199.249.230.160", "199.249.230.173", "199.249.230.158", "199.249.230.157", "199.249.230.108", "199.249.230.83", "199.249.230.168", "199.249.230.82", "199.249.230.166", "199.249.230.123", "199.249.230.106", "199.249.230.76", "199.249.230.117", "199.249.230.169", "199.249.230.171", "199.249.230.175", "199.249.230.107", "199.249.230.152", "199.249.230.162", "2.58.95.53", "199.249.230.69", "2.58.95.47", "2.58.95.59", "2.58.95.56", "178.175.142.26", "199.249.230.156", "199.249.230.87", "103.28.52.93", "185.107.70.56", "89.147.108.56", "148.113.2.104", "38.242.203.135", "162.247.74.201", "172.232.238.10", "5.255.98.198", "5.255.98.231", "23.137.249.150", "149.102.155.205", "199.249.230.179", "199.249.230.165", "199.249.230.182", "199.249.230.184", "199.249.230.142", "136.243.147.59", "199.249.230.185", "185.220.101.89", "149.102.145.222", "185.220.101.90", "185.220.101.88", "87.118.110.27", "37.48.70.156", "185.165.190.111", "5.255.125.153", "205.185.124.176", "107.189.14.41", "93.95.228.81", "172.81.131.140", "185.38.142.4", "95.168.173.143", "178.218.144.18", "189.147.238.226", "189.147.187.10", "189.147.242.169", "104.219.236.93", "161.35.129.51", "86.104.194.13", "104.244.74.159", "185.220.101.40", "185.220.101.32", "185.220.101.38", "185.220.101.37", "185.220.101.35", "185.220.101.33", "185.220.101.34", "185.220.101.41", "185.220.101.42", "205.185.127.100", "185.220.101.57", "185.220.101.43", "185.220.101.46", "185.220.101.58", "185.220.101.61", "185.220.101.60", "185.220.101.63", "185.220.101.54", "185.220.101.52", "185.220.101.62", "185.220.101.56", "185.220.101.44", "185.220.101.49", "5.255.117.56", "185.220.101.55", "185.220.101.45", "185.220.101.53", "185.220.101.59", "185.220.101.51", "185.220.101.48", "185.220.101.47", "185.220.101.50", "95.111.238.0", "152.89.233.169", "89.147.110.82", "176.58.117.81", "23.155.8.104", "51.89.153.112", "5.61.51.143", "5.135.174.213", "37.120.166.23", "37.252.255.135", "82.153.138.48", "185.81.115.120", "45.139.122.176", "84.211.225.54", "31.220.87.46", "144.172.73.6", "51.89.200.109", "212.44.107.82", "89.147.111.124", "94.177.106.59", "94.177.106.55", "94.177.106.46", "93.95.231.88", "152.32.238.235", "74.208.96.95", "38.242.239.62", "87.118.114.44", "80.78.25.9", "185.193.125.95", "107.173.179.59", "179.43.159.78", "81.17.28.95", "45.79.129.209", "82.221.139.190", "107.189.13.254", "81.19.137.127", "149.102.129.11", "81.0.218.34", "93.90.74.31", "51.81.254.4", "109.123.231.55", "185.196.8.2", "158.220.81.45", "62.149.23.133", "158.220.81.47", "158.220.81.78", "209.141.51.180", "176.121.81.51", "178.17.170.184", "202.61.226.98", "202.139.229.157", "89.147.111.106"]); - const checkIfTor = tokenAPI.checkIfTor = () => { - return fetch('https://api.ipify.org?format=json').then(response => response.json()) - .then(result => { - return torExitNodes.has(result.ip) - }).catch(e => { - console.error(e) - return false - }) - } - let isTor = false; - checkIfTor().then(result => { - isTor = result - if (isTor) { - DEFAULT.apiURL.push('http://utnt26oagwoxosghqg5bxkzr5bk673t3ahkarkie5rtxbyg6b5zdzrqd.onion/') - } - }); - - Object.defineProperties(tokenAPI, { - URL: { - get: () => DEFAULT.apiURL[0], - }, - currency: { - get: () => DEFAULT.currency, - set: currency => DEFAULT.currency = currency - } - }); - - if (floGlobals.currency) tokenAPI.currency = floGlobals.currency; - - Object.defineProperties(floGlobals, { - currency: { - get: () => DEFAULT.currency, - set: currency => DEFAULT.currency = currency - } - }); - - const fetch_api = tokenAPI.fetch = function (apicall, apiURLs = DEFAULT.apiURL) { - return new Promise((resolve, reject) => { - if (apiURLs.length === 0) { - reject("No API URLs available"); - return; - } - const currentURL = apiURLs[0]; - console.debug(currentURL + apicall); - fetch(currentURL + apicall).then(response => { - if (response.ok) - response.json().then(data => resolve(data)); - else - reject(response); - }).catch(error => { - console.error(`Failed to fetch from ${currentURL}: ${error}`); - // Try the next API URL recursively - fetch_api(apicall, apiURLs.slice(1)).then(resolve).catch(reject); - }); - }); - } - - const getBalance = tokenAPI.getBalance = function (floID, token = DEFAULT.currency) { - return new Promise((resolve, reject) => { - fetch_api(`api/v2/floAddressInfo/${floID}`) - .then(result => resolve(result.floAddressBalances[token]?.balance || 0)) - .catch(error => reject(error)) - }) - } - - tokenAPI.getTx = function (txID) { - return new Promise((resolve, reject) => { - fetch_api(`api/v2/transactionDetails/${txID}`).then(res => { - if (res.result === "error") - reject(res.description); - else if (!res.parsedFloData) - reject("Data piece (parsedFloData) missing"); - else if (!res.transactionDetails) - reject("Data piece (transactionDetails) missing"); - else - resolve(res); - }).catch(error => reject(error)) - }) - } - - tokenAPI.sendToken = function (privKey, amount, receiverID, message = "", token = DEFAULT.currency, options = {}) { - return new Promise((resolve, reject) => { - let senderID = floCrypto.getFloID(privKey); - if (typeof amount !== "number" || isNaN(amount) || amount <= 0) - return reject("Invalid amount"); - getBalance(senderID, token).then(bal => { - if (amount > bal) - return reject(`Insufficient ${token}# balance`); - floBlockchainAPI.writeData(senderID, `send ${amount} ${token}# ${message}`, privKey, receiverID, options) - .then(txid => resolve(txid)) - .catch(error => reject(error)) - }).catch(error => reject(error)) - }); - } - - function sendTokens_raw(privKey, receiverID, token, amount, utxo, vout, scriptPubKey) { - return new Promise((resolve, reject) => { - var trx = bitjs.transaction(); - trx.addinput(utxo, vout, scriptPubKey) - trx.addoutput(receiverID, floBlockchainAPI.sendAmt); - trx.addflodata(`send ${amount} ${token}#`); - var signedTxHash = trx.sign(privKey, 1); - floBlockchainAPI.broadcastTx(signedTxHash) - .then(txid => resolve([receiverID, txid])) - .catch(error => reject([receiverID, error])) - }) - } - - //bulk transfer tokens - tokenAPI.bulkTransferTokens = function (sender, privKey, token, receivers) { - return new Promise((resolve, reject) => { - if (typeof receivers !== 'object') - return reject("receivers must be object in format {receiver1: amount1, receiver2:amount2...}") - - let receiver_list = Object.keys(receivers), amount_list = Object.values(receivers); - let invalidReceivers = receiver_list.filter(id => !floCrypto.validateFloID(id)); - let invalidAmount = amount_list.filter(val => typeof val !== 'number' || val <= 0); - if (invalidReceivers.length) - return reject(`Invalid receivers: ${invalidReceivers}`); - else if (invalidAmount.length) - return reject(`Invalid amounts: ${invalidAmount}`); - - if (receiver_list.length == 0) - return reject("Receivers cannot be empty"); - - if (receiver_list.length == 1) { - let receiver = receiver_list[0], amount = amount_list[0]; - floTokenAPI.sendToken(privKey, amount, receiver, "", token) - .then(txid => resolve({ success: { [receiver]: txid } })) - .catch(error => reject(error)) - } else { - //check for token balance - floTokenAPI.getBalance(sender, token).then(token_balance => { - let total_token_amout = amount_list.reduce((a, e) => a + e, 0); - if (total_token_amout > token_balance) - return reject(`Insufficient ${token}# balance`); - - //split utxos - floBlockchainAPI.splitUTXOs(sender, privKey, receiver_list.length).then(split_txid => { - //wait for the split utxo to get confirmation - floBlockchainAPI.waitForConfirmation(split_txid).then(split_tx => { - //send tokens using the split-utxo - var scriptPubKey = split_tx.vout[0].scriptPubKey.hex; - let promises = []; - for (let i in receiver_list) - promises.push(sendTokens_raw(privKey, receiver_list[i], token, amount_list[i], split_txid, i, scriptPubKey)); - Promise.allSettled(promises).then(results => { - let success = Object.fromEntries(results.filter(r => r.status == 'fulfilled').map(r => r.value)); - let failed = Object.fromEntries(results.filter(r => r.status == 'rejected').map(r => r.reason)); - resolve({ success, failed }); - }) - }).catch(error => reject(error)) - }).catch(error => reject(error)) - }).catch(error => reject(error)) - } - - }) - } - - tokenAPI.getAllTxs = function (floID, token = DEFAULT.currency) { - return new Promise((resolve, reject) => { - fetch_api(`api/v2/floAddressTransactions/${floID}${token ? `?token=${token}` : ''}`) - .then(result => resolve(result)) - .catch(error => reject(error)) - }) - } - - const util = tokenAPI.util = {}; - - util.parseTxData = function (txData) { - let parsedData = {}; - for (let p in txData.parsedFloData) - parsedData[p] = txData.parsedFloData[p]; - parsedData.sender = txData.transactionDetails.vin[0].addr; - for (let vout of txData.transactionDetails.vout) - if (vout.scriptPubKey.addresses[0] !== parsedData.sender) - parsedData.receiver = vout.scriptPubKey.addresses[0]; - parsedData.time = txData.transactionDetails.time; - return parsedData; - } - -})('object' === typeof module ? module.exports : window.floTokenAPI = {}); \ No newline at end of file diff --git a/js/floTokenAPI.min.js b/js/floTokenAPI.min.js deleted file mode 100644 index a381d34..0000000 --- a/js/floTokenAPI.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(EXPORTS){"use strict";const tokenAPI="object"===typeof module?module.exports:window.floTokenAPI={},DEFAULT={apiURL:[floGlobals.tokenURL||"https://ranchimallflo.ranchimall.net/"],currency:floGlobals.currency||"rupee"},torExitNodes=new Set(["185.241.208.232","194.26.192.64","171.25.193.25","80.67.167.81","192.42.116.187","198.98.51.189","89.58.26.216","109.70.100.4","149.56.22.133","5.45.102.93","178.17.174.14","192.42.116.196","185.220.101.4","45.141.215.62","94.102.51.15","192.42.116.213","107.189.28.166","185.241.208.243","45.141.215.80","193.26.115.61","192.42.116.175","149.56.44.47","107.189.13.91","87.118.116.103","178.17.171.102","185.243.218.110","192.42.116.208","89.58.41.156","2.58.56.43","104.192.1.138","45.95.169.184","107.189.8.56","176.58.121.177","185.220.101.31","45.141.215.200","109.70.100.1","185.244.192.175","185.129.61.2","144.172.118.41","192.42.116.184","45.151.167.10","185.220.101.27","91.203.144.194","45.141.215.88","179.43.182.232","185.220.101.5","109.70.100.2","107.189.14.4","94.16.116.81","185.220.101.8","185.220.101.12","88.80.20.86","23.154.177.15","45.141.215.56","5.42.66.6","23.129.64.225","104.244.75.74","45.95.169.228","37.187.5.192","45.141.215.169","109.70.100.66","45.79.144.222","185.227.68.78","179.43.159.199","2.57.122.246","192.42.116.201","185.220.102.248","195.176.3.23","45.138.16.42","216.73.159.75","185.165.169.239","23.129.64.213","109.70.100.6","45.80.158.27","45.138.16.240","178.20.55.16","192.42.116.173","51.15.249.160","192.42.116.200","185.220.102.254","45.141.215.63","193.218.118.151","192.42.116.211","185.100.85.24","185.195.71.12","107.189.8.181","193.189.100.199","109.70.100.69","185.100.87.250","31.220.93.201","89.236.112.100","45.141.215.90","185.35.202.222","109.70.100.65","95.142.161.63","192.42.116.181","192.42.116.23","194.26.192.77","193.189.100.198","180.150.226.99","23.129.64.227","107.189.4.23","45.141.215.235","185.220.102.252","109.70.100.67","185.220.100.255","185.220.101.21","185.100.85.22","128.31.0.13","46.182.21.248","192.42.116.174","185.241.208.115","185.220.101.1","192.42.116.202","45.141.215.97","185.243.218.204","78.142.18.219","192.42.116.192","190.120.229.98","192.42.116.177","45.138.16.113","192.42.116.212","185.220.101.3","45.138.16.222","5.42.80.232","87.118.122.51","107.189.11.166","185.220.102.245","185.220.102.251","46.182.21.250","5.255.103.235","185.243.218.89","185.193.52.180","185.220.101.24","2.57.122.215","45.15.157.177","185.220.100.253","37.48.120.64","204.8.156.142","192.42.116.179","185.220.100.240","185.241.208.236","185.195.71.244","193.105.134.155","51.15.59.15","185.100.85.23","45.151.167.11","82.197.182.161","192.42.116.191","27.255.75.198","171.25.193.79","45.95.169.255","45.138.16.230","107.189.29.103","163.172.213.212","95.143.193.125","23.154.177.7","185.220.101.23","195.176.3.24","107.189.1.9","192.42.116.182","23.137.249.240","192.42.116.189","23.129.64.146","45.138.16.107","107.189.5.121","107.189.30.236","94.16.121.91","109.70.100.70","185.254.196.141","194.15.112.133","192.42.116.180","173.249.57.253","185.220.102.250","185.100.85.25","185.220.101.13","185.220.101.25","192.42.116.199","23.154.177.2","107.189.31.232","45.141.215.81","192.42.116.220","185.67.82.114","45.141.215.114","185.243.218.61","107.189.13.184","107.189.10.141","104.244.79.61","185.106.94.195","176.126.253.190","23.154.177.22","192.42.116.210","185.220.102.249","23.184.48.127","192.42.116.218","91.208.75.4","192.42.116.178","178.175.148.209","208.109.36.224","23.137.251.61","94.142.241.194","162.251.5.152","23.154.177.4","45.138.16.76","45.9.150.103","213.252.140.118","185.243.218.95","45.134.225.36","109.70.100.5","185.243.218.202","185.220.101.19","192.42.116.176","109.70.100.71","45.151.167.13","185.220.102.4","185.220.102.7","104.244.79.50","178.17.174.198","199.195.249.214","66.146.193.33","107.189.8.238","139.99.8.57","45.141.215.95","192.42.116.219","114.199.75.111","185.220.100.242","5.42.80.234","173.237.206.68","139.99.172.11","23.129.64.143","80.241.60.207","192.42.116.194","45.95.169.226","185.220.102.8","109.70.100.3","179.43.159.200","192.42.116.217","185.220.101.6","198.98.50.199","185.100.87.192","193.189.100.202","163.172.45.102","185.220.101.0","107.189.8.133","185.129.61.6","104.244.78.233","192.42.116.15","192.42.116.195","45.141.215.110","193.189.100.203","77.48.28.237","104.244.79.232","193.26.115.43","199.195.250.165","190.211.254.97","45.141.215.61","185.220.101.17","192.42.116.203","185.220.102.247","91.132.144.59","185.141.147.129","23.129.64.149","185.183.157.214","95.211.244.28","192.42.116.188","188.214.104.21","192.42.116.186","192.42.116.197","107.189.13.247","212.73.134.204","185.235.146.29","188.68.49.235","92.205.237.227","23.154.177.12","199.195.253.180","171.25.193.234","185.241.208.71","96.66.15.152","94.16.121.226","204.85.191.9","91.210.59.57","5.255.115.42","185.220.103.113","216.239.90.19","77.91.87.79","192.42.116.216","23.154.177.23","192.42.116.198","173.255.255.215","144.217.80.80","107.189.10.175","45.95.169.227","103.251.167.20","185.220.101.30","5.255.125.196","198.98.48.192","185.220.102.242","23.154.177.18","185.86.148.90","185.142.239.49","185.220.101.2","5.255.100.219","107.189.5.7","199.195.251.119","185.220.101.10","92.246.84.133","66.220.242.222","184.105.48.40","23.129.64.133","185.130.44.108","192.42.116.20","185.181.61.115","192.42.116.19","149.202.79.129","146.59.35.38","23.154.177.20","185.191.204.254","23.154.177.3","185.233.100.23","23.154.177.19","45.92.1.74","107.189.31.225","89.58.18.10","138.59.18.110","185.246.188.73","192.42.116.221","104.244.77.192","192.42.116.214","178.170.37.11","188.68.41.191","192.42.116.183","185.220.103.115","178.175.135.7","209.141.51.30","141.98.11.62","171.25.193.235","23.137.249.143","179.43.159.197","192.99.168.180","185.220.101.11","185.243.218.41","89.234.157.254","47.243.74.136","107.189.28.199","185.129.61.9","185.220.101.28","185.220.101.29","5.255.99.5","179.43.182.58","185.129.61.3","23.129.64.135","107.189.30.69","51.15.227.109","185.207.107.216","185.129.61.129","185.100.87.41","23.129.64.145","179.43.159.201","23.129.64.224","192.42.116.28","93.99.104.194","185.244.192.184","45.95.169.223","104.244.73.43","185.56.83.83","87.120.254.48","185.185.170.27","195.88.74.206","107.174.138.172","109.70.100.68","23.129.64.139","94.230.208.147","77.91.85.147","77.81.247.72","2.58.56.220","185.220.103.7","149.202.79.101","5.255.104.202","178.175.148.195","83.96.213.63","185.100.87.174","79.137.195.103","185.220.101.20","107.189.3.11","185.220.101.22","185.220.101.7","217.12.221.131","179.43.159.196","45.95.169.230","107.189.1.160","208.109.215.188","171.25.193.78","204.194.29.4","104.244.77.80","162.247.72.199","89.58.52.25","192.42.116.209","217.146.2.41","185.220.103.117","23.154.177.10","91.208.75.3","94.230.208.148","95.128.43.164","171.25.193.20","102.130.113.9","91.92.109.43","107.189.7.144","185.220.102.240","5.255.124.150","198.98.60.158","185.227.134.106","193.233.233.221","71.19.144.106","185.84.31.254","23.129.64.132","62.171.137.169","193.189.100.196","185.220.101.18","107.189.12.3","91.208.75.178","193.35.18.49","185.246.188.74","45.132.246.245","209.141.55.26","198.98.48.20","185.129.61.1","108.61.189.136","185.220.102.243","107.189.1.96","185.100.87.136","213.95.149.22","23.129.64.217","192.42.116.185","5.45.104.176","192.42.116.193","23.154.177.16","198.98.49.203","171.25.193.77","91.208.75.153","162.247.74.216","179.43.159.194","54.36.108.162","198.98.48.33","188.68.52.231","185.220.100.252","205.185.124.193","104.244.73.190","185.100.87.139","23.154.177.25","77.105.146.42","79.137.202.92","51.38.81.135","87.118.116.90","23.129.64.134","185.246.188.67","185.129.62.62","185.220.100.241","82.221.131.71","209.141.59.116","194.195.120.132","185.207.107.130","178.218.144.99","172.104.243.155","93.99.104.128","87.118.122.30","185.100.87.253","51.195.91.124","104.192.3.74","185.252.232.218","23.129.64.141","5.196.95.34","185.220.102.6","23.184.48.128","193.239.232.102","185.220.101.16","91.203.145.116","185.129.61.4","23.129.64.147","37.228.129.63","45.151.167.12","93.95.228.205","185.220.102.244","209.141.54.203","93.95.230.165","94.142.244.16","162.247.72.192","185.146.232.234","81.16.33.42","107.189.30.86","51.81.222.62","23.154.177.5","77.220.196.253","72.167.47.69","185.220.101.26","104.219.236.100","192.42.116.204","185.246.128.161","200.122.181.2","199.195.253.247","109.201.133.100","142.44.234.69","89.147.110.202","89.185.85.140","104.244.79.44","5.2.79.179","23.129.64.130","104.244.78.187","23.154.177.13","5.255.97.221","92.205.129.119","80.82.78.14","23.154.177.8","51.38.113.118","45.61.184.205","107.189.31.134","185.220.103.114","179.48.251.188","135.125.205.25","198.98.54.49","193.189.100.205","185.220.102.253","45.79.50.161","202.69.76.36","79.137.198.213","46.166.139.111","5.255.111.64","51.89.138.51","216.73.159.101","166.70.207.2","96.27.198.133","194.15.115.212","46.234.47.105","146.59.35.246","23.137.248.100","185.220.102.241","107.189.14.43","212.95.50.77","128.127.180.156","80.67.172.162","185.129.61.5","185.129.61.10","23.129.64.214","185.220.100.254","160.119.249.240","185.243.218.46","185.220.102.246","104.244.74.97","23.129.64.228","23.129.64.218","185.220.100.243","54.36.101.21","5.255.99.124","107.189.13.253","130.149.80.199","171.25.193.80","144.24.197.112","199.195.251.78","23.129.64.223","195.80.151.30","185.7.33.146","107.189.4.12","45.95.169.229","107.189.6.124","46.38.255.27","107.189.8.226","143.42.199.223","103.251.167.10","185.34.33.2","5.255.98.23","74.82.47.194","194.163.157.49","192.42.116.215","185.220.101.14","194.15.113.118","89.147.108.62","185.220.101.15","185.42.170.203","23.154.177.6","162.247.74.27","199.195.253.124","193.189.100.201","62.182.84.146","191.101.217.24","23.129.64.229","85.93.218.204","178.17.174.164","205.185.117.149","193.218.118.133","23.154.177.21","5.255.101.10","82.221.131.5","193.189.100.204","103.196.37.111","103.109.101.105","192.42.116.18","23.129.64.226","107.189.13.251","45.56.81.190","192.42.116.13","107.189.11.111","198.46.166.157","185.220.103.119","54.38.183.101","77.68.20.217","185.220.101.36","103.236.201.88","162.247.74.213","185.129.61.8","89.147.110.154","45.95.169.225","141.239.149.94","82.221.128.191","72.14.179.10","46.232.251.191","23.129.64.215","162.247.74.7","23.154.177.14","89.147.109.226","193.41.226.117","89.147.108.209","23.129.64.137","93.123.12.112","185.14.97.37","103.163.218.11","23.129.64.131","23.129.64.142","23.137.249.185","89.58.41.251","185.220.101.9","202.182.99.129","205.185.119.35","193.189.100.194","204.85.191.8","185.56.171.94","23.129.64.144","102.130.127.117","192.42.116.24","179.43.159.198","185.38.175.133","185.220.101.39","193.168.143.129","5.255.127.222","95.211.210.103","185.220.103.116","23.129.64.211","23.129.64.220","185.113.128.30","151.80.148.159","192.99.149.111","23.129.64.210","37.228.129.128","91.208.75.239","185.220.103.120","185.165.171.84","193.105.134.150","209.141.46.203","209.141.50.178","104.244.74.23","45.95.169.224","23.129.64.140","176.118.193.33","204.85.191.7","104.244.73.193","162.247.74.204","91.208.75.156","205.185.116.34","125.212.241.131","5.2.72.110","179.43.159.195","185.154.110.142","91.206.26.26","45.79.177.21","23.154.177.9","193.189.100.197","46.165.243.36","107.189.2.108","23.154.177.17","23.129.64.148","5.45.98.162","5.255.101.131","23.129.64.136","107.189.31.33","185.82.219.109","104.244.73.136","185.129.61.7","5.255.115.58","23.154.177.24","165.73.242.163","193.189.100.200","192.46.227.185","5.196.8.113","77.91.86.95","85.209.176.103","23.137.249.8","5.255.98.151","23.129.64.221","23.129.64.219","23.129.64.216","185.243.218.35","104.244.77.208","94.228.169.70","51.75.64.23","176.58.100.98","23.154.177.11","23.129.64.138","143.42.110.237","94.16.112.22","144.172.118.4","185.130.47.58","185.154.110.17","104.244.72.132","5.2.79.190","23.129.64.212","109.169.33.163","5.2.67.226","109.69.67.17","108.181.27.205","5.255.103.190","107.189.14.106","5.255.99.147","193.189.100.206","193.218.118.182","185.181.61.142","23.129.64.222","193.35.18.77","185.100.86.128","91.203.5.118","83.97.20.77","45.138.16.203","2.57.122.58","185.181.61.18","195.176.3.19","195.176.3.20","198.58.107.53","138.128.222.68","118.163.74.160","185.241.208.54","38.97.116.244","104.244.77.79","103.253.24.18","185.225.69.203","162.247.74.206","79.124.8.241","91.203.5.115","144.172.118.102","144.172.118.124","185.225.69.232","163.5.143.76","144.172.118.51","178.20.55.182","109.104.153.22","193.233.133.109","51.158.115.62","92.205.31.137","185.193.158.134","217.12.215.167","45.15.158.39","185.174.136.114","91.219.239.166","91.219.237.56","51.159.211.57","192.210.255.181","185.170.114.25","205.185.123.93","205.185.121.170","107.189.13.180","104.244.78.162","104.244.76.170","104.244.74.57","195.160.220.104","31.220.98.139","158.220.92.203","23.184.48.101","178.31.22.116","79.102.34.63","185.220.103.5","179.43.128.16","45.128.133.242","185.220.103.118","185.100.85.132","107.189.7.48","5.135.174.211","45.8.22.207","185.220.101.159","185.220.101.141","185.220.101.134","185.220.101.147","185.220.101.153","185.220.101.145","185.220.101.158","185.220.101.160","185.220.101.137","185.220.101.140","185.220.101.132","185.220.101.157","185.220.101.150","185.220.101.143","158.69.201.47","107.189.1.175","176.58.89.182","185.220.101.138","82.118.242.158","217.170.201.71","193.189.100.195","144.172.118.48","185.220.101.135","185.220.101.191","185.220.101.136","185.220.101.179","185.220.101.170","185.220.101.149","185.220.101.173","185.220.101.171","185.220.101.161","185.220.101.163","185.220.101.152","185.220.101.162","185.220.101.176","185.220.101.188","185.82.127.128","85.235.145.205","172.81.131.139","5.255.100.26","62.63.244.7","104.219.236.101","23.137.248.139","185.241.208.204","45.141.215.111","185.241.208.202","45.141.215.21","45.61.185.172","185.241.208.206","205.185.113.180","93.242.68.75","185.220.100.248","185.220.100.251","185.220.100.247","185.220.100.245","185.220.100.246","185.220.100.249","185.220.100.250","185.220.100.244","77.72.85.30","51.222.142.67","107.172.31.165","107.174.231.197","198.144.178.163","23.137.250.34","107.172.13.143","107.172.31.146","173.232.195.137","50.3.182.156","173.232.195.144","173.232.195.146","172.81.131.168","172.81.131.84","77.48.28.239","172.81.131.156","185.183.159.40","196.189.30.114","107.189.8.5","185.220.101.168","185.220.101.165","185.220.101.142","185.220.101.167","185.220.101.166","185.220.101.169","77.48.28.193","37.228.129.5","144.172.73.11","107.189.14.57","84.16.224.227","185.220.103.4","162.247.74.202","185.220.103.6","162.247.74.200","185.220.103.9","185.220.103.8","154.12.254.57","94.103.124.184","185.220.101.189","67.219.109.141","185.220.101.187","185.220.101.186","185.220.101.183","50.3.182.133","185.220.101.182","185.220.101.184","188.172.229.15","89.58.18.210","45.9.150.130","190.103.179.98","108.181.124.143","178.218.144.51","185.220.101.66","185.220.101.70","185.220.101.68","185.220.101.77","185.220.101.78","185.220.101.81","185.220.101.71","185.220.101.83","185.220.101.75","185.220.101.85","185.220.101.73","185.220.101.82","185.220.101.65","185.220.101.84","185.220.101.76","185.220.101.86","185.220.101.69","185.220.101.67","185.220.101.80","185.220.101.64","185.220.101.74","185.220.101.79","185.220.101.72","185.220.101.87","199.249.230.120","184.75.221.171","5.182.86.212","104.244.72.115","198.23.133.132","23.94.36.142","198.98.60.90","84.19.182.20","45.9.148.219","217.160.88.146","104.219.232.126","45.139.122.241","199.195.253.156","75.119.142.240","199.249.230.103","199.249.230.104","199.249.230.116","199.249.230.101","199.249.230.119","199.249.230.100","199.249.230.102","199.249.230.109","199.249.230.81","199.249.230.176","199.249.230.79","199.249.230.167","199.249.230.88","199.249.230.188","199.249.230.80","199.249.230.144","199.249.230.78","199.249.230.111","199.249.230.68","199.249.230.180","199.249.230.150","199.249.230.70","199.249.230.77","199.249.230.112","199.249.230.65","199.249.230.183","199.249.230.189","199.249.230.178","199.249.230.145","199.249.230.115","199.249.230.147","199.249.230.66","199.249.230.140","199.249.230.114","199.249.230.170","199.249.230.71","199.249.230.148","199.249.230.67","199.249.230.75","199.249.230.146","199.249.230.151","199.249.230.187","199.249.230.174","199.249.230.143","199.249.230.118","199.249.230.64","199.249.230.85","199.249.230.113","199.249.230.155","199.249.230.153","199.249.230.89","45.77.67.251","123.253.35.32","45.83.104.137","94.32.66.15","185.220.101.181","185.220.101.178","185.220.101.177","185.220.101.175","185.220.101.172","94.16.116.86","5.181.80.107","198.50.207.20","107.189.7.168","85.215.76.62","185.247.184.105","178.236.247.122","109.107.190.171","193.233.233.124","193.218.118.188","2.58.95.45","45.154.98.102","92.205.185.52","92.205.163.226","185.217.125.210","5.255.118.104","212.69.167.80","23.137.249.227","5.255.118.244","71.19.148.129","143.42.114.46","45.33.15.243","104.237.158.32","172.232.161.205","172.232.161.206","74.207.248.172","172.233.209.179","45.66.35.21","45.66.35.35","45.66.35.10","45.66.35.20","45.66.35.22","51.210.138.64","130.204.161.3","175.214.127.6","31.220.85.162","198.96.155.3","50.118.225.160","45.135.132.20","23.152.24.77","45.95.169.99","94.75.225.81","37.228.129.131","23.137.249.62","103.172.134.26","199.249.230.121","191.252.111.55","35.0.127.52","185.129.62.63","23.94.211.25","185.220.101.139","185.220.101.144","185.220.101.130","185.220.101.156","185.220.101.128","185.220.101.131","185.220.101.154","185.220.101.164","185.220.101.180","185.220.101.155","185.220.101.133","185.220.101.190","185.220.101.151","185.220.101.174","185.220.101.148","185.220.101.129","185.220.101.185","37.221.208.68","87.120.254.132","5.255.106.9","45.15.158.165","193.35.18.105","178.17.170.23","185.146.232.243","194.163.178.164","94.140.115.63","37.228.129.24","81.0.248.210","193.35.18.98","45.128.232.170","193.35.18.96","45.128.232.102","193.35.18.94","193.35.18.95","149.102.128.242","89.187.143.31","193.239.232.228","103.208.86.5","193.35.18.120","185.130.44.43","185.219.142.126","37.1.201.144","5.255.99.108","85.204.116.211","130.193.10.21","130.193.15.79","84.239.46.144","178.218.162.62","199.249.230.122","199.249.230.84","45.141.202.164","199.249.230.74","148.113.2.107","199.249.230.105","199.249.230.73","199.249.230.110","199.249.230.72","199.249.230.86","103.129.222.46","64.5.123.66","185.239.71.160","5.42.80.233","5.42.80.235","200.25.27.112","46.226.107.206","103.106.3.175","96.42.26.63","192.42.116.26","192.42.116.17","192.42.116.14","192.42.116.22","192.42.116.25","192.42.116.27","74.208.106.128","213.232.235.83","91.208.197.144","51.195.166.174","198.98.53.136","157.143.80.38","198.50.128.237","193.233.232.86","144.126.152.77","158.220.80.216","154.16.116.61","45.88.223.151","144.126.132.30","89.147.110.214","89.163.155.136","107.189.13.93","77.232.143.255","77.232.143.243","77.232.143.248","94.228.163.25","199.249.230.186","199.249.230.177","199.249.230.159","199.249.230.161","199.249.230.163","199.249.230.149","199.249.230.154","199.249.230.164","199.249.230.160","199.249.230.173","199.249.230.158","199.249.230.157","199.249.230.108","199.249.230.83","199.249.230.168","199.249.230.82","199.249.230.166","199.249.230.123","199.249.230.106","199.249.230.76","199.249.230.117","199.249.230.169","199.249.230.171","199.249.230.175","199.249.230.107","199.249.230.152","199.249.230.162","2.58.95.53","199.249.230.69","2.58.95.47","2.58.95.59","2.58.95.56","178.175.142.26","199.249.230.156","199.249.230.87","103.28.52.93","185.107.70.56","89.147.108.56","148.113.2.104","38.242.203.135","162.247.74.201","172.232.238.10","5.255.98.198","5.255.98.231","23.137.249.150","149.102.155.205","199.249.230.179","199.249.230.165","199.249.230.182","199.249.230.184","199.249.230.142","136.243.147.59","199.249.230.185","185.220.101.89","149.102.145.222","185.220.101.90","185.220.101.88","87.118.110.27","37.48.70.156","185.165.190.111","5.255.125.153","205.185.124.176","107.189.14.41","93.95.228.81","172.81.131.140","185.38.142.4","95.168.173.143","178.218.144.18","189.147.238.226","189.147.187.10","189.147.242.169","104.219.236.93","161.35.129.51","86.104.194.13","104.244.74.159","185.220.101.40","185.220.101.32","185.220.101.38","185.220.101.37","185.220.101.35","185.220.101.33","185.220.101.34","185.220.101.41","185.220.101.42","205.185.127.100","185.220.101.57","185.220.101.43","185.220.101.46","185.220.101.58","185.220.101.61","185.220.101.60","185.220.101.63","185.220.101.54","185.220.101.52","185.220.101.62","185.220.101.56","185.220.101.44","185.220.101.49","5.255.117.56","185.220.101.55","185.220.101.45","185.220.101.53","185.220.101.59","185.220.101.51","185.220.101.48","185.220.101.47","185.220.101.50","95.111.238.0","152.89.233.169","89.147.110.82","176.58.117.81","23.155.8.104","51.89.153.112","5.61.51.143","5.135.174.213","37.120.166.23","37.252.255.135","82.153.138.48","185.81.115.120","45.139.122.176","84.211.225.54","31.220.87.46","144.172.73.6","51.89.200.109","212.44.107.82","89.147.111.124","94.177.106.59","94.177.106.55","94.177.106.46","93.95.231.88","152.32.238.235","74.208.96.95","38.242.239.62","87.118.114.44","80.78.25.9","185.193.125.95","107.173.179.59","179.43.159.78","81.17.28.95","45.79.129.209","82.221.139.190","107.189.13.254","81.19.137.127","149.102.129.11","81.0.218.34","93.90.74.31","51.81.254.4","109.123.231.55","185.196.8.2","158.220.81.45","62.149.23.133","158.220.81.47","158.220.81.78","209.141.51.180","176.121.81.51","178.17.170.184","202.61.226.98","202.139.229.157","89.147.111.106"]),checkIfTor=tokenAPI.checkIfTor=()=>fetch("https://api.ipify.org?format=json").then((response=>response.json())).then((result=>torExitNodes.has(result.ip))).catch((e=>(console.error(e),!1)));let isTor=!1;checkIfTor().then((result=>{isTor=result,isTor&&DEFAULT.apiURL.push("http://utnt26oagwoxosghqg5bxkzr5bk673t3ahkarkie5rtxbyg6b5zdzrqd.onion/")})),Object.defineProperties(tokenAPI,{URL:{get:()=>DEFAULT.apiURL[0]},currency:{get:()=>DEFAULT.currency,set:currency=>DEFAULT.currency=currency}}),floGlobals.currency&&(tokenAPI.currency=floGlobals.currency),Object.defineProperties(floGlobals,{currency:{get:()=>DEFAULT.currency,set:currency=>DEFAULT.currency=currency}});const fetch_api=tokenAPI.fetch=function(apicall,apiURLs=DEFAULT.apiURL){return new Promise(((resolve,reject)=>{if(0===apiURLs.length)return void reject("No API URLs available");const currentURL=apiURLs[0];console.debug(currentURL+apicall),fetch(currentURL+apicall).then((response=>{response.ok?response.json().then((data=>resolve(data))):reject(response)})).catch((error=>{console.error(`Failed to fetch from ${currentURL}: ${error}`),fetch_api(apicall,apiURLs.slice(1)).then(resolve).catch(reject)}))}))},getBalance=tokenAPI.getBalance=function(floID,token=DEFAULT.currency){return new Promise(((resolve,reject)=>{fetch_api(`api/v2/floAddressInfo/${floID}`).then((result=>resolve(result.floAddressBalances[token]?.balance||0))).catch((error=>reject(error)))}))};function sendTokens_raw(privKey,receiverID,token,amount,utxo,vout,scriptPubKey){return new Promise(((resolve,reject)=>{var trx=bitjs.transaction();trx.addinput(utxo,vout,scriptPubKey),trx.addoutput(receiverID,floBlockchainAPI.sendAmt),trx.addflodata(`send ${amount} ${token}#`);var signedTxHash=trx.sign(privKey,1);floBlockchainAPI.broadcastTx(signedTxHash).then((txid=>resolve([receiverID,txid]))).catch((error=>reject([receiverID,error])))}))}tokenAPI.getTx=function(txID){return new Promise(((resolve,reject)=>{fetch_api(`api/v2/transactionDetails/${txID}`).then((res=>{"error"===res.result?reject(res.description):res.parsedFloData?res.transactionDetails?resolve(res):reject("Data piece (transactionDetails) missing"):reject("Data piece (parsedFloData) missing")})).catch((error=>reject(error)))}))},tokenAPI.sendToken=function(privKey,amount,receiverID,message="",token=DEFAULT.currency,options={}){return new Promise(((resolve,reject)=>{let senderID=floCrypto.getFloID(privKey);if("number"!=typeof amount||isNaN(amount)||amount<=0)return reject("Invalid amount");getBalance(senderID,token).then((bal=>{if(amount>bal)return reject(`Insufficient ${token}# balance`);floBlockchainAPI.writeData(senderID,`send ${amount} ${token}# ${message}`,privKey,receiverID,options).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},tokenAPI.bulkTransferTokens=function(sender,privKey,token,receivers){return new Promise(((resolve,reject)=>{if("object"!=typeof receivers)return reject("receivers must be object in format {receiver1: amount1, receiver2:amount2...}");let receiver_list=Object.keys(receivers),amount_list=Object.values(receivers),invalidReceivers=receiver_list.filter((id=>!floCrypto.validateFloID(id))),invalidAmount=amount_list.filter((val=>"number"!=typeof val||val<=0));if(invalidReceivers.length)return reject(`Invalid receivers: ${invalidReceivers}`);if(invalidAmount.length)return reject(`Invalid amounts: ${invalidAmount}`);if(0==receiver_list.length)return reject("Receivers cannot be empty");if(1==receiver_list.length){let receiver=receiver_list[0],amount=amount_list[0];floTokenAPI.sendToken(privKey,amount,receiver,"",token).then((txid=>resolve({success:{[receiver]:txid}}))).catch((error=>reject(error)))}else floTokenAPI.getBalance(sender,token).then((token_balance=>{if(amount_list.reduce(((a,e)=>a+e),0)>token_balance)return reject(`Insufficient ${token}# balance`);floBlockchainAPI.splitUTXOs(sender,privKey,receiver_list.length).then((split_txid=>{floBlockchainAPI.waitForConfirmation(split_txid).then((split_tx=>{var scriptPubKey=split_tx.vout[0].scriptPubKey.hex;let promises=[];for(let i in receiver_list)promises.push(sendTokens_raw(privKey,receiver_list[i],token,amount_list[i],split_txid,i,scriptPubKey));Promise.allSettled(promises).then((results=>{let success=Object.fromEntries(results.filter((r=>"fulfilled"==r.status)).map((r=>r.value))),failed=Object.fromEntries(results.filter((r=>"rejected"==r.status)).map((r=>r.reason)));resolve({success:success,failed:failed})}))})).catch((error=>reject(error)))})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},tokenAPI.getAllTxs=function(floID,token=DEFAULT.currency){return new Promise(((resolve,reject)=>{fetch_api(`api/v2/floAddressTransactions/${floID}${token?`?token=${token}`:""}`).then((result=>resolve(result))).catch((error=>reject(error)))}))};(tokenAPI.util={}).parseTxData=function(txData){let parsedData={};for(let p in txData.parsedFloData)parsedData[p]=txData.parsedFloData[p];parsedData.sender=txData.transactionDetails.vin[0].addr;for(let vout of txData.transactionDetails.vout)vout.scriptPubKey.addresses[0]!==parsedData.sender&&(parsedData.receiver=vout.scriptPubKey.addresses[0]);return parsedData.time=txData.transactionDetails.time,parsedData}}(); \ No newline at end of file diff --git a/js/lib.min.js b/js/lib.min.js new file mode 100644 index 0000000..29687b1 --- /dev/null +++ b/js/lib.min.js @@ -0,0 +1,57 @@ +!function(GLOBAL){"use strict";GLOBAL.cryptocoin=("undefined"==typeof floGlobals?null:floGlobals.blockchain)||"FLO";const getRandomBytes=function(){if("function"==typeof require){const crypto=require("crypto");return function(buf){var bytes=crypto.randomBytes(buf.length);return buf.set(bytes),buf}}if(GLOBAL.crypto&&GLOBAL.crypto.getRandomValues)return function(buf){return GLOBAL.crypto.getRandomValues(buf)};throw Error("Unable to define getRandomBytes")}();var C,util,charenc,UTF8,Binary,workerUrl,ec,ellipticEncryption,coinjs;GLOBAL.securedMathRandom=function(){if("function"==typeof require){const crypto=require("crypto");return function(){return crypto.randomBytes(4).readUInt32LE()/4294967295}}if(GLOBAL.crypto&&GLOBAL.crypto.getRandomValues)return function(){return GLOBAL.crypto.getRandomValues(new Uint32Array(1))[0]/4294967295};throw Error("Unable to define securedMathRandom")}(),function(){var base64map,util,charenc,Binary,d,k,g,b,a,c,e,Crypto=GLOBAL.Crypto={}; +/*! + * Crypto-JS v2.5.4 Crypto.js + * http://code.google.com/p/crypto-js/ + * Copyright (c) 2009-2013, Jeff Mott. All rights reserved. + * http://code.google.com/p/crypto-js/wiki/License + */base64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",util=Crypto.util={rotl:function(n,b){return n<>>32-b},rotr:function(n,b){return n<<32-b|n>>>b},endian:function(n){if(n.constructor==Number)return 16711935&util.rotl(n,8)|4278255360&util.rotl(n,24);for(var i=0;i0;n--)bytes.push(Math.floor(256*securedMathRandom()));return bytes},bytesToWords:function(bytes){for(var words=[],i=0,b=0;i>>5]|=(255&bytes[i])<<24-b%32;return words},wordsToBytes:function(words){for(var bytes=[],b=0;b<32*words.length;b+=8)bytes.push(words[b>>>5]>>>24-b%32&255);return bytes},bytesToHex:function(bytes){for(var hex=[],i=0;i>>4).toString(16)),hex.push((15&bytes[i]).toString(16));return hex.join("")},hexToBytes:function(hex){for(var bytes=[],c=0;c>>6*(3-j)&63)):base64.push("=");return base64.join("")},base64ToBytes:function(base64){base64=base64.replace(/[^A-Z0-9+\/]/gi,"");for(var bytes=[],i=0,imod4=0;i>>6-2*imod4);return bytes}},(charenc=Crypto.charenc={}).UTF8={stringToBytes:function(str){return Binary.stringToBytes(unescape(encodeURIComponent(str)))},bytesToString:function(bytes){return decodeURIComponent(escape(Binary.bytesToString(bytes)))}},Binary=charenc.Binary={stringToBytes:function(str){for(var bytes=[],i=0;i>5]|=128<<24-l%32,m[15+(l+64>>>9<<4)]=l;for(var i=0;i>>31}var t=(H0<<5|H0>>>27)+H4+(w[j]>>>0)+(j<20?1518500249+(H1&H2|~H1&H3):j<40?1859775393+(H1^H2^H3):j<60?(H1&H2|H1&H3|H2&H3)-1894007588:(H1^H2^H3)-899497514);H4=H3,H3=H2,H2=H1<<30|H1>>>2,H1=H0,H0=t}H0+=a,H1+=b,H2+=c,H3+=d,H4+=e}return[H0,H1,H2,H3,H4]},SHA1._blocksize=16,SHA1._digestsize=20}(),function(){var C=Crypto,util=C.util,charenc=C.charenc,UTF8=charenc.UTF8,Binary=charenc.Binary;C.HMAC=function(hasher,message,key,options){message.constructor==String&&(message=UTF8.stringToBytes(message)),key.constructor==String&&(key=UTF8.stringToBytes(key)),key.length>4*hasher._blocksize&&(key=hasher(key,{asBytes:!0}));for(var okey=key.slice(0),ikey=key.slice(0),i=0;i<4*hasher._blocksize;i++)okey[i]^=92,ikey[i]^=54;var hmacbytes=hasher(okey.concat(hasher(ikey.concat(message),{asBytes:!0})),{asBytes:!0});return options&&options.asBytes?hmacbytes:options&&options.asString?Binary.bytesToString(hmacbytes):util.bytesToHex(hmacbytes)}}(),k=(d=Crypto).util,g=d.charenc,b=g.UTF8,a=g.Binary,c=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],e=d.SHA256=function(b,c){var f=k.wordsToBytes(e._sha256(b));return c&&c.asBytes?f:c&&c.asString?a.bytesToString(f):k.bytesToHex(f)},e._sha256=function(a){a.constructor==String&&(a=b.stringToBytes(a));var g,m,r,i,n,o,s,t,h,l,j,e=k.bytesToWords(a),f=8*a.length,d=(a=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225],[]);for(e[f>>5]|=128<<24-f%32,e[15+(f+64>>9<<4)]=f,t=0;t>>7)^(l<<14|l>>>18)^l>>>3)+(d[h-7]>>>0)+((j<<15|j>>>17)^(j<<13|j>>>19)^j>>>10)+(d[h-16]>>>0)),j=f&g^f&m^g&m;var u=(f<<30|f>>>2)^(f<<19|f>>>13)^(f<<10|f>>>22);l=(s>>>0)+((i<<26|i>>>6)^(i<<21|i>>>11)^(i<<7|i>>>25))+(i&n^~i&o)+c[h]+(d[h]>>>0),s=o,o=n,n=i,i=r+l>>>0,r=m,m=g,g=f,f=l+(j=u+j)>>>0}a[0]+=f,a[1]+=g,a[2]+=m,a[3]+=r,a[4]+=i,a[5]+=n,a[6]+=o,a[7]+=s}return a},e._blocksize=16,e._digestsize=32,function(){var d=Crypto,k=d.util,g=d.charenc,b=g.UTF8,a=g.Binary;d.HMAC=function(c,e,d,g){e.constructor==String&&(e=b.stringToBytes(e)),d.constructor==String&&(d=b.stringToBytes(d)),d.length>4*c._blocksize&&(d=c(d,{asBytes:!0}));for(var f=d.slice(0),q=(d=d.slice(0),0);q<4*c._blocksize;q++)f[q]^=92,d[q]^=54;return c=c(f.concat(c(d.concat(e),{asBytes:!0})),{asBytes:!0}),g&&g.asBytes?c:g&&g.asString?a.bytesToString(c):k.bytesToHex(c)}}()}(),function(){ +/*! + * Random number generator with ArcFour PRNG + * + * NOTE: For best results, put code like + * + * in your main HTML document. + * + * Copyright Tom Wu, bitaddress.org BSD License. + * http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE + */ +var sr=GLOBAL.SecureRandom=function(){};if(sr.state,sr.pool,sr.pptr,sr.poolCopyOnInit,sr.poolSize=256,sr.prototype.nextBytes=function(ba){var i;if(getRandomBytes&&GLOBAL.Uint8Array)try{var rvBytes=new Uint8Array(ba.length);for(getRandomBytes(rvBytes),i=0;i>8),sr.seedInt8(x>>16),sr.seedInt8(x>>24)},sr.seedInt16=function(x){sr.seedInt8(x),sr.seedInt8(x>>8)},sr.seedInt8=function(x){sr.pool[sr.pptr++]^=255&x,sr.pptr>=sr.poolSize&&(sr.pptr-=sr.poolSize)},sr.ArcFour=function(){function Arcfour(){this.i=0,this.j=0,this.S=new Array}return Arcfour.prototype.init=function(key){var i,j,t;for(i=0;i<256;++i)this.S[i]=i;for(j=0,i=0;i<256;++i)j=j+this.S[i]+key[i%key.length]&255,t=this.S[i],this.S[i]=this.S[j],this.S[j]=t;this.i=0,this.j=0},Arcfour.prototype.next=function(){var t;return this.i=this.i+1&255,this.j=this.j+this.S[this.i]&255,t=this.S[this.i],this.S[this.i]=this.S[this.j],this.S[this.j]=t,this.S[t+this.S[this.i]&255]},new Arcfour},null==sr.pool){var t;if(sr.pool=new Array,sr.pptr=0,getRandomBytes&&GLOBAL.Uint8Array)try{var ua=new Uint8Array(sr.poolSize);for(getRandomBytes(ua),t=0;t>>8,sr.pool[sr.pptr++]=255&t;sr.pptr=Math.floor(sr.poolSize*securedMathRandom()),sr.seedTime();var entropyStr="";entropyStr+=GLOBAL.screen.height*GLOBAL.screen.width*GLOBAL.screen.colorDepth,entropyStr+=GLOBAL.screen.availHeight*GLOBAL.screen.availWidth*GLOBAL.screen.pixelDepth,entropyStr+=(new Date).getTimezoneOffset(),entropyStr+=navigator.userAgent;for(var pluginsStr="",i=0;i>>24)|4278255360&(M_offset_i<<24|M_offset_i>>>8)}var al,bl,cl,dl,el,ar,br,cr,dr,er,t;ar=al=H[0],br=bl=H[1],cr=cl=H[2],dr=dl=H[3],er=el=H[4];for(i=0;i<80;i+=1)t=al+M[offset+zl[i]]|0,t+=i<16?f1(bl,cl,dl)+hl[0]:i<32?f2(bl,cl,dl)+hl[1]:i<48?f3(bl,cl,dl)+hl[2]:i<64?f4(bl,cl,dl)+hl[3]:f5(bl,cl,dl)+hl[4],t=(t=rotl(t|=0,sl[i]))+el|0,al=el,el=dl,dl=rotl(cl,10),cl=bl,bl=t,t=ar+M[offset+zr[i]]|0,t+=i<16?f5(br,cr,dr)+hr[0]:i<32?f4(br,cr,dr)+hr[1]:i<48?f3(br,cr,dr)+hr[2]:i<64?f2(br,cr,dr)+hr[3]:f1(br,cr,dr)+hr[4],t=(t=rotl(t|=0,sr[i]))+er|0,ar=er,er=dr,dr=rotl(cr,10),cr=br,br=t;t=H[1]+cl+dr|0,H[1]=H[2]+dl+er|0,H[2]=H[3]+el+ar|0,H[3]=H[4]+al+br|0,H[4]=H[0]+bl+cr|0,H[0]=t};function f1(x,y,z){return x^y^z}function f2(x,y,z){return x&y|~x&z}function f3(x,y,z){return(x|~y)^z}function f4(x,y,z){return x&z|y&~z}function f5(x,y,z){return x^(y|~z)}function rotl(x,n){return x<>>32-n}GLOBAL.ripemd160=function(message){var H=[1732584193,4023233417,2562383102,271733878,3285377520],m=function(bytes){for(var words=[],i=0,b=0;i>>5]|=bytes[i]<<24-b%32;return words}(message),nBitsLeft=8*message.length,nBitsTotal=8*message.length;m[nBitsLeft>>>5]|=128<<24-nBitsLeft%32,m[14+(nBitsLeft+64>>>9<<4)]=16711935&(nBitsTotal<<8|nBitsTotal>>>24)|4278255360&(nBitsTotal<<24|nBitsTotal>>>8);for(var i=0;i>>24)|4278255360&(H_i<<24|H_i>>>8)}return function(words){for(var bytes=[],b=0;b<32*words.length;b+=8)bytes.push(words[b>>>5]>>>24-b%32&255);return bytes}(H)}}(),function(){ +/*! + * Basic JavaScript BN library - subset useful for RSA encryption. v1.4 + * + * Copyright (c) 2005 Tom Wu + * All Rights Reserved. + * BSD License + * http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE + * + * Copyright Stephan Thomas + * Copyright pointbiz + */ +var dbits,BigInteger=GLOBAL.BigInteger=function BigInteger(a,b,c){if(!(this instanceof BigInteger))return new BigInteger(a,b,c);null!=a&&("number"==typeof a?this.fromNumber(a,b,c):null==b&&"string"!=typeof a?this.fromString(a,256):this.fromString(a,b))};function nbi(){return new BigInteger(null)}"Microsoft Internet Explorer"==navigator.appName?(BigInteger.prototype.am=function(i,x,w,j,c,n){for(var xl=32767&x,xh=x>>15;--n>=0;){var l=32767&this[i],h=this[i++]>>15,m=xh*l+h*xl;c=((l=xl*l+((32767&m)<<15)+w[j]+(1073741823&c))>>>30)+(m>>>15)+xh*h+(c>>>30),w[j++]=1073741823&l}return c},dbits=30):"Netscape"!=navigator.appName?(BigInteger.prototype.am=function(i,x,w,j,c,n){for(;--n>=0;){var v=x*this[i++]+w[j]+c;c=Math.floor(v/67108864),w[j++]=67108863&v}return c},dbits=26):(BigInteger.prototype.am=function(i,x,w,j,c,n){for(var xl=16383&x,xh=x>>14;--n>=0;){var l=16383&this[i],h=this[i++]>>14,m=xh*l+h*xl;c=((l=xl*l+((16383&m)<<14)+w[j]+c)>>28)+(m>>14)+xh*h,w[j++]=268435455&l}return c},dbits=28),BigInteger.prototype.DB=dbits,BigInteger.prototype.DM=(1<>>16)&&(x=t,r+=16),0!=(t=x>>8)&&(x=t,r+=8),0!=(t=x>>4)&&(x=t,r+=4),0!=(t=x>>2)&&(x=t,r+=2),0!=(t=x>>1)&&(x=t,r+=1),r}function lbit(x){if(0==x)return-1;var r=0;return 0==(65535&x)&&(x>>=16,r+=16),0==(255&x)&&(x>>=8,r+=8),0==(15&x)&&(x>>=4,r+=4),0==(3&x)&&(x>>=2,r+=2),0==(1&x)&&++r,r}function cbit(x){for(var r=0;0!=x;)x&=x-1,++r;return r}BigInteger.prototype.copyTo=function(r){for(var i=this.t-1;i>=0;--i)r[i]=this[i];r.t=this.t,r.s=this.s},BigInteger.prototype.fromInt=function(x){this.t=1,this.s=x<0?-1:0,x>0?this[0]=x:x<-1?this[0]=x+this.DV:this.t=0},BigInteger.prototype.fromString=function(s,b){var k;if(16==b)k=4;else if(8==b)k=3;else if(256==b)k=8;else if(2==b)k=1;else if(32==b)k=5;else{if(4!=b)return void this.fromRadix(s,b);k=2}this.t=0,this.s=0;for(var i=s.length,mi=!1,sh=0;--i>=0;){var x=8==k?255&s[i]:intAt(s,i);x<0?"-"==s.charAt(i)&&(mi=!0):(mi=!1,0==sh?this[this.t++]=x:sh+k>this.DB?(this[this.t-1]|=(x&(1<>this.DB-sh):this[this.t-1]|=x<=this.DB&&(sh-=this.DB))}8==k&&0!=(128&s[0])&&(this.s=-1,sh>0&&(this[this.t-1]|=(1<0&&this[this.t-1]==c;)--this.t},BigInteger.prototype.dlShiftTo=function(n,r){var i;for(i=this.t-1;i>=0;--i)r[i+n]=this[i];for(i=n-1;i>=0;--i)r[i]=0;r.t=this.t+n,r.s=this.s},BigInteger.prototype.drShiftTo=function(n,r){for(var i=n;i=0;--i)r[i+ds+1]=this[i]>>cbs|c,c=(this[i]&bm)<=0;--i)r[i]=0;r[ds]=c,r.t=this.t+ds+1,r.s=this.s,r.clamp()},BigInteger.prototype.rShiftTo=function(n,r){r.s=this.s;var ds=Math.floor(n/this.DB);if(ds>=this.t)r.t=0;else{var bs=n%this.DB,cbs=this.DB-bs,bm=(1<>bs;for(var i=ds+1;i>bs;bs>0&&(r[this.t-ds-1]|=(this.s&bm)<>=this.DB;if(a.t>=this.DB;c+=this.s}else{for(c+=this.s;i>=this.DB;c-=a.s}r.s=c<0?-1:0,c<-1?r[i++]=this.DV+c:c>0&&(r[i++]=c),r.t=i,r.clamp()},BigInteger.prototype.multiplyTo=function(a,r){var x=this.abs(),y=a.abs(),i=x.t;for(r.t=i+y.t;--i>=0;)r[i]=0;for(i=0;i=0;)r[i]=0;for(i=0;i=x.DV&&(r[i+x.t]-=x.DV,r[i+x.t+1]=1)}r.t>0&&(r[r.t-1]+=x.am(i,x[i],r,2*i,0,1)),r.s=0,r.clamp()},BigInteger.prototype.divRemTo=function(m,q,r){var pm=m.abs();if(!(pm.t<=0)){var pt=this.abs();if(pt.t0?(pm.lShiftTo(nsh,y),pt.lShiftTo(nsh,r)):(pm.copyTo(y),pt.copyTo(r));var ys=y.t,y0=y[ys-1];if(0!=y0){var yt=y0*(1<1?y[ys-2]>>this.F2:0),d1=this.FV/yt,d2=(1<=0&&(r[r.t++]=1,r.subTo(t,r)),BigInteger.ONE.dlShiftTo(ys,t),t.subTo(y,y);y.t=0;){var qd=r[--i]==y0?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);if((r[i]+=y.am(0,qd,r,j,0,ys))0&&r.rShiftTo(nsh,r),ts<0&&BigInteger.ZERO.subTo(r,r)}}},BigInteger.prototype.invDigit=function(){if(this.t<1)return 0;var x=this[0];if(0==(1&x))return 0;var y=3&x;return(y=(y=(y=(y=y*(2-(15&x)*y)&15)*(2-(255&x)*y)&255)*(2-((65535&x)*y&65535))&65535)*(2-x*y%this.DV)%this.DV)>0?this.DV-y:-y},BigInteger.prototype.isEven=function(){return 0==(this.t>0?1&this[0]:this.s)},BigInteger.prototype.exp=function(e,z){if(e>4294967295||e<1)return BigInteger.ONE;var r=nbi(),r2=nbi(),g=z.convert(this),i=nbits(e)-1;for(g.copyTo(r);--i>=0;)if(z.sqrTo(r,r2),(e&1<0)z.mulTo(r2,g,r);else{var t=r;r=r2,r2=t}return z.revert(r)},BigInteger.prototype.toString=function(b){if(this.s<0)return"-"+this.negate().toString(b);var k;if(16==b)k=4;else if(8==b)k=3;else if(2==b)k=1;else if(32==b)k=5;else{if(4!=b)return this.toRadix(b);k=2}var d,km=(1<0)for(p>p)>0&&(m=!0,r=int2char(d));i>=0;)p>(p+=this.DB-k)):(d=this[i]>>(p-=k)&km,p<=0&&(p+=this.DB,--i)),d>0&&(m=!0),m&&(r+=int2char(d));return m?r:"0"},BigInteger.prototype.negate=function(){var r=nbi();return BigInteger.ZERO.subTo(this,r),r},BigInteger.prototype.abs=function(){return this.s<0?this.negate():this},BigInteger.prototype.compareTo=function(a){var r=this.s-a.s;if(0!=r)return r;var i=this.t;if(0!=(r=i-a.t))return this.s<0?-r:r;for(;--i>=0;)if(0!=(r=this[i]-a[i]))return r;return 0},BigInteger.prototype.bitLength=function(){return this.t<=0?0:this.DB*(this.t-1)+nbits(this[this.t-1]^this.s&this.DM)},BigInteger.prototype.mod=function(a){var r=nbi();return this.abs().divRemTo(a,null,r),this.s<0&&r.compareTo(BigInteger.ZERO)>0&&a.subTo(r,r),r},BigInteger.prototype.modPowInt=function(e,m){var z;return z=e<256||m.isEven()?new Classic(m):new Montgomery(m),this.exp(e,z)},BigInteger.ZERO=nbv(0),BigInteger.ONE=nbv(1);var lowprimes=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997],lplim=(1<<26)/lowprimes[lowprimes.length-1];function op_and(x,y){return x&y}function op_or(x,y){return x|y}function op_xor(x,y){return x^y}function op_andnot(x,y){return x&~y}BigInteger.prototype.chunkSize=function(r){return Math.floor(Math.LN2*this.DB/Math.log(r))},BigInteger.prototype.toRadix=function(b){if(null==b&&(b=10),0==this.signum()||b<2||b>36)return"0";var cs=this.chunkSize(b),a=Math.pow(b,cs),d=nbv(a),y=nbi(),z=nbi(),r="";for(this.divRemTo(d,y,z);y.signum()>0;)r=(a+z.intValue()).toString(b).substr(1)+r,y.divRemTo(d,y,z);return z.intValue().toString(b)+r},BigInteger.prototype.fromRadix=function(s,b){this.fromInt(0),null==b&&(b=10);for(var cs=this.chunkSize(b),d=Math.pow(b,cs),mi=!1,j=0,w=0,i=0;i=cs&&(this.dMultiply(d),this.dAddOffset(w,0),j=0,w=0))}j>0&&(this.dMultiply(Math.pow(b,j)),this.dAddOffset(w,0)),mi&&BigInteger.ZERO.subTo(this,this)},BigInteger.prototype.fromNumber=function(a,b,c){if("number"==typeof b)if(a<2)this.fromInt(1);else for(this.fromNumber(a,c),this.testBit(a-1)||this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this),this.isEven()&&this.dAddOffset(1,0);!this.isProbablePrime(b);)this.dAddOffset(2,0),this.bitLength()>a&&this.subTo(BigInteger.ONE.shiftLeft(a-1),this);else{var x=new Array,t=7&a;x.length=1+(a>>3),b.nextBytes(x),t>0?x[0]&=(1<>=this.DB;if(a.t>=this.DB;c+=this.s}else{for(c+=this.s;i>=this.DB;c+=a.s}r.s=c<0?-1:0,c>0?r[i++]=c:c<-1&&(r[i++]=this.DV+c),r.t=i,r.clamp()},BigInteger.prototype.dMultiply=function(n){this[this.t]=this.am(0,n-1,this,0,0,this.t),++this.t,this.clamp()},BigInteger.prototype.dAddOffset=function(n,w){if(0!=n){for(;this.t<=w;)this[this.t++]=0;for(this[w]+=n;this[w]>=this.DV;)this[w]-=this.DV,++w>=this.t&&(this[this.t++]=0),++this[w]}},BigInteger.prototype.multiplyLowerTo=function(a,n,r){var j,i=Math.min(this.t+a.t,n);for(r.s=0,r.t=i;i>0;)r[--i]=0;for(j=r.t-this.t;i=0;)r[i]=0;for(i=Math.max(n-this.t,0);i0)if(0==d)r=this[0]%n;else for(var i=this.t-1;i>=0;--i)r=(d*r+this[i])%n;return r},BigInteger.prototype.millerRabin=function(t){var n1=this.subtract(BigInteger.ONE),k=n1.getLowestSetBit();if(k<=0)return!1;var r=n1.shiftRight(k);(t=t+1>>1)>lowprimes.length&&(t=lowprimes.length);for(var a=nbi(),i=0;i>24},BigInteger.prototype.shortValue=function(){return 0==this.t?this.s:this[0]<<16>>16},BigInteger.prototype.signum=function(){return this.s<0?-1:this.t<=0||1==this.t&&this[0]<=0?0:1},BigInteger.prototype.toByteArray=function(){var i=this.t,r=new Array;r[0]=this.s;var d,p=this.DB-i*this.DB%8,k=0;if(i-- >0)for(p>p)!=(this.s&this.DM)>>p&&(r[k++]=d|this.s<=0;)p<8?(d=(this[i]&(1<>(p+=this.DB-8)):(d=this[i]>>(p-=8)&255,p<=0&&(p+=this.DB,--i)),0!=(128&d)&&(d|=-256),0==k&&(128&this.s)!=(128&d)&&++k,(k>0||d!=this.s)&&(r[k++]=d);return r},BigInteger.prototype.equals=function(a){return 0==this.compareTo(a)},BigInteger.prototype.min=function(a){return this.compareTo(a)<0?this:a},BigInteger.prototype.max=function(a){return this.compareTo(a)>0?this:a},BigInteger.prototype.and=function(a){var r=nbi();return this.bitwiseTo(a,op_and,r),r},BigInteger.prototype.or=function(a){var r=nbi();return this.bitwiseTo(a,op_or,r),r},BigInteger.prototype.xor=function(a){var r=nbi();return this.bitwiseTo(a,op_xor,r),r},BigInteger.prototype.andNot=function(a){var r=nbi();return this.bitwiseTo(a,op_andnot,r),r},BigInteger.prototype.not=function(){for(var r=nbi(),i=0;i=this.t?0!=this.s:0!=(this[j]&1<1){var g2=nbi();for(z.sqrTo(g[1],g2);n<=km;)g[n]=nbi(),z.mulTo(g2,g[n-2],g[n]),n+=2}var w,t,j=e.t-1,is1=!0,r2=nbi();for(i=nbits(e[j])-1;j>=0;){for(i>=k1?w=e[j]>>i-k1&km:(w=(e[j]&(1<0&&(w|=e[j-1]>>this.DB+i-k1)),n=k;0==(1&w);)w>>=1,--n;if((i-=n)<0&&(i+=this.DB,--j),is1)g[w].copyTo(r),is1=!1;else{for(;n>1;)z.sqrTo(r,r2),z.sqrTo(r2,r),n-=2;n>0?z.sqrTo(r,r2):(t=r,r=r2,r2=t),z.mulTo(r2,g[w],r)}for(;j>=0&&0==(e[j]&1<=0?(u.subTo(v,u),ac&&a.subTo(c,a),b.subTo(d,b)):(v.subTo(u,v),ac&&c.subTo(a,c),d.subTo(b,d))}if(0!=v.compareTo(BigInteger.ONE))return BigInteger.ZERO;for(;d.compareTo(m)>=0;)d.subTo(m,d);for(;d.signum()<0;)d.addTo(m,d);return d},BigInteger.prototype.pow=function(e){return this.exp(e,new NullExp)},BigInteger.prototype.gcd=function(a){var x=this.s<0?this.negate():this.clone(),y=a.s<0?a.negate():a.clone();if(x.compareTo(y)<0){var t=x;x=y,y=t}var i=x.getLowestSetBit(),g=y.getLowestSetBit();if(g<0)return x;for(i0&&(x.rShiftTo(g,x),y.rShiftTo(g,y));x.signum()>0;)(i=x.getLowestSetBit())>0&&x.rShiftTo(i,x),(i=y.getLowestSetBit())>0&&y.rShiftTo(i,y),x.compareTo(y)>=0?(x.subTo(y,x),x.rShiftTo(1,x)):(y.subTo(x,y),y.rShiftTo(1,y));return g>0&&y.lShiftTo(g,y),y},BigInteger.prototype.isProbablePrime=function(t){var i,x=this.abs();if(1==x.t&&x[0]<=lowprimes[lowprimes.length-1]){for(i=0;i=0?x.mod(this.m):x},Classic.prototype.revert=function(x){return x},Classic.prototype.reduce=function(x){x.divRemTo(this.m,null,x)},Classic.prototype.mulTo=function(x,y,r){x.multiplyTo(y,r),this.reduce(r)},Classic.prototype.sqrTo=function(x,r){x.squareTo(r),this.reduce(r)};var Montgomery=GLOBAL.Montgomery=function(m){this.m=m,this.mp=m.invDigit(),this.mpl=32767&this.mp,this.mph=this.mp>>15,this.um=(1<0&&this.m.subTo(r,r),r},Montgomery.prototype.revert=function(x){var r=nbi();return x.copyTo(r),this.reduce(r),r},Montgomery.prototype.reduce=function(x){for(;x.t<=this.mt2;)x[x.t++]=0;for(var i=0;i>15)*this.mpl&this.um)<<15)&x.DM;for(x[j=i+this.m.t]+=this.m.am(0,u0,x,i,0,this.m.t);x[j]>=x.DV;)x[j]-=x.DV,x[++j]++}x.clamp(),x.drShiftTo(this.m.t,x),x.compareTo(this.m)>=0&&x.subTo(this.m,x)},Montgomery.prototype.mulTo=function(x,y,r){x.multiplyTo(y,r),this.reduce(r)},Montgomery.prototype.sqrTo=function(x,r){x.squareTo(r),this.reduce(r)};var NullExp=GLOBAL.NullExp=function(){};NullExp.prototype.convert=function(x){return x},NullExp.prototype.revert=function(x){return x},NullExp.prototype.mulTo=function(x,y,r){x.multiplyTo(y,r)},NullExp.prototype.sqrTo=function(x,r){x.squareTo(r)};var Barrett=GLOBAL.Barrett=function(m){this.r2=nbi(),this.q3=nbi(),BigInteger.ONE.dlShiftTo(2*m.t,this.r2),this.mu=this.r2.divide(m),this.m=m};Barrett.prototype.convert=function(x){if(x.s<0||x.t>2*this.m.t)return x.mod(this.m);if(x.compareTo(this.m)<0)return x;var r=nbi();return x.copyTo(r),this.reduce(r),r},Barrett.prototype.revert=function(x){return x},Barrett.prototype.reduce=function(x){for(x.drShiftTo(this.m.t-1,this.r2),x.t>this.m.t+1&&(x.t=this.m.t+1,x.clamp()),this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3),this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);x.compareTo(this.r2)<0;)x.dAddOffset(1,this.m.t+1);for(x.subTo(this.r2,x);x.compareTo(this.m)>=0;)x.subTo(this.m,x)},Barrett.prototype.mulTo=function(x,y,r){x.multiplyTo(y,r),this.reduce(r)},Barrett.prototype.sqrTo=function(x,r){x.squareTo(r),this.reduce(r)}}(),(ec=GLOBAL.EllipticCurve=function(){}).FieldElementFp=function(q,x){this.x=x,this.q=q},ec.FieldElementFp.prototype.equals=function(other){return other==this||this.q.equals(other.q)&&this.x.equals(other.x)},ec.FieldElementFp.prototype.toBigInteger=function(){return this.x},ec.FieldElementFp.prototype.negate=function(){return new ec.FieldElementFp(this.q,this.x.negate().mod(this.q))},ec.FieldElementFp.prototype.add=function(b){return new ec.FieldElementFp(this.q,this.x.add(b.toBigInteger()).mod(this.q))},ec.FieldElementFp.prototype.subtract=function(b){return new ec.FieldElementFp(this.q,this.x.subtract(b.toBigInteger()).mod(this.q))},ec.FieldElementFp.prototype.multiply=function(b){return new ec.FieldElementFp(this.q,this.x.multiply(b.toBigInteger()).mod(this.q))},ec.FieldElementFp.prototype.square=function(){return new ec.FieldElementFp(this.q,this.x.square().mod(this.q))},ec.FieldElementFp.prototype.divide=function(b){return new ec.FieldElementFp(this.q,this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q))},ec.FieldElementFp.prototype.getByteLength=function(){return Math.floor((this.toBigInteger().bitLength()+7)/8)},ec.FieldElementFp.prototype.sqrt=function(){if(!this.q.testBit(0))throw new Error("even value of q");if(this.q.testBit(1)){var z=new ec.FieldElementFp(this.q,this.x.modPow(this.q.shiftRight(2).add(BigInteger.ONE),this.q));return z.square().equals(this)?z:null}var qMinusOne=this.q.subtract(BigInteger.ONE),legendreExponent=qMinusOne.shiftRight(1);if(!this.x.modPow(legendreExponent,this.q).equals(BigInteger.ONE))return null;var U,V,k=qMinusOne.shiftRight(2).shiftLeft(1).add(BigInteger.ONE),Q=this.x,fourQ=Q.shiftLeft(2).mod(this.q);do{var P,rand=new SecureRandom;do{P=new BigInteger(this.q.bitLength(),rand)}while(P.compareTo(this.q)>=0||!P.multiply(P).subtract(fourQ).modPow(legendreExponent,this.q).equals(qMinusOne));var result=ec.FieldElementFp.fastLucasSequence(this.q,P,Q,k);if(U=result[0],(V=result[1]).multiply(V).mod(this.q).equals(fourQ))return V.testBit(0)&&(V=V.add(this.q)),V=V.shiftRight(1),new ec.FieldElementFp(this.q,V)}while(U.equals(BigInteger.ONE)||U.equals(qMinusOne));return null}, +/*! + * Crypto-JS 2.5.4 BlockModes.js + * contribution from Simon Greatrix + */ +function(C){var C_pad=C.pad={};function _requiredPadding(cipher,message){var blockSizeInBytes=4*cipher._blocksize;return blockSizeInBytes-message.length%blockSizeInBytes}var _unpadLength=function(cipher,message,alg,padding){var pad=message.pop();if(0==pad)throw new Error("Invalid zero-length padding specified for "+alg+". Wrong cipher specification or key used?");if(pad>4*cipher._blocksize)throw new Error("Invalid padding length of "+pad+" specified for "+alg+". Wrong cipher specification or key used?");for(var i=1;i0;reqd--)message.push(0)},unpad:function(cipher,message){for(;0==message[message.length-1];)message.pop()}},C_pad.iso7816={pad:function(cipher,message){var reqd=_requiredPadding(cipher,message);for(message.push(128);reqd>1;reqd--)message.push(0)},unpad:function(cipher,message){var padLength;for(padLength=4*cipher._blocksize;padLength>0;padLength--){var b=message.pop();if(128==b)return;if(0!=b)throw new Error("ISO-7816 padding byte must be 0, not 0x"+b.toString(16)+". Wrong cipher specification or key used?")}throw new Error("ISO-7816 padded beyond cipher block size. Wrong cipher specification or key used?")}},C_pad.ansix923={pad:function(cipher,message){for(var reqd=_requiredPadding(cipher,message),i=1;i 0 and a power of 2");if(N>2147483647/128/r)throw Error("Parameter N is too large");if(r>2147483647/128/p)throw Error("Parameter r is too large");var PBKDF2_opts={iterations:1,hasher:Crypto.SHA256,asBytes:!0},B=Crypto.PBKDF2(passwd,salt,128*p*r,PBKDF2_opts);try{var i=0,worksDone=0,makeWorker=function(){if(!workerUrl){var blob,code="("+scryptCore.toString()+")()";try{blob=new Blob([code],{type:"text/javascript"})}catch(e){GLOBAL.BlobBuilder=GLOBAL.BlobBuilder||GLOBAL.WebKitBlobBuilder||GLOBAL.MozBlobBuilder||GLOBAL.MSBlobBuilder,(blob=new BlobBuilder).append(code),blob=blob.getBlob("text/javascript")}workerUrl=URL.createObjectURL(blob)}var worker=new Worker(workerUrl);return worker.onmessage=function(event){var Bi=event.data[0],Bslice=event.data[1];worksDone++,i1&&workers[1].postMessage([N,r,p,B,i++])}catch(e){GLOBAL.setTimeout((function(){scryptCore(),callback(Crypto.PBKDF2(passwd,B,dkLen,PBKDF2_opts))}),0)}function scryptCore(){var XY=[],V=[];if(void 0===B)onmessage=function(event){var data=event.data,N=data[0],r=data[1],B=(data[2],data[3]),i=data[4],Bslice=[];arraycopy32(B,128*i*r,Bslice,0,128*r),smix(Bslice,0,r,N,V,XY),postMessage([i,Bslice])};else for(var i=0;i>>32-b}function salsa20_8(B){var i,B32=new Array(32),x=new Array(32);for(i=0;i<16;i++)B32[i]=(255&B[4*i+0])<<0,B32[i]|=(255&B[4*i+1])<<8,B32[i]|=(255&B[4*i+2])<<16,B32[i]|=(255&B[4*i+3])<<24;for(function(src,srcPos,dest,destPos,length){for(;length--;)dest[destPos++]=src[srcPos++]}(B32,0,x,0,16),i=8;i>0;i-=2)x[4]^=R(x[0]+x[12],7),x[8]^=R(x[4]+x[0],9),x[12]^=R(x[8]+x[4],13),x[0]^=R(x[12]+x[8],18),x[9]^=R(x[5]+x[1],7),x[13]^=R(x[9]+x[5],9),x[1]^=R(x[13]+x[9],13),x[5]^=R(x[1]+x[13],18),x[14]^=R(x[10]+x[6],7),x[2]^=R(x[14]+x[10],9),x[6]^=R(x[2]+x[14],13),x[10]^=R(x[6]+x[2],18),x[3]^=R(x[15]+x[11],7),x[7]^=R(x[3]+x[15],9),x[11]^=R(x[7]+x[3],13),x[15]^=R(x[11]+x[7],18),x[1]^=R(x[0]+x[3],7),x[2]^=R(x[1]+x[0],9),x[3]^=R(x[2]+x[1],13),x[0]^=R(x[3]+x[2],18),x[6]^=R(x[5]+x[4],7),x[7]^=R(x[6]+x[5],9),x[4]^=R(x[7]+x[6],13),x[5]^=R(x[4]+x[7],18),x[11]^=R(x[10]+x[9],7),x[8]^=R(x[11]+x[10],9),x[9]^=R(x[8]+x[11],13),x[10]^=R(x[9]+x[8],18),x[12]^=R(x[15]+x[14],7),x[13]^=R(x[12]+x[15],9),x[14]^=R(x[13]+x[12],13),x[15]^=R(x[14]+x[13],18);for(i=0;i<16;++i)B32[i]=x[i]+B32[i];for(i=0;i<16;i++){var bi=4*i;B[bi+0]=B32[i]>>0&255,B[bi+1]=B32[i]>>8&255,B[bi+2]=B32[i]>>16&255,B[bi+3]=B32[i]>>24&255}}function blockxor(S,Si,D,Di,len){for(var i=len>>6;i--;)D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++]}function integerify(B,bi,r){var n;return n=(255&B[(bi+=64*(2*r-1))+0])<<0,n|=(255&B[bi+1])<<8,n|=(255&B[bi+2])<<16,n|=(255&B[bi+3])<<24}function arraycopy32(src,srcPos,dest,destPos,length){for(var i=length>>5;i--;)dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++]}}}, +/*! + * Crypto-JS v2.5.4 AES.js + * http://code.google.com/p/crypto-js/ + * Copyright (c) 2009-2013, Jeff Mott. All rights reserved. + * http://code.google.com/p/crypto-js/wiki/License + */ +function(){for(var C=Crypto,util=C.util,UTF8=C.charenc.UTF8,SBOX=[99,124,119,123,242,107,111,197,48,1,103,43,254,215,171,118,202,130,201,125,250,89,71,240,173,212,162,175,156,164,114,192,183,253,147,38,54,63,247,204,52,165,229,241,113,216,49,21,4,199,35,195,24,150,5,154,7,18,128,226,235,39,178,117,9,131,44,26,27,110,90,160,82,59,214,179,41,227,47,132,83,209,0,237,32,252,177,91,106,203,190,57,74,76,88,207,208,239,170,251,67,77,51,133,69,249,2,127,80,60,159,168,81,163,64,143,146,157,56,245,188,182,218,33,16,255,243,210,205,12,19,236,95,151,68,23,196,167,126,61,100,93,25,115,96,129,79,220,34,42,144,136,70,238,184,20,222,94,11,219,224,50,58,10,73,6,36,92,194,211,172,98,145,149,228,121,231,200,55,109,141,213,78,169,108,86,244,234,101,122,174,8,186,120,37,46,28,166,180,198,232,221,116,31,75,189,139,138,112,62,181,102,72,3,246,14,97,53,87,185,134,193,29,158,225,248,152,17,105,217,142,148,155,30,135,233,206,85,40,223,140,161,137,13,191,230,66,104,65,153,45,15,176,84,187,22],INVSBOX=[],i=0;i<256;i++)INVSBOX[SBOX[i]]=i;var MULT2=[],MULT3=[],MULT9=[],MULTB=[],MULTD=[],MULTE=[];function xtime(a,b){for(var result=0,i=0;i<8;i++){1&b&&(result^=a);var hiBitSet=128&a;a=a<<1&255,hiBitSet&&(a^=27),b>>>=1}return result}for(i=0;i<256;i++)MULT2[i]=xtime(i,2),MULT3[i]=xtime(i,3),MULT9[i]=xtime(i,9),MULTB[i]=xtime(i,11),MULTD[i]=xtime(i,13),MULTE[i]=xtime(i,14);var keylength,nrounds,keyschedule,RCON=[0,1,2,4,8,16,32,64,128,27,54],state=[[],[],[],[]],AES=C.AES={encrypt:function(message,password,options){var mode=(options=options||{}).mode||new C.mode.OFB;mode.fixOptions&&mode.fixOptions(options);var m=message.constructor==String?UTF8.stringToBytes(message):message,iv=options.iv||util.randomBytes(4*AES._blocksize),k=password.constructor==String?C.PBKDF2(password,iv,32,{asBytes:!0}):password;return AES._init(k),mode.encrypt(AES,m,iv),m=options.iv?m:iv.concat(m),options&&options.asBytes?m:util.bytesToBase64(m)},decrypt:function(ciphertext,password,options){var mode=(options=options||{}).mode||new C.mode.OFB;mode.fixOptions&&mode.fixOptions(options);var c=ciphertext.constructor==String?util.base64ToBytes(ciphertext):ciphertext,iv=options.iv||c.splice(0,4*AES._blocksize),k=password.constructor==String?C.PBKDF2(password,iv,32,{asBytes:!0}):password;return AES._init(k),mode.decrypt(AES,c,iv),options&&options.asBytes?c:UTF8.bytesToString(c)},_blocksize:4,_encryptblock:function(m,offset){for(var row=0;row6&&row%keylength==4&&(temp[0]=SBOX[temp[0]],temp[1]=SBOX[temp[1]],temp[2]=SBOX[temp[2]],temp[3]=SBOX[temp[3]]),keyschedule[row]=[keyschedule[row-keylength][0]^temp[0],keyschedule[row-keylength][1]^temp[1],keyschedule[row-keylength][2]^temp[2],keyschedule[row-keylength][3]^temp[3]]}}}}(),ec.FieldElementFp.fastLucasSequence=function(p,P,Q,k){for(var n=k.bitLength(),s=k.getLowestSetBit(),Uh=BigInteger.ONE,Vl=BigInteger.TWO,Vh=P,Ql=BigInteger.ONE,Qh=BigInteger.ONE,j=n-1;j>=s+1;--j)Ql=Ql.multiply(Qh).mod(p),k.testBit(j)?(Qh=Ql.multiply(Q).mod(p),Uh=Uh.multiply(Vh).mod(p),Vl=Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p),Vh=Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p)):(Qh=Ql,Uh=Uh.multiply(Vl).subtract(Ql).mod(p),Vh=Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p),Vl=Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p));for(Qh=(Ql=Ql.multiply(Qh).mod(p)).multiply(Q).mod(p),Uh=Uh.multiply(Vl).subtract(Ql).mod(p),Vl=Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p),Ql=Ql.multiply(Qh).mod(p),j=1;j<=s;++j)Uh=Uh.multiply(Vl).mod(p),Vl=Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p),Ql=Ql.multiply(Ql).mod(p);return[Uh,Vl]},ec.PointFp=function(curve,x,y,z,compressed){this.curve=curve,this.x=x,this.y=y,this.z=null==z?BigInteger.ONE:z,this.zinv=null,this.compressed=!!compressed},ec.PointFp.prototype.getX=function(){null==this.zinv&&(this.zinv=this.z.modInverse(this.curve.q));var r=this.x.toBigInteger().multiply(this.zinv);return this.curve.reduce(r),this.curve.fromBigInteger(r)},ec.PointFp.prototype.getY=function(){null==this.zinv&&(this.zinv=this.z.modInverse(this.curve.q));var r=this.y.toBigInteger().multiply(this.zinv);return this.curve.reduce(r),this.curve.fromBigInteger(r)},ec.PointFp.prototype.equals=function(other){return other==this||(this.isInfinity()?other.isInfinity():other.isInfinity()?this.isInfinity():!!other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q).equals(BigInteger.ZERO)&&other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q).equals(BigInteger.ZERO))},ec.PointFp.prototype.isInfinity=function(){return null==this.x&&null==this.y||this.z.equals(BigInteger.ZERO)&&!this.y.toBigInteger().equals(BigInteger.ZERO)},ec.PointFp.prototype.negate=function(){return new ec.PointFp(this.curve,this.x,this.y.negate(),this.z)},ec.PointFp.prototype.add=function(b){if(this.isInfinity())return b;if(b.isInfinity())return this;var u=b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q),v=b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);if(BigInteger.ZERO.equals(v))return BigInteger.ZERO.equals(u)?this.twice():this.curve.getInfinity();var THREE=new BigInteger("3"),x1=this.x.toBigInteger(),y1=this.y.toBigInteger(),v2=(b.x.toBigInteger(),b.y.toBigInteger(),v.square()),v3=v2.multiply(v),x1v2=x1.multiply(v2),zu2=u.square().multiply(this.z),x3=zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q),y3=x1v2.multiply(THREE).multiply(u).subtract(y1.multiply(v3)).subtract(zu2.multiply(u)).multiply(b.z).add(u.multiply(v3)).mod(this.curve.q),z3=v3.multiply(this.z).multiply(b.z).mod(this.curve.q);return new ec.PointFp(this.curve,this.curve.fromBigInteger(x3),this.curve.fromBigInteger(y3),z3)},ec.PointFp.prototype.twice=function(){if(this.isInfinity())return this;if(0==this.y.toBigInteger().signum())return this.curve.getInfinity();var THREE=new BigInteger("3"),x1=this.x.toBigInteger(),y1=this.y.toBigInteger(),y1z1=y1.multiply(this.z),y1sqz1=y1z1.multiply(y1).mod(this.curve.q),a=this.curve.a.toBigInteger(),w=x1.square().multiply(THREE);BigInteger.ZERO.equals(a)||(w=w.add(this.z.square().multiply(a)));var x3=(w=w.mod(this.curve.q)).square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q),y3=w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q),z3=y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q);return new ec.PointFp(this.curve,this.curve.fromBigInteger(x3),this.curve.fromBigInteger(y3),z3)},ec.PointFp.prototype.multiply=function(k){if(this.isInfinity())return this;if(0==k.signum())return this.curve.getInfinity();var i,e=k,h=e.multiply(new BigInteger("3")),neg=this.negate(),R=this;for(i=h.bitLength()-2;i>0;--i){R=R.twice();var hBit=h.testBit(i);hBit!=e.testBit(i)&&(R=R.add(hBit?this:neg))}return R},ec.PointFp.prototype.multiplyTwo=function(j,x,k){var i;i=j.bitLength()>k.bitLength()?j.bitLength()-1:k.bitLength()-1;for(var R=this.curve.getInfinity(),both=this.add(x);i>=0;)R=R.twice(),j.testBit(i)?R=k.testBit(i)?R.add(both):R.add(this):k.testBit(i)&&(R=R.add(x)),--i;return R},ec.PointFp.prototype.getEncoded=function(compressed){var x=this.getX().toBigInteger(),y=this.getY().toBigInteger(),enc=ec.integerToBytes(x,32);return compressed?y.isEven()?enc.unshift(2):enc.unshift(3):(enc.unshift(4),enc=enc.concat(ec.integerToBytes(y,32))),enc},ec.PointFp.decodeFrom=function(curve,enc){enc[0];var dataLen=enc.length-1,xBa=enc.slice(1,1+dataLen/2),yBa=enc.slice(1+dataLen/2,1+dataLen);xBa.unshift(0),yBa.unshift(0);var x=new BigInteger(xBa),y=new BigInteger(yBa);return new ec.PointFp(curve,curve.fromBigInteger(x),curve.fromBigInteger(y))},ec.PointFp.prototype.add2D=function(b){if(this.isInfinity())return b;if(b.isInfinity())return this;if(this.x.equals(b.x))return this.y.equals(b.y)?this.twice():this.curve.getInfinity();var x_x=b.x.subtract(this.x),gamma=b.y.subtract(this.y).divide(x_x),x3=gamma.square().subtract(this.x).subtract(b.x),y3=gamma.multiply(this.x.subtract(x3)).subtract(this.y);return new ec.PointFp(this.curve,x3,y3)},ec.PointFp.prototype.twice2D=function(){if(this.isInfinity())return this;if(0==this.y.toBigInteger().signum())return this.curve.getInfinity();var TWO=this.curve.fromBigInteger(BigInteger.valueOf(2)),THREE=this.curve.fromBigInteger(BigInteger.valueOf(3)),gamma=this.x.square().multiply(THREE).add(this.curve.a).divide(this.y.multiply(TWO)),x3=gamma.square().subtract(this.x.multiply(TWO)),y3=gamma.multiply(this.x.subtract(x3)).subtract(this.y);return new ec.PointFp(this.curve,x3,y3)},ec.PointFp.prototype.multiply2D=function(k){if(this.isInfinity())return this;if(0==k.signum())return this.curve.getInfinity();var i,e=k,h=e.multiply(new BigInteger("3")),neg=this.negate(),R=this;for(i=h.bitLength()-2;i>0;--i){R=R.twice();var hBit=h.testBit(i);hBit!=e.testBit(i)&&(R=R.add2D(hBit?this:neg))}return R},ec.PointFp.prototype.isOnCurve=function(){var x=this.getX().toBigInteger(),y=this.getY().toBigInteger(),a=this.curve.getA().toBigInteger(),b=this.curve.getB().toBigInteger(),n=this.curve.getQ(),lhs=y.multiply(y).mod(n),rhs=x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(n);return lhs.equals(rhs)},ec.PointFp.prototype.toString=function(){return"("+this.getX().toBigInteger().toString()+","+this.getY().toBigInteger().toString()+")"},ec.PointFp.prototype.validate=function(){var n=this.curve.getQ();if(this.isInfinity())throw new Error("Point is at infinity.");var x=this.getX().toBigInteger(),y=this.getY().toBigInteger();if(x.compareTo(BigInteger.ONE)<0||x.compareTo(n.subtract(BigInteger.ONE))>0)throw new Error("x coordinate out of bounds");if(y.compareTo(BigInteger.ONE)<0||y.compareTo(n.subtract(BigInteger.ONE))>0)throw new Error("y coordinate out of bounds");if(!this.isOnCurve())throw new Error("Point is not on the curve.");if(this.multiply(n).isInfinity())throw new Error("Point is not a scalar multiple of G.");return!0},ec.CurveFp=function(q,a,b){this.q=q,this.a=this.fromBigInteger(a),this.b=this.fromBigInteger(b),this.infinity=new ec.PointFp(this,null,null),this.reducer=new Barrett(this.q)},ec.CurveFp.prototype.getQ=function(){return this.q},ec.CurveFp.prototype.getA=function(){return this.a},ec.CurveFp.prototype.getB=function(){return this.b},ec.CurveFp.prototype.equals=function(other){return other==this||this.q.equals(other.q)&&this.a.equals(other.a)&&this.b.equals(other.b)},ec.CurveFp.prototype.getInfinity=function(){return this.infinity},ec.CurveFp.prototype.fromBigInteger=function(x){return new ec.FieldElementFp(this.q,x)},ec.CurveFp.prototype.reduce=function(x){this.reducer.reduce(x)},ec.CurveFp.prototype.decodePointHex=function(s){var firstByte=parseInt(s.substr(0,2),16);switch(firstByte){case 0:return this.infinity;case 2:case 3:var yTilde=1&firstByte,xHex=s.substr(2,s.length-2),X1=new BigInteger(xHex,16);return this.decompressPoint(yTilde,X1);case 4:case 6:case 7:var len=(s.length-2)/2,yHex=(xHex=s.substr(2,len),s.substr(len+2,len));return new ec.PointFp(this,this.fromBigInteger(new BigInteger(xHex,16)),this.fromBigInteger(new BigInteger(yHex,16)));default:return null}},ec.CurveFp.prototype.encodePointHex=function(p){if(p.isInfinity())return"00";var xHex=p.getX().toBigInteger().toString(16),yHex=p.getY().toBigInteger().toString(16),oLen=this.getQ().toString(16).length;for(oLen%2!=0&&oLen++;xHex.lengthbytes.length;)bytes.unshift(0);return bytes},ec.X9Parameters=function(curve,g,n,h){this.curve=curve,this.g=g,this.n=n,this.h=h},ec.X9Parameters.prototype.getCurve=function(){return this.curve},ec.X9Parameters.prototype.getG=function(){return this.g},ec.X9Parameters.prototype.getN=function(){return this.n},ec.X9Parameters.prototype.getH=function(){return this.h},ec.secNamedCurves={secp256k1:function(){var p=ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"),a=BigInteger.ZERO,b=ec.fromHex("7"),n=ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"),h=BigInteger.ONE,curve=new ec.CurveFp(p,a,b),G=curve.decodePointHex("0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8");return new ec.X9Parameters(curve,G,n,h)}},ec.getSECCurveByName=function(name){return null==ec.secNamedCurves[name]?null:ec.secNamedCurves[name]()},function(){var bitjs=GLOBAL.bitjs=function(){};bitjs.pub=35,bitjs.priv=163,bitjs.multisig=94,bitjs.compressed=!1,"FLO_TEST"==GLOBAL.cryptocoin&&(bitjs.pub=115,bitjs.priv=163,bitjs.multisig=198),bitjs.privkey2wif=function(h){var r=Crypto.util.hexToBytes(h);1==bitjs.compressed&&r.push(1),r.unshift(bitjs.priv);var checksum=Crypto.SHA256(Crypto.SHA256(r,{asBytes:!0}),{asBytes:!0}).slice(0,4);return B58.encode(r.concat(checksum))},bitjs.wif2privkey=function(wif){var compressed=!1,decode=B58.decode(wif),key=decode.slice(0,decode.length-4);return(key=key.slice(1,key.length)).length>=33&&1==key[key.length-1]&&(key=key.slice(0,key.length-1),compressed=!0),{privkey:Crypto.util.bytesToHex(key),compressed:compressed}},bitjs.wif2pubkey=function(wif){var compressed=bitjs.compressed,r=bitjs.wif2privkey(wif);bitjs.compressed=r.compressed;var pubkey=bitjs.newPubkey(r.privkey);return bitjs.compressed=compressed,{pubkey:pubkey,compressed:r.compressed}},bitjs.wif2address=function(wif){var r=bitjs.wif2pubkey(wif);return{address:bitjs.pubkey2address(r.pubkey),compressed:r.compressed}},bitjs.newPubkey=function(hash){var privateKeyBigInt=BigInteger.fromByteArrayUnsigned(Crypto.util.hexToBytes(hash)),curvePt=EllipticCurve.getSECCurveByName("secp256k1").getG().multiply(privateKeyBigInt),x=curvePt.getX().toBigInteger(),y=curvePt.getY().toBigInteger(),publicKeyBytes=EllipticCurve.integerToBytes(x,32);if((publicKeyBytes=publicKeyBytes.concat(EllipticCurve.integerToBytes(y,32))).unshift(4),1==bitjs.compressed){var publicKeyBytesCompressed=EllipticCurve.integerToBytes(x,32);return y.isEven()?publicKeyBytesCompressed.unshift(2):publicKeyBytesCompressed.unshift(3),Crypto.util.bytesToHex(publicKeyBytesCompressed)}return Crypto.util.bytesToHex(publicKeyBytes)},bitjs.pubkey2address=function(h,byte){var r=ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(h),{asBytes:!0}));r.unshift(byte||bitjs.pub);var checksum=Crypto.SHA256(Crypto.SHA256(r,{asBytes:!0}),{asBytes:!0}).slice(0,4);return B58.encode(r.concat(checksum))},bitjs.pubkeys2multisig=function(pubkeys,required){var s=[];s.push(80+required);for(var i=0;i520)throw Error(`redeemScript size(=${s.length}) too large`);var x=ripemd160(Crypto.SHA256(s,{asBytes:!0}),{asBytes:!0});x.unshift(bitjs.multisig);var r=x,checksum=(r=Crypto.SHA256(Crypto.SHA256(r,{asBytes:!0}),{asBytes:!0})).slice(0,4),redeemScript=Crypto.util.bytesToHex(s);return{address:B58.encode(x.concat(checksum)),redeemScript:redeemScript,size:s.length}},bitjs.transaction=function(tx_data=void 0){var btrx={};return btrx.version=2,btrx.inputs=[],btrx.outputs=[],btrx.locktime=0,btrx.floData="",btrx.addinput=function(txid,index,scriptPubKey,sequence){var o={};return o.outpoint={hash:txid,index:index},o.script=Crypto.util.hexToBytes(scriptPubKey),o.sequence=sequence||(0==btrx.locktime?4294967295:0),this.inputs.push(o)},btrx.addoutput=function(address,value){var o={},buf=[],addr=this.addressDecode(address);return o.value=new BigInteger(""+Math.round(1*value*1e8),10),addr.version===bitjs.pub?(buf.push(118),buf.push(169),(buf=this.writeBytesToScriptBuffer(buf,addr.bytes)).push(136),buf.push(172)):addr.version===bitjs.multisig&&(buf.push(169),(buf=this.writeBytesToScriptBuffer(buf,addr.bytes)).push(135)),o.script=buf,this.outputs.push(o)},btrx.addflodata=function(data){if("string"!=typeof data)throw Error("floData should be String");if(data.length>1040)throw Error("floData Character Limit Exceeded");if(bitjs.strToBytes(data).some((c=>c<32||c>127)))throw Error("floData contains Invalid characters (only ASCII characters allowed");return this.floData=data,this.floData},btrx.addressDecode=function(address){var bytes=B58.decode(address),front=bytes.slice(0,bytes.length-4),back=bytes.slice(bytes.length-4);if(Crypto.SHA256(Crypto.SHA256(front,{asBytes:!0}),{asBytes:!0}).slice(0,4)+""==back+"")return{version:front[0],bytes:front.slice(1)}},btrx.transactionHash=function(index,sigHashType){for(var clone=bitjs.clone(this),shType=sigHashType||1,i=0;i=128)if(clone.inputs=[clone.inputs[index]],129==shType);else if(130==shType)clone.outputs=[];else if(131==shType){clone.outputs.length=index+1;for(i=0;i0&&(s=n.subtract(s));var sig=function(r,s){var rBa=r.toByteArraySigned(),sBa=s.toByteArraySigned(),sequence=[];return sequence.push(2),sequence.push(rBa.length),(sequence=sequence.concat(rBa)).push(2),sequence.push(sBa.length),(sequence=sequence.concat(sBa)).unshift(sequence.length),sequence.unshift(48),sequence}(r,s);return sig.push(parseInt(shType,10)),Crypto.util.bytesToHex(sig)}return!1},btrx.deterministicK=function(wif,hash,badrs){badrs=badrs||0;var key=bitjs.wif2privkey(wif),x=Crypto.util.hexToBytes(key.privkey),N=EllipticCurve.getSECCurveByName("secp256k1").getN(),v=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],k=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];k=Crypto.HMAC(Crypto.SHA256,v.concat([0]).concat(x).concat(hash),k,{asBytes:!0}),v=Crypto.HMAC(Crypto.SHA256,v,k,{asBytes:!0}),k=Crypto.HMAC(Crypto.SHA256,v.concat([1]).concat(x).concat(hash),k,{asBytes:!0}),v=Crypto.HMAC(Crypto.SHA256,v,k,{asBytes:!0});var T=[];T=v=Crypto.HMAC(Crypto.SHA256,v,k,{asBytes:!0});for(var KBigInt=BigInteger.fromByteArrayUnsigned(T),i=0;KBigInt.compareTo(N)>=0||KBigInt.compareTo(BigInteger.ZERO)<=0||i>>8&255)):(buf.push(78),buf.push(255&bytes.length),buf.push(bytes.length>>>8&255),buf.push(bytes.length>>>16&255),buf.push(bytes.length>>>24&255)),buf=buf.concat(bytes)},btrx.parseScript=function(script){var chunks=[],i=0;function readChunk(n){chunks.push(script.slice(i,i+n)),i+=n}for(;i=240&&(opcode=opcode<<8|script[i++]),opcode>0&&opcode<76?readChunk(opcode):76==opcode?readChunk(script[i++]):77==opcode?readChunk(script[i++]<<8|script[i++]):78==opcode?readChunk(script[i++]<<24|script[i++]<<16|script[i++]<<8|script[i++]):chunks.push(opcode),i<0)break}return chunks},btrx.decodeRedeemScript=function(rs){"string"==typeof rs&&(rs=Crypto.util.hexToBytes(rs));var script=this.parseScript(rs);if(!(script[0]>80&&script[script.length-2]>80&&174==script[script.length-1]))throw"Invalid RedeemScript";var r={};r.required=script[0]-80,r.pubkeys=[];for(var i=1;i=80&&174==script[i][script[i].length-1]&&(redeemScript=script[i]))}else redeemScript=script;var pubkeyList=this.decodeRedeemScript(redeemScript).pubkeys,pubkey=bitjs.wif2pubkey(wif).pubkey;if(!pubkeyList.includes(pubkey))return!1;pubkeyList=pubkeyList.map((pub=>Crypto.util.hexToBytes(bitjs.pubkeydecompress(pub))));var shType=sigHashType||1;this.inputs[index].script=redeemScript;var signature=Crypto.util.hexToBytes(this.transactionSig(index,wif,shType));sigsList.push(signature);var buf=[];buf.push(0);for(let x in pubkeyList)for(let y in sigsList){var sighash=Crypto.util.hexToBytes(this.transactionHash(index,1*sigsList[y].slice(-1)[0]));if(bitjs.verifySignature(sighash,sigsList[y],pubkeyList[x])){buf=this.writeBytesToScriptBuffer(buf,sigsList[y]);break}}return buf=this.writeBytesToScriptBuffer(buf,redeemScript),this.inputs[index].script=buf,!0},btrx.sign=function(wif,sigHashType){for(var shType=sigHashType||1,i=0;i=80&&174==script[script.length-1]?{type:"multisig",rs:Array.from(this.inputs[index].script)}:void 0},btrx.serialize=function(){var buffer=[];buffer=(buffer=buffer.concat(bitjs.numToBytes(parseInt(this.version),4))).concat(bitjs.numToVarInt(this.inputs.length));for(var i=0;iString.fromCharCode(b))).join("")}(tx_data),btrx},bitjs.numToBytes=function(num,bytes){return void 0===bytes&&(bytes=8),0==bytes?[]:-1==num?Crypto.util.hexToBytes("ffffffffffffffff"):[num%256].concat(bitjs.numToBytes(Math.floor(num/256),bytes-1))},bitjs.numToByteArray=function(num){return num<=256?[num]:[num%256].concat(bitjs.numToByteArray(Math.floor(num/256)))},bitjs.numToVarInt=function(num){return num<253?[num]:num<65536?[253].concat(bitjs.numToBytes(num,2)):num<4294967296?[254].concat(bitjs.numToBytes(num,4)):[255].concat(bitjs.numToBytes(num,8))},bitjs.bytesToNum=function(bytes){return 0==bytes.length?0:bytes[0]+256*bitjs.bytesToNum(bytes.slice(1))},bitjs.strToBytes=function(str){return str.split("").map((c=>c.charCodeAt(0)))},bitjs.pubkeydecompress=function(pubkey){if("string"==typeof pubkey&&pubkey.match(/^[a-f0-9]+$/i)){var curve=EllipticCurve.getSECCurveByName("secp256k1");try{var pt=curve.curve.decodePointHex(pubkey),x=pt.getX().toBigInteger(),y=pt.getY().toBigInteger(),publicKeyBytes=EllipticCurve.integerToBytes(x,32);return(publicKeyBytes=publicKeyBytes.concat(EllipticCurve.integerToBytes(y,32))).unshift(4),Crypto.util.bytesToHex(publicKeyBytes)}catch(e){return!1}}return!1},bitjs.verifySignature=function(hash,sig,pubkey){return Bitcoin.ECDSA.verify(hash,sig,pubkey)},bitjs.clone=function(obj){if(null==obj||"object"!=typeof obj)return obj;var temp=new obj.constructor;for(var key in obj)obj.hasOwnProperty(key)&&(temp[key]=bitjs.clone(obj[key]));return temp};var B58=bitjs.Base58={alphabet:"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",validRegex:/^[1-9A-HJ-NP-Za-km-z]+$/,base:BigInteger.valueOf(58),encode:function(input){for(var bi=BigInteger.fromByteArrayUnsigned(input),chars=[];bi.compareTo(B58.base)>=0;){var mod=bi.mod(B58.base);chars.unshift(B58.alphabet[mod.intValue()]),bi=bi.subtract(mod).divide(B58.base)}chars.unshift(B58.alphabet[bi.intValue()]);for(var i=0;i=0;i--){var alphaIndex=B58.alphabet.indexOf(input[i]);if(alphaIndex<0)throw"Invalid character";bi=bi.add(BigInteger.valueOf(alphaIndex).multiply(B58.base.pow(input.length-1-i))),"1"==input[i]?leadingZerosNum++:leadingZerosNum=0}for(var bytes=bi.toByteArrayUnsigned();leadingZerosNum-- >0;)bytes.unshift(0);return bytes}}}(),function(){var ecparams,rng,P_OVER_FOUR,ECDSA,Bip38,Bitcoin=GLOBAL.Bitcoin={},B58=Bitcoin.Base58={alphabet:"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",validRegex:/^[1-9A-HJ-NP-Za-km-z]+$/,base:BigInteger.valueOf(58),encode:function(input){for(var bi=BigInteger.fromByteArrayUnsigned(input),chars=[];bi.compareTo(B58.base)>=0;){var mod=bi.mod(B58.base);chars.unshift(B58.alphabet[mod.intValue()]),bi=bi.subtract(mod).divide(B58.base)}chars.unshift(B58.alphabet[bi.intValue()]);for(var i=0;i=0;i--){var alphaIndex=B58.alphabet.indexOf(input[i]);if(alphaIndex<0)throw"Invalid character";bi=bi.add(BigInteger.valueOf(alphaIndex).multiply(B58.base.pow(input.length-1-i))),"1"==input[i]?leadingZerosNum++:leadingZerosNum=0}for(var bytes=bi.toByteArrayUnsigned();leadingZerosNum-- >0;)bytes.unshift(0);return bytes}};Bitcoin.Address=function(bytes){if("string"==typeof bytes){var d=Bitcoin.Address.decodeString(bytes);if(bytes=d.hash,d.version!=Bitcoin.Address.standardVersion&&d.version!=Bitcoin.Address.multisigVersion)throw"Version (prefix) "+d.version+" not supported!";this.version=d.version}else this.version=Bitcoin.Address.standardVersion;this.hash=bytes},Bitcoin.Address.standardVersion=35,Bitcoin.Address.multisigVersion=94,"FLO_TEST"==GLOBAL.cryptocoin&&(Bitcoin.Address.standardVersion=115,Bitcoin.Address.multisigVersion=198),Bitcoin.Address.prototype.toString=function(version=null){var hash=this.hash.slice(0);hash.unshift(null!==version?version:this.version);var checksum=Crypto.SHA256(Crypto.SHA256(hash,{asBytes:!0}),{asBytes:!0}),bytes=hash.concat(checksum.slice(0,4));return Bitcoin.Base58.encode(bytes)},Bitcoin.Address.prototype.getHashBase64=function(){return Crypto.util.bytesToBase64(this.hash)},Bitcoin.Address.decodeString=function(string){var bytes=Bitcoin.Base58.decode(string),hash=bytes.slice(0,21),checksum=Crypto.SHA256(Crypto.SHA256(hash,{asBytes:!0}),{asBytes:!0});if(checksum[0]!=bytes[21]||checksum[1]!=bytes[22]||checksum[2]!=bytes[23]||checksum[3]!=bytes[24])throw"Checksum validation failed!";return{version:hash.shift(),hash:hash}},Bitcoin.ECDSA=(ecparams=EllipticCurve.getSECCurveByName("secp256k1"),rng=new SecureRandom,P_OVER_FOUR=null,ECDSA={getBigRandom:function(limit){return new BigInteger(limit.bitLength(),rng).mod(limit.subtract(BigInteger.ONE)).add(BigInteger.ONE)},sign:function(hash,priv){var d=priv,n=ecparams.getN(),e=BigInteger.fromByteArrayUnsigned(hash);do{var k=ECDSA.getBigRandom(n),r=ecparams.getG().multiply(k).getX().toBigInteger().mod(n)}while(r.compareTo(BigInteger.ZERO)<=0);var s=k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);return ECDSA.serializeSig(r,s)},verify:function(hash,sig,pubkey){var r,s,Q;if(Bitcoin.Util.isArray(sig)){var obj=ECDSA.parseSig(sig);r=obj.r,s=obj.s}else{if("object"!=typeof sig||!sig.r||!sig.s)throw"Invalid value for signature";r=sig.r,s=sig.s}if(pubkey instanceof EllipticCurve.PointFp)Q=pubkey;else{if(!Bitcoin.Util.isArray(pubkey))throw"Invalid format for pubkey value, must be byte array or ec.PointFp";Q=EllipticCurve.PointFp.decodeFrom(ecparams.getCurve(),pubkey)}var e=BigInteger.fromByteArrayUnsigned(hash);return ECDSA.verifyRaw(e,r,s,Q)},verifyRaw:function(e,r,s,Q){var n=ecparams.getN(),G=ecparams.getG();if(r.compareTo(BigInteger.ONE)<0||r.compareTo(n)>=0)return!1;if(s.compareTo(BigInteger.ONE)<0||s.compareTo(n)>=0)return!1;var c=s.modInverse(n),u1=e.multiply(c).mod(n),u2=r.multiply(c).mod(n);return G.multiply(u1).add(Q.multiply(u2)).getX().toBigInteger().mod(n).equals(r)},serializeSig:function(r,s){var rBa=r.toByteArraySigned(),sBa=s.toByteArraySigned(),sequence=[];return sequence.push(2),sequence.push(rBa.length),(sequence=sequence.concat(rBa)).push(2),sequence.push(sBa.length),(sequence=sequence.concat(sBa)).unshift(sequence.length),sequence.unshift(48),sequence},parseSig:function(sig){var cursor;if(48!=sig[0])throw new Error("Signature not a valid DERSequence");if(2!=sig[cursor=2])throw new Error("First element in signature must be a DERInteger");var rBa=sig.slice(cursor+2,cursor+2+sig[cursor+1]);if(2!=sig[cursor+=2+sig[cursor+1]])throw new Error("Second element in signature must be a DERInteger");var sBa=sig.slice(cursor+2,cursor+2+sig[cursor+1]);return cursor+=2+sig[cursor+1],{r:BigInteger.fromByteArrayUnsigned(rBa),s:BigInteger.fromByteArrayUnsigned(sBa)}},parseSigCompact:function(sig){if(65!==sig.length)throw"Signature has the wrong length";var i=sig[0]-27;if(i<0||i>7)throw"Invalid signature type";var n=ecparams.getN();return{r:BigInteger.fromByteArrayUnsigned(sig.slice(1,33)).mod(n),s:BigInteger.fromByteArrayUnsigned(sig.slice(33,65)).mod(n),i:i}},recoverPubKey:function(r,s,hash,i){var isYEven=1&(i&=3),isSecondKey=i>>1,n=ecparams.getN(),G=ecparams.getG(),curve=ecparams.getCurve(),p=curve.getQ(),a=curve.getA().toBigInteger(),b=curve.getB().toBigInteger();P_OVER_FOUR||(P_OVER_FOUR=p.add(BigInteger.ONE).divide(BigInteger.valueOf(4)));var x=isSecondKey?r.add(n):r,beta=x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p).modPow(P_OVER_FOUR,p),y=(beta.isEven(),(beta.isEven()?!isYEven:isYEven)?beta:p.subtract(beta)),R=new EllipticCurve.PointFp(curve,curve.fromBigInteger(x),curve.fromBigInteger(y));R.validate();var e=BigInteger.fromByteArrayUnsigned(hash),eNeg=BigInteger.ZERO.subtract(e).mod(n),rInv=r.modInverse(n),Q=function(P,k,Q,l){for(var m=Math.max(k.bitLength(),l.bitLength()),Z=P.add2D(Q),R=P.curve.getInfinity(),i=m-1;i>=0;--i)(R=R.twice2D()).z=BigInteger.ONE,k.testBit(i)?R=l.testBit(i)?R.add2D(Z):R.add2D(P):l.testBit(i)&&(R=R.add2D(Q));return R}(R,s,G,eNeg).multiply(rInv);if(Q.validate(),!ECDSA.verifyRaw(e,r,s,Q))throw"Pubkey recovery unsuccessful";var pubKey=new Bitcoin.ECKey;return pubKey.pub=Q,pubKey},calcPubkeyRecoveryParam:function(address,r,s,hash){for(var i=0;i<4;i++)try{if(Bitcoin.ECDSA.recoverPubKey(r,s,hash,i).getBitcoinAddress().toString()==address)return i}catch(e){}throw"Unable to find valid recovery factor"}}),Bitcoin.KeyPool=new function(){return this.keyArray=[],this.push=function(item){if(null!=item&&null!=item.priv){var doAdd=!0;for(var index in this.keyArray){var currentItem=this.keyArray[index];if(null!=currentItem&&null!=currentItem.priv&&item.getBitcoinAddress()==currentItem.getBitcoinAddress()){doAdd=!1;break}}doAdd&&this.keyArray.push(item)}},this.reset=function(){this.keyArray=[]},this.getArray=function(){return this.keyArray.slice(0)},this.setArray=function(ka){this.keyArray=ka},this.length=function(){return this.keyArray.length},this.toString=function(){var keyPoolString="# = "+this.length()+"\n",pool=this.getArray();for(var index in pool){var item=pool[index];Bitcoin.Util.hasMethods(item,"getBitcoinAddress","toString")&&null!=item&&(keyPoolString+='"'+item.getBitcoinAddress()+'", "'+item.toString("wif")+'"\n')}return keyPoolString},this},Bitcoin.Bip38Key=((Bip38=function(address,encryptedKey){this.address=address,this.priv=encryptedKey}).prototype.getBitcoinAddress=function(){return this.address},Bip38.prototype.toString=function(){return this.priv},Bip38),Bitcoin.ECKey=function(){var ECDSA=Bitcoin.ECDSA,KeyPool=Bitcoin.KeyPool,ecparams=EllipticCurve.getSECCurveByName("secp256k1"),ECKey=function(input){if(input){if(input instanceof BigInteger)this.priv=input;else if(Bitcoin.Util.isArray(input))this.priv=BigInteger.fromByteArrayUnsigned(input);else if("string"==typeof input){var bytes=null;try{/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{52}$/.test(input)?(bytes=ECKey.decodeCompressedWalletImportFormat(input),this.compressed=!0):ECKey.isHexFormat(input)&&(bytes=Crypto.util.hexToBytes(input))}catch(exc1){this.setError(exc1)}ECKey.isBase6Format(input)?this.priv=new BigInteger(input,6):null==bytes||32!=bytes.length?this.priv=null:this.priv=BigInteger.fromByteArrayUnsigned(bytes)}}else{var n=ecparams.getN();this.priv=ECDSA.getBigRandom(n)}this.compressed=null==this.compressed?!!ECKey.compressByDefault:this.compressed;try{null!=this.priv&&0==BigInteger.ZERO.compareTo(this.priv)&&this.setError("Error: BigInteger equal to zero.");var rangeLimitBytes=Crypto.util.hexToBytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140"),limitBigInt=BigInteger.fromByteArrayUnsigned(rangeLimitBytes);null!=this.priv&&limitBigInt.compareTo(this.priv)<0&&this.setError("Error: BigInteger outside of curve range."),null!=this.priv&&KeyPool.push(this)}catch(exc2){this.setError(exc2)}};return"FLO"==GLOBAL.cryptocoin?ECKey.privateKeyPrefix=163:"FLO_TEST"==GLOBAL.cryptocoin&&(ECKey.privateKeyPrefix=239),ECKey.compressByDefault=!1,ECKey.prototype.setError=function(err){return this.error=err,this.priv=null,this},ECKey.prototype.setCompressed=function(v){return this.compressed=!!v,this.pubPoint&&(this.pubPoint.compressed=this.compressed),this},ECKey.prototype.getPub=function(){return this.compressed?this.pubComp?this.pubComp:this.pubComp=this.getPubPoint().getEncoded(1):this.pubUncomp?this.pubUncomp:this.pubUncomp=this.getPubPoint().getEncoded(0)},ECKey.prototype.getPubPoint=function(){return this.pubPoint||(this.pubPoint=ecparams.getG().multiply(this.priv),this.pubPoint.compressed=this.compressed),this.pubPoint},ECKey.prototype.getPubKeyHex=function(){return this.compressed?this.pubKeyHexComp?this.pubKeyHexComp:this.pubKeyHexComp=Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase():this.pubKeyHexUncomp?this.pubKeyHexUncomp:this.pubKeyHexUncomp=Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase()},ECKey.prototype.getPubKeyHash=function(){return this.compressed?this.pubKeyHashComp?this.pubKeyHashComp:this.pubKeyHashComp=Bitcoin.Util.sha256ripe160(this.getPub()):this.pubKeyHashUncomp?this.pubKeyHashUncomp:this.pubKeyHashUncomp=Bitcoin.Util.sha256ripe160(this.getPub())},ECKey.prototype.getBitcoinAddress=function(){var hash=this.getPubKeyHash();return new Bitcoin.Address(hash).toString()},ECKey.prototype.setPub=function(pub){Bitcoin.Util.isArray(pub)&&(pub=Crypto.util.bytesToHex(pub).toString().toUpperCase());var ecPoint=ecparams.getCurve().decodePointHex(pub);return this.setCompressed(ecPoint.compressed),this.pubPoint=ecPoint,this},ECKey.prototype.getBitcoinWalletImportFormat=function(){var bytes=this.getBitcoinPrivateKeyByteArray();if(null==bytes)return"";bytes.unshift(ECKey.privateKeyPrefix),this.compressed&&bytes.push(1);var checksum=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0});return bytes=bytes.concat(checksum.slice(0,4)),Bitcoin.Base58.encode(bytes)},ECKey.prototype.getBitcoinHexFormat=function(){return Crypto.util.bytesToHex(this.getBitcoinPrivateKeyByteArray()).toString().toUpperCase()},ECKey.prototype.getBitcoinBase64Format=function(){return Crypto.util.bytesToBase64(this.getBitcoinPrivateKeyByteArray())},ECKey.prototype.getBitcoinPrivateKeyByteArray=function(){if(null==this.priv)return null;for(var bytes=this.priv.toByteArrayUnsigned();bytes.length<32;)bytes.unshift(0);return bytes},ECKey.prototype.toString=function(format){return"base64"==(format=format||"").toString().toLowerCase()||"b64"==format.toString().toLowerCase()?this.getBitcoinBase64Format():"wif"==format.toString().toLowerCase()?this.getBitcoinWalletImportFormat():this.getBitcoinHexFormat()},ECKey.prototype.sign=function(hash){return ECDSA.sign(hash,this.priv)},ECKey.prototype.verify=function(hash,sig){return ECDSA.verify(hash,sig,this.getPub())},ECKey.decodeWalletImportFormat=function(privStr){var bytes=Bitcoin.Base58.decode(privStr),hash=bytes.slice(0,33),checksum=Crypto.SHA256(Crypto.SHA256(hash,{asBytes:!0}),{asBytes:!0});if(checksum[0]!=bytes[33]||checksum[1]!=bytes[34]||checksum[2]!=bytes[35]||checksum[3]!=bytes[36])throw"Checksum validation failed!";hash.shift();return hash},ECKey.decodeCompressedWalletImportFormat=function(privStr){var bytes=Bitcoin.Base58.decode(privStr),hash=bytes.slice(0,34),checksum=Crypto.SHA256(Crypto.SHA256(hash,{asBytes:!0}),{asBytes:!0});if(checksum[0]!=bytes[34]||checksum[1]!=bytes[35]||checksum[2]!=bytes[36]||checksum[3]!=bytes[37])throw"Checksum validation failed!";hash.shift();return hash.pop(),hash},ECKey.isHexFormat=function(key){return key=key.toString(),/^[A-Fa-f0-9]{64}$/.test(key)},ECKey.isWalletImportFormat=function(key){return key=key.toString(),128==ECKey.privateKeyPrefix?/^5[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50}$/.test(key):/^R[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50}$/.test(key)},ECKey.isCompressedWalletImportFormat=function(key){return key=key.toString(),128==ECKey.privateKeyPrefix?/^[LK][123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{51}$/.test(key):/^R[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{51}$/.test(key)},ECKey.isBase64Format=function(key){return key=key.toString(),/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=+\/]{44}$/.test(key)},ECKey.isBase6Format=function(key){return key=key.toString(),/^[012345]{99}$/.test(key)},ECKey.isMiniFormat=function(key){key=key.toString();var validChars22=/^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21}$/.test(key),validChars26=/^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{25}$/.test(key),validChars30=/^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{29}$/.test(key),testBytes=Crypto.SHA256(key+"?",{asBytes:!0});return(0===testBytes[0]||1===testBytes[0])&&(validChars22||validChars26||validChars30)},ECKey}(),Bitcoin.Util={isArray:Array.isArray||function(o){return"[object Array]"===Object.prototype.toString.call(o)},makeFilledArray:function(len,val){for(var array=[],i=0;i>>8,255&i]:i<=1?[254].concat(Crypto.util.wordsToBytes([i])):[255].concat(Crypto.util.wordsToBytes([i>>>32,i]))},valueToBigInt:function(valueBuffer){return valueBuffer instanceof BigInteger?valueBuffer:BigInteger.fromByteArrayUnsigned(valueBuffer)},formatValue:function(valueBuffer){for(var value=this.valueToBigInt(valueBuffer).toString(),integerPart=value.length>8?value.substr(0,value.length-8):"0",decimalPart=value.length>8?value.substr(value.length-8):value;decimalPart.length<8;)decimalPart="0"+decimalPart;for(decimalPart=decimalPart.replace(/0*$/,"");decimalPart.length<2;)decimalPart+="0";return integerPart+"."+decimalPart},parseValue:function(valueString){for(var valueComp=valueString.split("."),integralPart=valueComp[0],fractionalPart=valueComp[1]||"0";fractionalPart.length<8;)fractionalPart+="0";fractionalPart=fractionalPart.replace(/^0+/g,"");var value=BigInteger.valueOf(parseInt(integralPart));return value=(value=value.multiply(BigInteger.valueOf(1e8))).add(BigInteger.valueOf(parseInt(fractionalPart)))},sha256ripe160:function(data){return ripemd160(Crypto.SHA256(data,{asBytes:!0}),{asBytes:!0})},dsha256:function(data){return Crypto.SHA256(Crypto.SHA256(data,{asBytes:!0}),{asBytes:!0})},hasMethods:function(obj){for(var methodName,i=1;methodName=arguments[i++];)if("function"!=typeof obj[methodName])return!1;return!0}}}(),(ellipticEncryption=GLOBAL.ellipticCurveEncryption=function(){}).rng=new SecureRandom,ellipticEncryption.getCurveParameters=function(curveName){curveName=void 0!==curveName?curveName:"secp256k1";var c=EllipticCurve.getSECCurveByName(curveName),curveDetails={Q:"",A:"",B:"",GX:"",GY:"",N:""};return curveDetails.Q=c.getCurve().getQ().toString(),curveDetails.A=c.getCurve().getA().toBigInteger().toString(),curveDetails.B=c.getCurve().getB().toBigInteger().toString(),curveDetails.GX=c.getG().getX().toBigInteger().toString(),curveDetails.GY=c.getG().getY().toBigInteger().toString(),curveDetails.N=c.getN().toString(),curveDetails},ellipticEncryption.selectedCurve=ellipticEncryption.getCurveParameters("secp256k1"),ellipticEncryption.get_curve=function(){return new EllipticCurve.CurveFp(new BigInteger(this.selectedCurve.Q),new BigInteger(this.selectedCurve.A),new BigInteger(this.selectedCurve.B))},ellipticEncryption.get_G=function(curve){return new EllipticCurve.PointFp(curve,curve.fromBigInteger(new BigInteger(this.selectedCurve.GX)),curve.fromBigInteger(new BigInteger(this.selectedCurve.GY)))},ellipticEncryption.pick_rand=function(){var n=new BigInteger(this.selectedCurve.N),n1=n.subtract(BigInteger.ONE);return new BigInteger(n.bitLength(),this.rng).mod(n1).add(BigInteger.ONE)},ellipticEncryption.senderRandom=function(){return this.pick_rand().toString()},ellipticEncryption.receiverRandom=function(){return this.pick_rand().toString()},ellipticEncryption.senderPublicString=function(senderPrivateKey){var senderKeyECData={},curve=this.get_curve(),G=this.get_G(curve),a=new BigInteger(senderPrivateKey),P=G.multiply(a);return senderKeyECData.XValuePublicString=P.getX().toBigInteger().toString(),senderKeyECData.YValuePublicString=P.getY().toBigInteger().toString(),senderKeyECData},ellipticEncryption.receiverPublicString=function(receiverPublicKey){var receiverKeyECData={},curve=this.get_curve(),G=this.get_G(curve),a=new BigInteger(receiverPublicKey),P=G.multiply(a);return receiverKeyECData.XValuePublicString=P.getX().toBigInteger().toString(),receiverKeyECData.YValuePublicString=P.getY().toBigInteger().toString(),receiverKeyECData},ellipticEncryption.senderSharedKeyDerivation=function(receiverPublicStringXValue,receiverPublicStringYValue,senderPrivateKey){var senderDerivedKey={},curve=this.get_curve(),P=new EllipticCurve.PointFp(curve,curve.fromBigInteger(new BigInteger(receiverPublicStringXValue)),curve.fromBigInteger(new BigInteger(receiverPublicStringYValue))),a=new BigInteger(senderPrivateKey),S=P.multiply(a);return senderDerivedKey.XValue=S.getX().toBigInteger().toString(),senderDerivedKey.YValue=S.getY().toBigInteger().toString(),senderDerivedKey},ellipticEncryption.receiverSharedKeyDerivation=function(senderPublicStringXValue,senderPublicStringYValue,receiverPrivateKey){var receiverDerivedKey={},curve=this.get_curve(),P=new EllipticCurve.PointFp(curve,curve.fromBigInteger(new BigInteger(senderPublicStringXValue)),curve.fromBigInteger(new BigInteger(senderPublicStringYValue))),a=new BigInteger(receiverPrivateKey),S=P.multiply(a);return receiverDerivedKey.XValue=S.getX().toBigInteger().toString(),receiverDerivedKey.YValue=S.getY().toBigInteger().toString(),receiverDerivedKey},function(){function n(a){throw a}var q=null;function s(a,b){this.a=a,this.b=b}function u(a,b){var g,d=[],h=(1<>>5]|=(a.charCodeAt(g/b)&h)<<32-b-g%32;return{value:d,binLen:f}}function x(a){var h,f,b=[],d=a.length;for(0!=d%2&&n("String of HEX type must be in byte increments"),h=0;h>>3]|=f<<24-h%8*4;return{value:b,binLen:4*d}}function B(a){var h,f,g,k,m,b=[],d=0;for(-1===a.search(/^[a-zA-Z0-9=+\/]+$/)&&n("Invalid character in base-64 string"),h=a.indexOf("="),a=a.replace(/\=/g,""),-1!==h&&h1&&"'"==c[c.length-1],child_index=2147483647&parseInt(use_private?c.slice(0,c.length-1):c);use_private&&(child_index+=2147483648);var key=(hdp=hdp.derive(child_index)).keys_extended.privkey&&""!=hdp.keys_extended.privkey?hdp.keys_extended.privkey:hdp.keys_extended.pubkey;hdp=coinjs.hd(key)}return hdp},derive:function(i){i=i||0;var k,key,pubkey,o,blob=Crypto.util.hexToBytes(this.keys.pubkey).concat(coinjs.numToBytes(i,4).reverse()),hash=new jsSHA(Crypto.util.bytesToHex(blob),"HEX").getHMAC(Crypto.util.bytesToHex(r.chain_code),"HEX","SHA-512","HEX"),il=new BigInteger(hash.slice(0,64),16),ir=Crypto.util.hexToBytes(hash.slice(64,128)),ecparams=EllipticCurve.getSECCurveByName("secp256k1");if(ecparams.getCurve(),(o=coinjs.clone(this)).chain_code=ir,o.child_index=i,"private"==this.type)k=il.add(new BigInteger([0].concat(Crypto.util.hexToBytes(this.keys.privkey)))).mod(ecparams.getN()),key=Crypto.util.bytesToHex(k.toByteArrayUnsigned()),pubkey=coinjs.newPubkey(key),o.keys={privkey:key,pubkey:pubkey,wif:coinjs.privkey2wif(key),address:coinjs.pubkey2address(pubkey)};else if("public"==this.type){q=ecparams.curve.decodePointHex(this.keys.pubkey);var curvePt=ecparams.getG().multiply(il).add(q),x=curvePt.getX().toBigInteger(),y=curvePt.getY().toBigInteger(),publicKeyBytesCompressed=EllipticCurve.integerToBytes(x,32);y.isEven()?publicKeyBytesCompressed.unshift(2):publicKeyBytesCompressed.unshift(3),pubkey=Crypto.util.bytesToHex(publicKeyBytesCompressed),o.keys={pubkey:pubkey,address:coinjs.pubkey2address(pubkey)}}return o.parent_fingerprint=ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(r.keys.pubkey),{asBytes:!0}),{asBytes:!0}).slice(0,4),o.keys_extended=o.extend(),o},master:function(pass){var seed=pass?Crypto.SHA256(pass):coinjs.newPrivkey(),I=new jsSHA(seed,"HEX").getHMAC("Bitcoin seed","TEXT","SHA-512","HEX"),chain=(Crypto.util.hexToBytes(I.slice(0,64)),Crypto.util.hexToBytes(I.slice(64,128)));return coinjs.hd().make({depth:0,parent_fingerprint:[0,0,0,0],child_index:0,chain_code:chain,privkey:I.slice(0,64),pubkey:coinjs.newPubkey(I.slice(0,64))})},make:function(data){var k=[];k.push(1*data.depth),k=(k=(k=k.concat(data.parent_fingerprint)).concat(coinjs.numToBytes(data.child_index,4).reverse())).concat(data.chain_code);var o={};if(data.privkey){var prv=coinjs.numToBytes(coinjs.hdkey.prv,4).reverse();(prv=prv.concat(k)).push(0),prv=prv.concat(Crypto.util.hexToBytes(data.privkey));var checksum=Crypto.SHA256(Crypto.SHA256(prv,{asBytes:!0}),{asBytes:!0}).slice(0,4),ret=prv.concat(checksum);o.privkey=coinjs.base58encode(ret)}if(data.pubkey){var pub=coinjs.numToBytes(coinjs.hdkey.pub,4).reverse();pub=(pub=pub.concat(k)).concat(Crypto.util.hexToBytes(data.pubkey)),checksum=Crypto.SHA256(Crypto.SHA256(pub,{asBytes:!0}),{asBytes:!0}).slice(0,4),ret=pub.concat(checksum),o.pubkey=coinjs.base58encode(ret)}return o}};return r.parse()},coinjs.script=function(data){var r={};return data?"string"==typeof data?r.buffer=Crypto.util.hexToBytes(data):coinjs.isArray(data)?r.buffer=data:data instanceof coinjs.script?r.buffer=data.buffer:r.buffer=data:r.buffer=[],r.parse=function(){var self=this;r.chunks=[];var i=0;function readChunk(n){self.chunks.push(self.buffer.slice(i,i+n)),i+=n}for(;i=240&&(opcode=opcode<<8|this.buffer[i++]),opcode>0&&opcode<76?readChunk(opcode):76==opcode?readChunk(this.buffer[i++]):77==opcode?readChunk(this.buffer[i++]<<8|this.buffer[i++]):78==opcode?readChunk(this.buffer[i++]<<24|this.buffer[i++]<<16|this.buffer[i++]<<8|this.buffer[i++]):this.chunks.push(opcode),i<0)break}return!0},r.decodeRedeemScript=function(script){var r=!1;try{var s=coinjs.script(Crypto.util.hexToBytes(script));if(s.chunks.length>=3&&174==s.chunks[s.chunks.length-1]){(r={}).signaturesRequired=s.chunks[0]-80;for(var pubkeys=[],i=1;i=3&&174==s.chunks[s.chunks.length-1]){(r={}).signaturesRequired=s.chunks[0]-80;for(var pubkeys=[],i=1;i>>8&255)):(this.buffer.push(78),this.buffer.push(255&data.length),this.buffer.push(data.length>>>8&255),this.buffer.push(data.length>>>16&255),this.buffer.push(data.length>>>24&255)),this.buffer=this.buffer.concat(data),this.chunks.push(data),!0},r.parse(),r},coinjs.transaction=function(){var r={version:1,lock_time:0,ins:[],outs:[],witness:!1,timestamp:null,block:null,addinput:function(txid,index,script,sequence){var o={};return o.outpoint={hash:txid,index:index},o.script=coinjs.script(script||[]),o.sequence=sequence||(0==r.lock_time?4294967295:0),this.ins.push(o)},addoutput:function(address,value){var o={};o.value=new BigInteger(""+Math.round(1*value*1e8),10);var s=coinjs.script();return o.script=s.spendToScript(address),this.outs.push(o)},addstealth:function(stealth,value){var ephemeralKeyBigInt=BigInteger.fromByteArrayUnsigned(Crypto.util.hexToBytes(coinjs.newPrivkey())),curve=EllipticCurve.getSECCurveByName("secp256k1"),p=EllipticCurve.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"),a=BigInteger.ZERO,b=EllipticCurve.fromHex("7"),calccurve=new EllipticCurve.CurveFp(p,a,b),ephemeralPt=curve.getG().multiply(ephemeralKeyBigInt),sharedPt=calccurve.decodePointHex(stealth.scankey).multiply(ephemeralKeyBigInt),stealthindexKeyBigInt=BigInteger.fromByteArrayUnsigned(Crypto.SHA256(sharedPt.getEncoded(!0),{asBytes:!0})),stealthindexPt=curve.getG().multiply(stealthindexKeyBigInt),addressPt=calccurve.decodePointHex(stealth.spendkey).add(stealthindexPt),sendaddress=coinjs.pubkey2address(Crypto.util.bytesToHex(addressPt.getEncoded(!0))),OPRETBytes=[6].concat(Crypto.util.randomBytes(4)).concat(ephemeralPt.getEncoded(!0)),q=coinjs.script();q.writeOp(106),q.writeBytes(OPRETBytes),v={},v.value=0,v.script=q,this.outs.push(v);var o={};o.value=new BigInteger(""+Math.round(1*value*1e8),10);var s=coinjs.script();return o.script=s.spendToScript(sendaddress),this.outs.push(o)},adddata:function(data){if(data.match(/^[a-f0-9]+$/gi)&&data.length<160&&data.length%2==0){var s=coinjs.script();return s.writeOp(106),s.writeBytes(Crypto.util.hexToBytes(data)),o={},o.value=0,o.script=s,this.outs.push(o)}return!1},listUnspent:function(address,callback){coinjs.ajax(coinjs.host+"?uid="+coinjs.uid+"&key="+coinjs.key+"&setmodule=addresses&request=unspent&address="+address+"&r="+Math.random(),callback,"GET")},getTransaction:function(txid,callback){coinjs.ajax(coinjs.host+"?uid="+coinjs.uid+"&key="+coinjs.key+"&setmodule=bitcoin&request=gettransaction&txid="+txid+"&r="+Math.random(),callback,"GET")},addUnspent:function(address,callback,script,segwit,sequence){var self=this;this.listUnspent(address,(function(data){var s=coinjs.script(),value=0,total=0,x={};GLOBAL.DOMParser?(parser=new DOMParser,xmlDoc=parser.parseFromString(data,"text/xml")):(xmlDoc=new ActiveXObject("Microsoft.XMLDOM"),xmlDoc.async=!1,xmlDoc.loadXML(data));var unspent=xmlDoc.getElementsByTagName("unspent")[0];if(unspent)for(i=1;i<=unspent.childElementCount;i++){var u=xmlDoc.getElementsByTagName("unspent_"+i)[0],txhash=u.getElementsByTagName("tx_hash")[0].childNodes[0].nodeValue.match(/.{1,2}/g).reverse().join("")+"",n=u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue,scr=script||u.getElementsByTagName("script")[0].childNodes[0].nodeValue;segwit&&((s=coinjs.script()).writeBytes(Crypto.util.hexToBytes(script)),s.writeOp(0),s.writeBytes(coinjs.numToBytes(1*u.getElementsByTagName("value")[0].childNodes[0].nodeValue,8)),scr=Crypto.util.bytesToHex(s.buffer));var seq=sequence||!1;self.addinput(txhash,n,scr,seq),value+=1*u.getElementsByTagName("value")[0].childNodes[0].nodeValue,total++}return x.result=xmlDoc.getElementsByTagName("result")[0].childNodes[0].nodeValue,x.unspent=unspent,x.value=value,x.total=total,x.response=xmlDoc.getElementsByTagName("response")[0].childNodes[0].nodeValue,callback(x)}))},addUnspentAndSign:function(wif,callback){var self=this,address=coinjs.wif2address(wif);self.addUnspent(address.address,(function(data){return self.sign(wif),callback(data)}))},broadcast:function(callback,txhex){var tx=txhex||this.serialize();coinjs.ajax(coinjs.host+"?uid="+coinjs.uid+"&key="+coinjs.key+"&setmodule=bitcoin&request=sendrawtransaction",callback,"POST",["rawtx="+tx])},transactionHash:function(index,sigHashType){for(var clone=coinjs.clone(this),shType=sigHashType||1,i=0;i=128)if(clone.ins=[clone.ins[index]],129==shType);else if(130==shType)clone.outs=[];else if(131==shType)for(clone.outs.length=index+1,i=0;i80&&scriptcode.unshift(scriptcode.length);var value=coinjs.numToBytes(extract.value,8),zero=coinjs.numToBytes(0,32),version=coinjs.numToBytes(parseInt(this.version),4),bufferTmp=[];if(!(sigHashType>=80))for(var i=0;i=1?Crypto.SHA256(Crypto.SHA256(bufferTmp,{asBytes:!0}),{asBytes:!0}):zero;if(bufferTmp=[],!(sigHashType>=80)&&2!=sigHashType&&3!=sigHashType)for(i=0;i=1?Crypto.SHA256(Crypto.SHA256(bufferTmp,{asBytes:!0}),{asBytes:!0}):zero,outpoint=Crypto.util.hexToBytes(this.ins[index].outpoint.hash).reverse();outpoint=outpoint.concat(coinjs.numToBytes(this.ins[index].outpoint.index,4));var nsequence=coinjs.numToBytes(this.ins[index].sequence,4),hashOutputs=zero;if(bufferTmp=[],2!=sigHashType&&3!=sigHashType){for(i=0;i0&&(22==this.ins[index].script.chunks[0].length&&0==this.ins[index].script.chunks[0][0]||20==this.ins[index].script.chunks[0].length&&0==this.ins[index].script.chunks[1])){var sigs="true"==(signed=this.witness[index]&&2==this.witness[index].length?"true":"false")?1:0,value=-1;return this.ins[index].script.chunks[2]&&8==this.ins[index].script.chunks[2].length&&(value=coinjs.bytesToNum(this.ins[index].script.chunks[2])),{type:"segwit",signed:signed,signatures:sigs,script:Crypto.util.bytesToHex(this.ins[index].script.chunks[0]),value:value}}if(0==this.ins[index].script.chunks[0]&&174==this.ins[index].script.chunks[this.ins[index].script.chunks.length-1][this.ins[index].script.chunks[this.ins[index].script.chunks.length-1].length-1]){var sigcount=0;for(let i=1;i=80&&174==this.ins[index].script.chunks[this.ins[index].script.chunks.length-1])return{type:"multisig",signed:"false",signatures:0,script:Crypto.util.bytesToHex(this.ins[index].script.buffer)};if(3==this.ins[index].script.chunks.length&&this.ins[index].script.chunks[0][0]>=80&&174==this.ins[index].script.chunks[0][this.ins[index].script.chunks[0].length-1]&&0==this.ins[index].script.chunks[1]){let last_index=this.ins[index].script.chunks.length-1;return value=-1,last_index>=2&&8==this.ins[index].script.chunks[last_index].length&&(value=coinjs.bytesToNum(this.ins[index].script.chunks[last_index])),{type:"multisig_bech32",signed:"false",signatures:sigcount=this.witness[index]?this.witness[index].length-2:0,script:Crypto.util.bytesToHex(this.ins[index].script.chunks[0]),value:value}}var signed;return 0==this.ins[index].script.chunks.length?{type:"empty",signed:signed=this.witness[index]&&this.witness[index].length>=2?"true":"false",signatures:sigs="true"==signed?this.witness[index][0]?1:this.witness[index].length-2:0,script:""}:{type:"unknown",signed:"false",signatures:0,script:Crypto.util.bytesToHex(this.ins[index].script.buffer)}}return!1},transactionSig:function(index,wif,sigHashType,txhash){var shType=sigHashType||1,hash=txhash||Crypto.util.hexToBytes(this.transactionHash(index,shType));if(hash){var curve=EllipticCurve.getSECCurveByName("secp256k1"),key=coinjs.wif2privkey(wif),priv=BigInteger.fromByteArrayUnsigned(Crypto.util.hexToBytes(key.privkey)),n=curve.getN(),e=BigInteger.fromByteArrayUnsigned(hash),badrs=0;do{var k=this.deterministicK(wif,hash,badrs),r=curve.getG().multiply(k).getX().toBigInteger().mod(n),s=k.modInverse(n).multiply(e.add(priv.multiply(r))).mod(n);badrs++}while(r.compareTo(BigInteger.ZERO)<=0||s.compareTo(BigInteger.ZERO)<=0);var halfn=n.shiftRight(1);s.compareTo(halfn)>0&&(s=n.subtract(s));var sig=function(r,s){var rBa=r.toByteArraySigned(),sBa=s.toByteArraySigned(),sequence=[];return sequence.push(2),sequence.push(rBa.length),(sequence=sequence.concat(rBa)).push(2),sequence.push(sBa.length),(sequence=sequence.concat(sBa)).unshift(sequence.length),sequence.unshift(48),sequence}(r,s);return sig.push(parseInt(shType,10)),Crypto.util.bytesToHex(sig)}return!1},deterministicK:function(wif,hash,badrs){badrs=badrs||0;var key=coinjs.wif2privkey(wif),x=Crypto.util.hexToBytes(key.privkey),N=EllipticCurve.getSECCurveByName("secp256k1").getN(),v=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],k=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];k=Crypto.HMAC(Crypto.SHA256,v.concat([0]).concat(x).concat(hash),k,{asBytes:!0}),v=Crypto.HMAC(Crypto.SHA256,v,k,{asBytes:!0}),k=Crypto.HMAC(Crypto.SHA256,v.concat([1]).concat(x).concat(hash),k,{asBytes:!0}),v=Crypto.HMAC(Crypto.SHA256,v,k,{asBytes:!0});var T=[];T=v=Crypto.HMAC(Crypto.SHA256,v,k,{asBytes:!0});for(var KBigInt=BigInteger.fromByteArrayUnsigned(T),i=0;KBigInt.compareTo(N)>=0||KBigInt.compareTo(BigInteger.ZERO)<=0||i=decode_rs.signaturesRequired&&(this.ins[index].script=coinjs.script()),w.unshift(0),w.push(redeemScript),this.witness[index]=w}},signmultisig:function(index,wif,sigHashType){var redeemScript=174==this.ins[index].script.chunks[this.ins[index].script.chunks.length-1]?this.ins[index].script.buffer:this.ins[index].script.chunks[this.ins[index].script.chunks.length-1],pubkeyList=function(redeemScript){for(var r={},i=1;i=1)for(i=0;i0&&(s=n.subtract(s));var sig=function(r,s){var rBa=r.toByteArraySigned(),sBa=s.toByteArraySigned(),sequence=[];return sequence.push(2),sequence.push(rBa.length),(sequence=sequence.concat(rBa)).push(2),sequence.push(sBa.length),(sequence=sequence.concat(sBa)).unshift(sequence.length),sequence.unshift(48),sequence}(r,s);return sig.push(parseInt(shType,10)),Crypto.util.bytesToHex(sig)}return!1},deserialize:function(buffer){"string"==typeof buffer&&(buffer=Crypto.util.hexToBytes(buffer));var pos=0,witness=!1,readAsInt=function(bytes){return 0==bytes?0:(pos++,buffer[pos-1]+256*readAsInt(bytes-1))},readVarInt=function(){return pos++,buffer[pos-1]<253?buffer[pos-1]:readAsInt(buffer[pos-1]-251)},readBytes=function(bytes){return pos+=bytes,buffer.slice(pos-bytes,pos)},readVarString=function(){var size=readVarInt();return readBytes(size)},obj=new coinjs.transaction;obj.version=readAsInt(4),0==buffer[pos]&&1==buffer[pos+1]&&(witness=!0,obj.witness=[],pos+=2);for(var ins=readVarInt(),i=0;i=0)return!1;if(s.compareTo(BigInteger.ONE)<0||s.compareTo(n)>=0)return!1;var c=s.modInverse(n),u1=e.multiply(c).mod(n),u2=r.multiply(c).mod(n);return G.multiply(u1).add(Q.multiply(u2)).getX().toBigInteger().mod(n).equals(r)},coinjs.base58encode=function(buffer){for(var alphabet="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",base=BigInteger.valueOf(58),bi=BigInteger.fromByteArrayUnsigned(buffer),chars=[];bi.compareTo(base)>=0;){var mod=bi.mod(base);chars.unshift(alphabet[mod.intValue()]),bi=bi.subtract(mod).divide(base)}chars.unshift(alphabet[bi.intValue()]);for(var i=0;i=0;i--){var alphaIndex="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".indexOf(buffer[i]);if(alphaIndex<0)throw"Invalid character";bi=bi.add(BigInteger.valueOf(alphaIndex).multiply(base.pow(buffer.length-1-i))),"1"==buffer[i]?leadingZerosNum++:leadingZerosNum=0}for(var bytes=bi.toByteArrayUnsigned();leadingZerosNum-- >0;)bytes.unshift(0);return bytes},coinjs.ajax=function(u,f,m,a){var x=!1;try{x=new ActiveXObject("Msxml2.XMLHTTP")}catch(e){try{x=new ActiveXObject("Microsoft.XMLHTTP")}catch(e){x=new XMLHttpRequest}}if(0==x)return!1;x.open(m,u,!0),x.onreadystatechange=function(){4==x.readyState&&f&&f(x.responseText)},"POST"==m&&x.setRequestHeader("Content-type","application/x-www-form-urlencoded"),x.send(a)},coinjs.clone=function(obj){if(null==obj||"object"!=typeof obj)return obj;var temp=new obj.constructor;for(var key in obj)obj.hasOwnProperty(key)&&(temp[key]=coinjs.clone(obj[key]));return temp},coinjs.numToBytes=function(num,bytes){return void 0===bytes&&(bytes=8),0==bytes?[]:-1==num?Crypto.util.hexToBytes("ffffffffffffffff"):[num%256].concat(coinjs.numToBytes(Math.floor(num/256),bytes-1))},coinjs.numToScriptNumBytes=function(_number){for(var value=Math.abs(_number),size=function(i){return i>2147483647?5:i>8388607?4:i>32767?3:i>127?2:i>0?1:0}(value),result=[],i=0;i{const result=[];let len=string.length-2;for(;len>=0;)result.push(string.substr(len,2)),len-=2;return result.join("")},coinjs.getTransactionHash=function(transaction_in_hex,changeOutputEndianess){var x1,x2,x3,x4,x5;return x1=Crypto.util.hexToBytes(transaction_in_hex),x2=Crypto.SHA256(x1),x3=Crypto.util.hexToBytes(x2),x4=Crypto.SHA256(x3),x5=coinjs.changeEndianness(x4),1==changeOutputEndianess||void 0!==changeOutputEndianess&&0!=changeOutputEndianess||(x5=x4),x5},coinjs.compressedToUncompressed=function(compressed){var t1,curve=EllipticCurve.getSECCurveByName("secp256k1");return t1=curve.curve.decodePointHex(compressed),curve.curve.encodePointHex(t1)},coinjs.uncompressedToCompressed=function(uncompressed){var t1;return t1=uncompressed.charAt(uncompressed.length-1),(parseInt(t1,10)%2==1?"03":"02")+uncompressed.substr(2,64)},coinjs.verifySignatureHex=function(hashHex,sigHex,pubHexCompressed){var h1,s1,p1,p2;return h1=Crypto.util.hexToBytes(hashHex),s1=Crypto.util.hexToBytes(sigHex),p1=coinjs.compressedToUncompressed(pubHexCompressed),p2=Crypto.util.hexToBytes(p1),coinjs.verifySignature(h1,s1,p2)},coinjs.generateBitcoinSignature=function(private_key,hash,sighash_type_int=1){var wif;return wif=private_key.length<60?private_key:coinjs.privkey2wif(private_key),coinjs.transaction().transactionSigNoIndex(wif,sighash_type_int,hash)},coinjs.dSHA256=function(data){var t1,t2;return t1=Crypto.SHA256(Crypto.util.hexToBytes(data)),t2=Crypto.util.hexToBytes(t1),Crypto.SHA256(t2)},coinjs.fromBitcoinAmountFormat=function(data){var x1;return x1=coinjs.changeEndianness(data),parseInt(x1,16)/10**8},coinjs.toBitcoinAmountFormat=function(countBitcoin){var t3;return t3=(countBitcoin*10**8).toString(16),coinjs.changeEndianness(t3).padEnd(16,"0")},coinjs.scriptcodeCreatorBasic=function(scriptpubkey){return"0014"==scriptpubkey.substr(0,4)?"1976a9"+scriptpubkey.slice(2)+"88ac":(scriptpubkey.length/2).toString(16)+scriptpubkey},coinjs.ripemd160sha256=function(data){var t1;return t1=ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(data),{asBytes:!0}),{asBytes:!0}),Crypto.util.bytesToHex(t1)},coinjs.random=function(length){var r="",l=length||25;for(let x=0;x<|./;'#][=-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".charAt(Math.floor(62*Math.random()));return r},function(){var SecretShare=GLOBAL.shamirSecretShare={},defaults={bits:8,radix:16,minBits:3,maxBits:20,bytesPerChar:2,maxBytesPerChar:6,primitivePolynomials:[null,null,1,3,3,5,3,3,29,17,9,5,83,27,43,3,45,9,39,39,9,5,3,33,27,9,71,39,9,5,83],warning:"WARNING:\nA secure random number generator was not found.\nUsing securedMathRandom(), which is NOT cryptographically strong!"},config={};function init(bits){if(bits&&("number"!=typeof bits||bits%1!=0||bitsdefaults.maxBits))throw new Error("Number of bits must be an integer between "+defaults.minBits+" and "+defaults.maxBits+", inclusive.");config.radix=defaults.radix,config.bits=bits||defaults.bits,config.size=Math.pow(2,config.bits),config.max=config.size-1;for(var logs=[],exps=[],x=1,primitive=defaults.primitivePolynomials[config.bits],i=0;i=config.size&&(x^=primitive,x&=config.max);config.logs=logs,config.exps=exps}function isInited(){return!!(config.bits&&config.size&&config.max&&config.logs&&config.exps&&config.logs.length===config.size&&config.exps.length===config.size)}function warn(){GLOBAL.console.warn(defaults.warning),"function"==typeof GLOBAL.alert&&config.alert&&GLOBAL.alert(defaults.warning)}function isSetRNG(){return"function"==typeof config.rng}function horner(x,coeffs){for(var logx=config.logs[x],fx=0,i=coeffs.length-1;i>=0;i--)fx=0!==fx?config.exps[(logx+config.logs[fx])%config.max]^coeffs[i]:coeffs[i];return fx}function inArray(arr,val){for(var i=0,len=arr.length;idefaults.maxBits))throw new Error("Number of bits must be an integer between "+defaults.minBits+" and "+defaults.maxBits+", inclusive.");var max=Math.pow(2,bits)-1,idLength=max.toString(config.radix).length,id=parseInt(share.substr(1,idLength),config.radix);if("number"!=typeof id||id%1!=0||id<1||id>max)throw new Error("Share id must be an integer between 1 and "+config.max+", inclusive.");if(!(share=share.substr(idLength+1)).length)throw new Error("Invalid share: zero-length share.");return{bits:bits,id:id,value:share}}function combine(at,shares){for(var setBits,share,x=[],y=[],result="",i=0,len=shares.length;iconfig.bits;i-=config.bits)parts.push(parseInt(str.slice(i-config.bits,i),2));return parts.push(parseInt(str.slice(0,i),2)),parts}function padLeft(str,bits){bits=bits||config.bits;var missing=str.length%bits;return(missing?new Array(bits-missing+1).join("0"):"")+str}function hex2bin(str){for(var num,bin="",i=str.length-1;i>=0;i--){if(num=parseInt(str[i],16),isNaN(num))throw new Error("Invalid hex character.");bin=padLeft(num.toString(2),4)+bin}return bin}function bin2hex(str){for(var num,hex="",i=(str=padLeft(str,4)).length;i>=4;i-=4){if(num=parseInt(str.slice(i-4,i),2),isNaN(num))throw new Error("Invalid binary character.");hex=num.toString(16)+hex}return hex}SecretShare.getConfig=function(){return{bits:config.bits,unsafePRNG:config.unsafePRNG}},SecretShare.init=init,SecretShare.setRNG=function(rng,alert){if(isInited()||this.init(),config.unsafePRNG=!1,"function"!=typeof(rng=rng||function(){var crypto;function construct(bits,arr,radix,size){for(var str="",i=0,len=arr.length-1;iconfig.bits||rng(config.bits).lengthconfig.max){var neededBits=Math.ceil(Math.log(numShares+1)/Math.LN2);throw new Error("Number of shares must be an integer between 2 and 2^bits-1 ("+config.max+"), inclusive. To create "+numShares+" shares, use at least "+neededBits+" bits.")}if("number"!=typeof threshold||threshold%1!=0||threshold<2)throw new Error("Threshold number of shares must be an integer between 2 and 2^bits-1 ("+config.max+"), inclusive.");if(threshold>config.max){neededBits=Math.ceil(Math.log(threshold+1)/Math.LN2);throw new Error("Threshold number of shares must be an integer between 2 and 2^bits-1 ("+config.max+"), inclusive. To use a threshold of "+threshold+", use at least "+neededBits+" bits.")}if("number"!=typeof padLength||padLength%1!=0)throw new Error("Zero-pad length must be an integer greater than 1.");config.unsafePRNG&&warn(),secret=split(secret="1"+hex2bin(secret),padLength);for(var x=new Array(numShares),y=new Array(numShares),i=0,len=secret.length;imax)throw new Error("Share id must be an integer between 1 and "+config.max+", inclusive.");var padding=max.toString(config.radix).length;return config.bits.toString(36).toUpperCase()+padLeft(id.toString(config.radix),padding)+combine(id,shares)},SecretShare._lagrange=lagrange,SecretShare.str2hex=function(str,bytesPerChar){if("string"!=typeof str)throw new Error("Input must be a character string.");if("number"!=typeof(bytesPerChar=bytesPerChar||defaults.bytesPerChar)||bytesPerChar%1!=0||bytesPerChar<1||bytesPerChar>defaults.maxBytesPerChar)throw new Error("Bytes per character must be an integer between 1 and "+defaults.maxBytesPerChar+", inclusive.");for(var num,hexChars=2*bytesPerChar,max=Math.pow(16,hexChars)-1,out="",i=0,len=str.length;imax){var neededBytes=Math.ceil(Math.log(num+1)/Math.log(256));throw new Error("Invalid character code ("+num+"). Maximum allowable is 256^bytes-1 ("+max+"). To convert this character, use at least "+neededBytes+" bytes.")}out=padLeft(num.toString(16),hexChars)+out}return out},SecretShare.hex2str=function(str,bytesPerChar){if("string"!=typeof str)throw new Error("Input must be a hexadecimal string.");if("number"!=typeof(bytesPerChar=bytesPerChar||defaults.bytesPerChar)||bytesPerChar%1!=0||bytesPerChar<1||bytesPerChar>defaults.maxBytesPerChar)throw new Error("Bytes per character must be an integer between 1 and "+defaults.maxBytesPerChar+", inclusive.");for(var hexChars=2*bytesPerChar,out="",i=0,len=(str=padLeft(str,hexChars)).length;icandidate.vectorClock?incumbent:candidate},this.distance=function(firstId,secondId){let distance=0,i=0;const min=Math.min(firstId.length,secondId.length),max=Math.max(firstId.length,secondId.length);for(;i=0?(this._update(node,index,contact),this):node.contacts.length0&&contacts.length[this.distance(a.id,id),a])).sort(((a,b)=>a[0]-b[0])).slice(0,n).map((a=>a[1]))},this.count=function(){let count=0;for(const nodes=[this.root];nodes.length>0;){const node=nodes.pop();null===node.contacts?nodes.push(node.right,node.left):count+=node.contacts.length}return count},this._determineNode=function(node,id,bitIndex){const bytesDescribedByBitIndex=bitIndex>>3,bitIndexWithinByte=bitIndex%8;return id.length<=bytesDescribedByBitIndex&&0!==bitIndexWithinByte?node.left:id[bytesDescribedByBitIndex]&1<<7-bitIndexWithinByte?node.right:node.left},this.get=function(id){this.ensureInt8("id",id);let bitIndex=0,node=this.root;for(;null===node.contacts;)node=this._determineNode(node,id,bitIndex++);const index=this._indexOf(node,id);return index>=0?node.contacts[index]:null},this._indexOf=function(node,id){for(let i=0;i=0&&node.contacts.splice(index,1)[0],this},this._split=function(node,bitIndex){node.left=this.createNode(),node.right=this.createNode();for(const contact of node.contacts)this._determineNode(node,contact.id,bitIndex).contacts.push(contact);node.contacts=null;const detNode=this._determineNode(node,this.localNodeId,bitIndex);(node.left===detNode?node.right:node.left).dontSplit=!0},this.toArray=function(){let result=[];for(const nodes=[this.root];nodes.length>0;){const node=nodes.pop();null===node.contacts?nodes.push(node.right,node.left):result=result.concat(node.contacts)}return result},this._update=function(node,index,contact){if(!this.arrayEquals(node.contacts[index].id,contact.id))throw new Error("wrong index for _update");const incumbent=node.contacts[index],selection=this.arbiter(incumbent,contact);selection===incumbent&&incumbent!==contact||(node.contacts.splice(index,1),node.contacts.push(selection))}}}("undefined"!=typeof global?global:window); \ No newline at end of file diff --git a/js/main.js b/js/main.js deleted file mode 100644 index e69de29..0000000 diff --git a/js/main_UI.js b/js/main_UI.js index d5a72fd..fa440f6 100644 --- a/js/main_UI.js +++ b/js/main_UI.js @@ -326,11 +326,13 @@ function fetchRibcData() { return floCloudAPI.requestObjectData("RIBC", { application: "InternManage", receiverID: "FMyRTrz9CG4TFNM6rCQgy3VQ5NF23bY2xD", - senderID: [ "FCja6sLv58e3RMy41T5AmWyvXEWesqBCkX", "FFS5hFXG7DBtdgzrLwixZLpenAmsCKRddm", "FS4jMAcSimRMrhoRhk5cjuJERS2otiwq4A" ], + senderID: ["FCja6sLv58e3RMy41T5AmWyvXEWesqBCkX", "FFS5hFXG7DBtdgzrLwixZLpenAmsCKRddm", "FS4jMAcSimRMrhoRhk5cjuJERS2otiwq4A"], }) } function fetchTransactions() { - return floTokenAPI.getAllTxs(floGlobals.payer) + return floBlockchainAPI + .readAllTxs("FThgnJLcuStugLc24FJQggmp2WgaZjrBSn") + .then(({ items }) => items) } const render = { internCard(floId) { @@ -428,40 +430,42 @@ const oldInterns = { "FEHKFxQxycsxw2qQQSn2Y1BCT6Mfb8EMko": "Abhijeet Anand", } function getReceiverAddress(vout) { - for(const output of vout) { + for (const output of vout) { for (const address of output.scriptPubKey.addresses) { - if(address !== floGlobals.payer) return address + if (address !== floGlobals.payer) return address } } } function main() { - return Promise.all([fetchTransactions(), fetchRibcData()]).then(([txData]) => { + return Promise.all([fetchTransactions(), fetchRibcData()]).then(([txs]) => { console.log(floGlobals.appObjects.RIBC.internList) floGlobals.appObjects.RIBC.internList = { ...floGlobals.appObjects.RIBC.internList, ...oldInterns } - for (const txid in txData.transactions) { - const { parsedFloData: { tokenAmount }, transactionDetails } = txData.transactions[txid] - const floId = getReceiverAddress(transactionDetails.vout); - if (!floGlobals.appObjects.RIBC.internList[floId]) continue; // not an intern + txs.forEach((tx) => { + const floId = tx.vout[0].scriptPubKey.addresses[0]; + if (!floGlobals.appObjects.RIBC.internList[floId]) return; // not an intern + const { txid, floData, time } = tx if (!floGlobals.internTxs.has(floId)) - floGlobals.internTxs.set(floId, { + floGlobals.internTxs.set(floId, { total: 0, txs: [] }); - floGlobals.internTxs.get(floId).total += tokenAmount; + const amount = parseFloat(floData.match(/([0-9]+)/)[1]) || 0; // get amount from floData + floGlobals.internTxs.get(floId).total += amount; floGlobals.internTxs.get(floId).txs.push({ txid, - amount: tokenAmount, - time: transactionDetails.time + amount, + time }); - } + + }); floGlobals.internTxs.forEach((intern) => { - intern.txs.sort((a,b) => b.time - a.time) + intern.txs.sort((a, b) => b.time - a.time) }) // sort floGlobals.internTxs by date of last payment - floGlobals.internTxs = new Map([...floGlobals.internTxs.entries()].sort((a,b) => b[1].txs[0].time - a[1].txs[0].time)); + floGlobals.internTxs = new Map([...floGlobals.internTxs.entries()].sort((a, b) => b[1].txs[0].time - a[1].txs[0].time)); render.internPaymentList(); routeTo(window.location.hash) }).catch(err => { diff --git a/js/main_UI.min.js b/js/main_UI.min.js new file mode 100644 index 0000000..6bcf7f5 --- /dev/null +++ b/js/main_UI.min.js @@ -0,0 +1,50 @@ +"use strict";const appPages=["dashboard","settings"],{html:html,render:renderElem}=uhtml;navigator.onLine||(floGlobals.connectionErrorNotification=notify("There seems to be a problem connecting to the internet, Please check you internet connection.","error")),window.addEventListener("offline",(()=>{floGlobals.connectionErrorNotification=notify("There seems to be a problem connecting to the internet, Please check you internet connection.","error")})),window.addEventListener("online",(()=>{getRef("notification_drawer").remove(floGlobals.connectionErrorNotification),notify("We are back online.","success")}));const domRefs={};function getRef(elementId){return domRefs.hasOwnProperty(elementId)?domRefs[elementId].count<3?(domRefs[elementId].count=domRefs[elementId].count+1,document.getElementById(elementId)):(domRefs[elementId].ref||(domRefs[elementId].ref=document.getElementById(elementId)),domRefs[elementId].ref):(domRefs[elementId]={count:1,ref:null},document.getElementById(elementId))}const debounce=(callback,wait)=>{let timeoutId=null;return(...args)=>{window.clearTimeout(timeoutId),timeoutId=window.setTimeout((()=>{callback.apply(null,args)}),wait)}};function notify(message,mode,options={}){let icon;switch(mode){case"success":icon='';break;case"error":icon='',options.pinned=!0}return"error"===mode&&console.error(message),getRef("notification_drawer").push(message,{icon:icon,...options})}function getFormattedTime(timestamp,format){try{timestamp=parseInt(timestamp),String(timestamp).length<13&&(timestamp*=1e3);let[day,month,date,year]=new Date(timestamp).toString().split(" "),minutes=new Date(timestamp).getMinutes(),hours=new Date(timestamp).getHours();(new Date).toString().split(" ");minutes=minutes<10?`0${minutes}`:minutes;let finalHours="";switch(finalHours=hours>12?`${hours-12}:${minutes}`:0===hours?`12:${minutes}`:`${hours}:${minutes}`,finalHours=hours>=12?`${finalHours} PM`:`${finalHours} AM`,format){case"date-only":return`${month} ${date}, ${year}`;case"time-only":return finalHours;case"relative":return relativeTime.from(timestamp);default:return`${month} ${date}, ${year} at ${finalHours}`}}catch(e){return console.error(e),timestamp}}function createRipple(event,target){const circle=document.createElement("span"),diameter=Math.max(target.clientWidth,target.clientHeight),radius=diameter/2,targetDimensions=target.getBoundingClientRect();circle.style.width=circle.style.height=`${diameter}px`,circle.style.left=event.clientX-(targetDimensions.left+radius)+"px",circle.style.top=event.clientY-(targetDimensions.top+radius)+"px",circle.classList.add("ripple");const rippleAnimation=circle.animate([{transform:"scale(3)",opacity:0}],{duration:1e3,fill:"forwards",easing:"ease-out"});target.append(circle),rippleAnimation.onfinish=()=>{circle.remove()}}window.addEventListener("hashchange",(e=>routeTo(window.location.hash))),window.addEventListener("load",(()=>{document.body.classList.remove("hidden"),document.addEventListener("pointerdown",(e=>{e.target.closest("button, .interact")&&createRipple(e,e.target.closest("button, .interact"))})),document.addEventListener("copy",(()=>{notify("copied","success")})),document.addEventListener("keydown",(e=>{"/"===e.key&&(e.preventDefault(),getRef("search_payments").focusIn())})),getRef("search_payments").addEventListener("input",(e=>{const searchQuery=e.target.value.toLowerCase(),filteredInterns=[];floGlobals.internTxs.forEach(((intern,floId)=>{(floId.toLowerCase().includes(searchQuery)||floGlobals.appObjects.RIBC.internList[floId].toLowerCase().includes(searchQuery))&&filteredInterns.push({floId:floId,name:floGlobals.appObjects.RIBC.internList[floId]})})),filteredInterns.sort(((a,b)=>a.name.toLowerCase().includes(searchQuery)&&b.name.toLowerCase().includes(searchQuery)?a.name.toLowerCase().indexOf(searchQuery)-b.name.toLowerCase().indexOf(searchQuery):a.name.toLowerCase().includes(searchQuery)?-1:b.name.toLowerCase().includes(searchQuery)?1:a.floId.toLowerCase().indexOf(searchQuery)-b.floId.toLowerCase().indexOf(searchQuery))),renderElem(getRef("intern_payment_list"),html`${filteredInterns.map((intern=>render.internCard(intern.floId)))}`)}))}));const appState={params:{}};function routeTo(targetPage){const routingAnimation={in:slideInUp,out:slideOutUp};let pageId,subPageId1,searchParams,params;if(""===targetPage)pageId="home",history.replaceState(null,null,"#/home");else if(targetPage.includes("/"))if(targetPage.includes("?")){const splitAddress=targetPage.split("?");searchParams=splitAddress.pop(),[,pageId,subPageId1]=splitAddress.pop().split("/")}else[,pageId,subPageId1]=targetPage.split("/");else pageId=targetPage;if(getRef(pageId)?.classList.contains("page")){if(appState.currentPage=pageId,searchParams){const urlSearchParams=new URLSearchParams("?"+searchParams);params=Object.fromEntries(urlSearchParams.entries())}if(params&&(appState.params=params),"intern"===pageId)params&¶ms.id&&render.intern(params.id);if("intern"===appState.lastPage)routingAnimation.in=slideInRight,routingAnimation.out=slideOutRight;if("intern"===pageId)routingAnimation.in=slideInLeft,routingAnimation.out=slideOutLeft;appState.lastPage!==pageId&&(document.querySelectorAll(".page").forEach((page=>page.classList.add("hidden"))),getRef(pageId).closest(".page").classList.remove("hidden"),appState.lastPage&&(getRef(appState.lastPage).animate(routingAnimation.out,{duration:floGlobals.prefersReducedMotion?0:150,fill:"forwards",easing:"ease"}).onfinish=e=>{e.target.effect.target.classList.add("hidden")}),getRef(pageId).classList.remove("hidden"),getRef(pageId).animate(routingAnimation.in,{duration:floGlobals.prefersReducedMotion?0:150,fill:"forwards",easing:"ease"}).onfinish=e=>{appState.lastPage=pageId})}}const slideInLeft=[{opacity:0,transform:"translateX(1rem)"},{opacity:1,transform:"translateX(0)"}],slideOutLeft=[{opacity:1,transform:"translateX(0)"},{opacity:0,transform:"translateX(-1rem)"}],slideInRight=[{opacity:0,transform:"translateX(-1rem)"},{opacity:1,transform:"translateX(0)"}],slideOutRight=[{opacity:1,transform:"translateX(0)"},{opacity:0,transform:"translateX(1rem)"}],slideInDown=[{opacity:0,transform:"translateY(-1rem)"},{opacity:1,transform:"translateY(0)"}],slideOutDown=[{opacity:1,transform:"translateY(0)"},{opacity:0,transform:"translateY(1rem)"}],slideInUp=[{opacity:0,transform:"translateY(1rem)"},{opacity:1,transform:"translateY(0)"}],slideOutUp=[{opacity:1,transform:"translateY(0)"},{opacity:0,transform:"translateY(-1rem)"}];function formatAmount(amount=0){return amount?amount.toLocaleString("en-IN",{style:"currency",currency:"inr"}):"₹0"}function fetchRibcData(){return floCloudAPI.requestObjectData("RIBC",{application:"InternManage",receiverID:"FMyRTrz9CG4TFNM6rCQgy3VQ5NF23bY2xD",senderID:["FCja6sLv58e3RMy41T5AmWyvXEWesqBCkX","FFS5hFXG7DBtdgzrLwixZLpenAmsCKRddm","FS4jMAcSimRMrhoRhk5cjuJERS2otiwq4A"]})}function fetchTransactions(){return floBlockchainAPI.readAllTxs("FThgnJLcuStugLc24FJQggmp2WgaZjrBSn").then((({items:items})=>items))}floGlobals.payer="FThgnJLcuStugLc24FJQggmp2WgaZjrBSn",floGlobals.internTxs=new Map;const render={internCard(floId){const{total:total,txs:txs}=floGlobals.internTxs.get(floId);return html` +
  • +
    +

    ${floGlobals.appObjects.RIBC.internList[floId]}

    + +
    +
    +

    Last payment: ${formatAmount(txs[0].amount)} on ${getFormattedTime(txs[0].time,"date-only")}

    +

    Total paid: ${formatAmount(total)}

    +
    + + View details + + +
  • + `},internPaymentList(){const renderedList=[];floGlobals.internTxs.forEach(((data,internId)=>{renderedList.push(render.internCard(internId))})),renderElem(getRef("intern_payment_list"),html`${renderedList}`)},paymentCard(tx){const{txid:txid,amount:amount,time:time}=tx;return html` +
  • + +
    +

    ${formatAmount(amount)}

    + + + + + View transaction + +
    +
  • + `},intern(floId){renderElem(getRef("intern"),html` + + + Back + +
    +

    ${floGlobals.appObjects.RIBC.internList[floId]}

    +
    +

    FLO Address

    + +
    +

    Total paid: ${formatAmount(floGlobals.internTxs.get(floId).total)}

    +
    +
    +

    Payment history

    +
      + ${floGlobals.internTxs.get(floId).txs.map((tx=>render.paymentCard(tx)))} +
    +
    + `)}},oldInterns={FEvLovuDjWo4pXX3Y4SKDh8sq1AxJzqz9Z:"Megha Rani",F765ofUHBhfXhvzrSgnPjvCvJXXCpoW6be:"Madhu Verma",FHZtDh1NPepaPbbPwW65GjnDdVV1uo8NSA:"Vridhi Raj",FKa43RxHUAdJbgV6KipQ4PvXi6Kgw4HmFn:"Aakriti Sinha",FFaB6N1ETZsykXVS2PdM5xhj5BBoqsfsXC:"Ritika Agrawal",FSdjJCJdU43a1dyWY6dRES1ekoupEjFPqQ:"Muskan Kumari",FK96PZh4NskoJfWoyqcvLpSo7YnTLWMmdD:"Shambhavi Singh",FJK9EDGhKj4Wr2zeCo3zRPXCNU6CXFFQAN:"Shivam Kumar Pandey",FPtrQK6aSCgFeSNpzC68YTznHPfiz7CCvW:"Shruti Kashyap",FHWXdnjRRJErqazye4Y9MRmE42D4Bp6Bj7:"Rashi Sanghvi",FCTGD4M3DvMKupX3j2y5f3cQNDD9i6LUp7:"Gunjan Kumar Ranjan",F8zYh6rCuorGmnMtqGFpaKGeBqQaj9WVtG:"Kriti Shreya",FFoVnVMJv8BTfbk7ij9T5jPHs7VKSz886A:"Jaidev",F87Ai2ErAMFe3UmAR7S63UYX2jE9ofaXSH:"Keerthana A V",FEzy6pzEkm1TMXf1BGQz8dXvVZM3L1HFu2:"Saloni Jaitley",FB4tu13HCxHAadvUDmgDBhvE9MtCkgRacn:"Divyansh Bhardwaj",FLzcrXhzK1XzLnku5sT6yzURBcqQ5ZDNJy:"Tanishk Goyal",F7HVKrF68Y6YKE9XXpHhAcxt6MwRLcUD67:"Salomi Sarkar",FBYnAqhBt99XbTtCH6LAzjJ5yNZVPkYXhk:"Divyansh Bhardwaj (New FLO ID)",FF7jVqwGS8fGG9fxmbVkEvD1Qo11hDyg8b:"Ahana Chakraborty",FKknmmQd3PVaGbBbPFAJcQsARvw48NfeDF:"Prattay Mazumdar",FSoa46pVWsNuZDp26X9H9Fi6ijMk7cy7mc:"Jayant Kumar",FCqLr9nymnbh7ahta1gGC78z634y4GHJGQ:"Rakhijeet Singh",FEHKFxQxycsxw2qQQSn2Y1BCT6Mfb8EMko:"Abhijeet Anand"};function getReceiverAddress(vout){for(const output of vout)for(const address of output.scriptPubKey.addresses)if(address!==floGlobals.payer)return address}function main(){return Promise.all([fetchTransactions(),fetchRibcData()]).then((([txs])=>{console.log(floGlobals.appObjects.RIBC.internList),floGlobals.appObjects.RIBC.internList={...floGlobals.appObjects.RIBC.internList,...oldInterns},txs.forEach((tx=>{const floId=tx.vout[0].scriptPubKey.addresses[0];if(!floGlobals.appObjects.RIBC.internList[floId])return;const{txid:txid,floData:floData,time:time}=tx;floGlobals.internTxs.has(floId)||floGlobals.internTxs.set(floId,{total:0,txs:[]});const amount=parseFloat(floData.match(/([0-9]+)/)[1])||0;floGlobals.internTxs.get(floId).total+=amount,floGlobals.internTxs.get(floId).txs.push({txid:txid,amount:amount,time:time})})),floGlobals.internTxs.forEach((intern=>{intern.txs.sort(((a,b)=>b.time-a.time))})),floGlobals.internTxs=new Map([...floGlobals.internTxs.entries()].sort(((a,b)=>b[1].txs[0].time-a[1].txs[0].time))),render.internPaymentList(),routeTo(window.location.hash)})).catch((err=>{notify(`Error fetching data: ${err}`,"error")}))} \ No newline at end of file